Java 背景图像每次都在不同的地方
我有一个很大的程序,我会发布一些课程,希望你们能找到问题所在。基本上,有时当我启动它时,它会创建一个很好的游戏,而另一些时候,背景在北面和西面的方向上增加了几个像素,留下了非常难看的空白。我似乎找不到决定它是否这样做的缺失代码。老实说,我觉得我的机器出现了某种渲染故障。无论如何,我已经在调试中加入了一个backgroundJava 背景图像每次都在不同的地方,java,Java,我有一个很大的程序,我会发布一些课程,希望你们能找到问题所在。基本上,有时当我启动它时,它会创建一个很好的游戏,而另一些时候,背景在北面和西面的方向上增加了几个像素,留下了非常难看的空白。我似乎找不到决定它是否这样做的缺失代码。老实说,我觉得我的机器出现了某种渲染故障。无论如何,我已经在调试中加入了一个backgroundgetX和getY方法,并注意到无论背景是否完全拉伸到屏幕上(这是一个自定义背景,因此像素高度和宽度完全匹配),还是向上和向左,背景仍然显示为(0,0)。我将发布从主线程到菜单
getX
和getY
方法,并注意到无论背景是否完全拉伸到屏幕上(这是一个自定义背景,因此像素高度和宽度完全匹配),还是向上和向左,背景仍然显示为(0,0)。我将发布从主线程到菜单中创建背景的所有方法。我将留下笔记,指出它通过这段代码到达创建背景的路径。谢谢你的帮助,我会定期查看编辑和更多信息
编辑:添加了background.java
编辑2:添加了解释问题的图片
Menu.java*忽略文件IO
代码,主要是创建一个新的GamePanel()
接下来是GamePanel.java
public class GamePanel extends JPanel implements Runnable, KeyListener {
// ID
private static final long serialVersionUID = 1L;
// Dimensions
public static final int WIDTH = 320;
public static final int HEIGHT = 240;
public static final int SCALE = 2;
// Thread
private Thread thread;
private boolean running;
private int FPS = 30;
private long targetTime = 1000 / FPS;
// Image
private BufferedImage image;
private Graphics2D g;
// Game State Manager
private GameStateManager gsm;
public GamePanel() {
super();
setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
addKeyListener(this);
thread.start();
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
}
private void init() {
image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
running = true;
gsm = new GameStateManager();
}
@Override
public void run() {
init();
long start;
long elapsed;
long wait;
// Game Loop
while (running) {
start = System.nanoTime();
update();
draw();
drawToScreen();
elapsed = System.nanoTime() - start;
wait = targetTime - (elapsed / 1000000);
if (wait < 0) {
wait = 5;
}
try {
Thread.sleep(wait);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void update() {
gsm.update();
}
private void draw() {
gsm.draw(g);
}
private void drawToScreen() {
Graphics g2 = getGraphics();
g2.drawImage(image, 0, 0, WIDTH * SCALE, HEIGHT * SCALE, null);
g2.dispose();
}
@Override
public void keyPressed(KeyEvent k) {
gsm.keyPressed(k.getKeyCode());
}
@Override
public void keyReleased(KeyEvent k) {
}
@Override
public void keyTyped(KeyEvent arg0) {
}
}
GameState
是我拥有的一个抽象类,因此它不值得发布,它只包含init()
,draw()
等。下一个类是最后一个类,之所以调用它是因为GameStateMananger
从MENUSTATE
或0开始,当GSM初始化时,它会初始化它的当前状态,这样我们就可以去上课了MenuState
MenuState.java
public class MenuState extends GameState {
private Background bg;
public FontMetrics fontMetrics;
private int choice = 0;
private String[] options = { "Slot Machine", "Dice Toss", "Roulette Wheel", "Leaderboards", "Settings", "Help",
"Quit" };
private Color titleColor;
private Font titleFont;
private Font font;
public MenuState(GameStateManager gsm) {
this.gsm = gsm;
try {
bg = new Background("/Backgrounds/happybg.png");
titleColor = Color.WHITE;
titleFont = new Font("Georgia", Font.PLAIN, 28);
} catch (Exception e) {
e.printStackTrace();
}
font = new Font("Arial", Font.PLAIN, 12);
}
@Override
public void init() {
}
@Override
public void update() {
}
@Override
public void draw(Graphics2D g) {
Canvas c = new Canvas();
fontMetrics = c.getFontMetrics(font);
// Draw BG
bg.draw(g);
// Draw title
g.setColor(titleColor);
g.setFont(titleFont);
String title = "Jolly Jackpot Land!";
g.drawString(title, 36, 60);
g.setFont(font);
for (int i = 0; i < options.length; i++) {
if (i == choice)
g.setColor(Color.RED);
else
g.setColor(Color.WHITE);
g.drawString(options[i], 30, 120 + i * 15);
}
g.setColor(Color.WHITE);
g.setFont(new Font("Arial", Font.PLAIN, 10));
g.drawString("v1.1", 165, 235);
Object[] a = { ("Name: " + Player.getName()), ("Gil: " + Player.getGil()),
("Personal Best: " + Player.getPersonalBest()), ("Winnings: " + Player.getWinnings()),
("Wins: " + Player.getWins()), ("Losses: " + Player.getLosses()),
("Win/Loss Ratio: " + String.format("%.2f", Player.getRatio()) + "%") };
g.setFont(font);
if (Player.getName() != null) {
for (int x = 0; x < a.length; x++) {
g.drawString(a[x].toString(), GamePanel.WIDTH - fontMetrics.stringWidth(a[x].toString()) - 30,
120 + x * 15);
}
}
}
private void select() {
if (choice == 0) {
// Slots
gsm.setState(GameStateManager.SLOTGAMESTATE);
}
if (choice == 1) {
// Dice
gsm.setState(GameStateManager.DICEGAMESTATE);
}
if (choice == 2) {
// Roulette
gsm.setState(GameStateManager.ROULETTEGAMESTATE);
}
if (choice == 3) {
// Leaderboards
gsm.setState(GameStateManager.LEADERBOARDSTATE);
}
if (choice == 4) {
// Settings
gsm.setState(GameStateManager.SETTINGSSTATE);
}
if (choice == 5) {
// Help
gsm.setState(GameStateManager.HELPSTATE);
}
if (choice == 6) {
// Quit
System.exit(0);
}
}
@Override
public void keyPressed(int k) {
if (k == KeyEvent.VK_ENTER) {
select();
}
if (k == KeyEvent.VK_UP) {
choice--;
if (choice == -1) {
choice = options.length - 1;
}
}
if (k == KeyEvent.VK_DOWN) {
choice++;
if (choice == options.length) {
choice = 0;
}
}
}
@Override
public void keyReleased(int k) {
}
}
这就是它在游戏循环中等待输入的地方。我知道这是很多代码,但很多代码都是略读的,直到一个方法调用将您带到下一个类。我只是不明白为什么它只是偶尔发生,如果它是一致的,我可以调试它。任何帮助都将不胜感激
这些都是通过点击上面程序的.jar得到的,完全相同的.jar,完全相同的源代码,不同的结果。我很困惑。我们应该从如何
getGraphics
开始,而不是如何在Swing中进行自定义绘制,您基本上正在冒着一种风险,即您将代码绘制到Graphics
上下文和Swing执行相同的操作之间存在竞争条件,这将导致闪烁发生。如果您需要对绘制过程进行主动控制,则应使用,另请参阅以了解更多详细信息。因此,不要处理非您自己创建的图形上下文,这可能会导致某些系统停止绘制无需在您的draw
方法中创建Canvas
Graphics2D
有自己的getFontMetrics
方法。Background
类是如何自己绘制的?看看这个,看看一个带有图形的简单Swing应用程序应该如何编码。
public class GameStateManager {
private ArrayList<GameState> gameStates;
private int currentState;
public static final int MENUSTATE = 0;
public static final int SLOTGAMESTATE = 1;
public static final int DICEGAMESTATE = 2;
public static final int ROULETTEGAMESTATE = 3;
public static final int LEADERBOARDSTATE = 4;
public static final int SETTINGSSTATE = 5;
public static final int HELPSTATE = 6;
public GameStateManager() {
gameStates = new ArrayList<GameState>();
currentState = 0;
gameStates.add(new MenuState(this));
gameStates.add(new SlotGameState(this));
gameStates.add(new DiceGameState(this));
gameStates.add(new RouletteGameState(this));
gameStates.add(new LeaderboardState(this));
gameStates.add(new SettingsState(this));
gameStates.add(new HelpState(this));
}
public void setState(int state){
currentState = state;
gameStates.get(currentState).init();
currentState = 0;
}
public int getState() {
return currentState;
}
public void update() {
gameStates.get(currentState).init();
}
public void draw(java.awt.Graphics2D g){
gameStates.get(currentState).draw(g);
}
public void keyPressed(int k){
gameStates.get(currentState).keyPressed(k);
}
public void keyReleased(int k) {
gameStates.get(currentState).keyReleased(k);
}
}
public class MenuState extends GameState {
private Background bg;
public FontMetrics fontMetrics;
private int choice = 0;
private String[] options = { "Slot Machine", "Dice Toss", "Roulette Wheel", "Leaderboards", "Settings", "Help",
"Quit" };
private Color titleColor;
private Font titleFont;
private Font font;
public MenuState(GameStateManager gsm) {
this.gsm = gsm;
try {
bg = new Background("/Backgrounds/happybg.png");
titleColor = Color.WHITE;
titleFont = new Font("Georgia", Font.PLAIN, 28);
} catch (Exception e) {
e.printStackTrace();
}
font = new Font("Arial", Font.PLAIN, 12);
}
@Override
public void init() {
}
@Override
public void update() {
}
@Override
public void draw(Graphics2D g) {
Canvas c = new Canvas();
fontMetrics = c.getFontMetrics(font);
// Draw BG
bg.draw(g);
// Draw title
g.setColor(titleColor);
g.setFont(titleFont);
String title = "Jolly Jackpot Land!";
g.drawString(title, 36, 60);
g.setFont(font);
for (int i = 0; i < options.length; i++) {
if (i == choice)
g.setColor(Color.RED);
else
g.setColor(Color.WHITE);
g.drawString(options[i], 30, 120 + i * 15);
}
g.setColor(Color.WHITE);
g.setFont(new Font("Arial", Font.PLAIN, 10));
g.drawString("v1.1", 165, 235);
Object[] a = { ("Name: " + Player.getName()), ("Gil: " + Player.getGil()),
("Personal Best: " + Player.getPersonalBest()), ("Winnings: " + Player.getWinnings()),
("Wins: " + Player.getWins()), ("Losses: " + Player.getLosses()),
("Win/Loss Ratio: " + String.format("%.2f", Player.getRatio()) + "%") };
g.setFont(font);
if (Player.getName() != null) {
for (int x = 0; x < a.length; x++) {
g.drawString(a[x].toString(), GamePanel.WIDTH - fontMetrics.stringWidth(a[x].toString()) - 30,
120 + x * 15);
}
}
}
private void select() {
if (choice == 0) {
// Slots
gsm.setState(GameStateManager.SLOTGAMESTATE);
}
if (choice == 1) {
// Dice
gsm.setState(GameStateManager.DICEGAMESTATE);
}
if (choice == 2) {
// Roulette
gsm.setState(GameStateManager.ROULETTEGAMESTATE);
}
if (choice == 3) {
// Leaderboards
gsm.setState(GameStateManager.LEADERBOARDSTATE);
}
if (choice == 4) {
// Settings
gsm.setState(GameStateManager.SETTINGSSTATE);
}
if (choice == 5) {
// Help
gsm.setState(GameStateManager.HELPSTATE);
}
if (choice == 6) {
// Quit
System.exit(0);
}
}
@Override
public void keyPressed(int k) {
if (k == KeyEvent.VK_ENTER) {
select();
}
if (k == KeyEvent.VK_UP) {
choice--;
if (choice == -1) {
choice = options.length - 1;
}
}
if (k == KeyEvent.VK_DOWN) {
choice++;
if (choice == options.length) {
choice = 0;
}
}
}
@Override
public void keyReleased(int k) {
}
}
public class Background {
private BufferedImage image;
private double x;
private double y;
public Background(String s) {
try {
image = ImageIO.read(getClass().getResourceAsStream(s));
} catch (Exception e) {
e.printStackTrace();
}
}
public void setPosition(double x, double y) {
this.setX(x);
this.setY(y);
}
public void draw(Graphics2D g) {
g.drawImage(image, 0, 0, null);
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
}