我正在尝试制作一款游戏,在这个阶段它所做的只是创建一个你可以移除或放置的贴图板。然而,当我将网格扩展到任何高于128的值时,它就崩溃了。然而,只有当宽度较大时才会发生这种情况。如果高度更大,那么它会在第一个网格下面形成第二个网格,这就有点奇怪了。下面是我的代码和我得到的错误的堆栈跟踪。
你可以通过改变Game.java
下的世界设置中的值来看到它应该如何工作。(同样,如果width是更大的数字,并且它乘以超过128,这就是导致错误的原因。)
Game.java
package engine;
import java.awt.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class Game extends JPanel{
private Thread thread;
//world settings
static int worldWidth = 11;
static int worldHeight = 12;
public int w = worldWidth;
public int h = worldHeight;
//window settings
private static int windowWidth = 800;
private static int windowHeight = 600;
private static String windowTitle = "Game";
//tile settings
public static int tileSize = 50;
public static int tilex;
public static int tiley;
private static byte[] tiles;
public void paint(Graphics g) {
super.paintComponent(g);
//set background color
setBackground(new Color(0,128,255));
//set color and area of shape
g.setColor(new Color(0,255,0));
//checks array every repaint for modified tiles
for(int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int i = y + (x * w);
if (tiles[i] == 1) {
tilex = x * tileSize;
tiley = y * tileSize;
g.fillRect(tilex, tiley, tileSize, tileSize);
}
}
}
//Pointer/selector
}
public static void main(String[] args) throws InterruptedException {
new Game();
}
public void init() {
new Window(windowWidth, windowHeight, windowTitle, this);
Window.running = true;
thread = new Thread();
thread.start();
generate();
}
public void terminate() {
System.exit(0);
}
public Game() throws InterruptedException {
try {
init();
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e.toString(), "Failed to start " + windowTitle, JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
while(Window.running) {
Thread.sleep(1);
//closes game if escape is pressed or if window is closed (handled in window class)
if (!Window.running) {
System.out.println("Closing " + windowTitle);
terminate();
}
//render
repaint();
}
}
public void generate() {
tiles = new byte[w * h];
for(int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
int i = y + (x * w);
//1 = tile present, 0 = not present
tiles[i] = (byte) 1;
}
}
}
public static void changeSquare() {
if (GameListener.mouseButton == 3 && GameListener.modifyBlock) {
tiles[GameListener.byteToModify] = 1;
} else if (GameListener.mouseButton == 1 && GameListener.modifyBlock){
tiles[GameListener.byteToModify] = 0;
}
}
}
Window.java
package engine;
import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
public class Window {
public static boolean running = false;
public Window(int width, int height, String title, Game game) {
//creates and displays window
JFrame frame = new JFrame(title);
KeyListener keylistener = new KeyListener() {
@Override
public void keyPressed(KeyEvent keyEvent) {
GameListener.keyListener(keyEvent);
}
@Override
public void keyReleased(KeyEvent keyEvent) {
}
@Override
public void keyTyped(KeyEvent keyEvent) {
}
};
MouseListener mouselistener = new MouseListener() {
@Override
public void mouseClicked(MouseEvent mouseEvent) {
}
@Override
public void mouseEntered(MouseEvent mouseEvent) {
}
@Override
public void mouseExited(MouseEvent mouseEvent) {
}
@Override
public void mousePressed(MouseEvent mouseEvent) {
GameListener.mouseListener(mouseEvent);
Game.changeSquare();
}
@Override
public void mouseReleased(MouseEvent mouseEvent) {
}
};
MouseMotionListener mousemotionlistener = new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent mouseMotionEvent) {
GameListener.mouseMotionListener(mouseMotionEvent);
}
@Override
public void mouseMoved(MouseEvent arg0) {
}
};
//listens for window close and sends back to game loop to terminate
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
running = false;
}
});
frame.getContentPane().addKeyListener(keylistener);
frame.getContentPane().addMouseListener(mouselistener);
frame.getContentPane().addMouseMotionListener(mousemotionlistener);
frame.setPreferredSize(new Dimension(width, height));
frame.add(game);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
}
最后是GameListener.java
package engine;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
public class GameListener {
private static int tileX;
private static int tileY;
private static int xTries;
private static int yTries;
private static int tileXM;
private static int tileYM;
private static int xTriesM;
private static int yTriesM;
public static int byteToModify;
public static int mouseButton;
public static boolean modifyBlock;
public static boolean drawSelector;
public static int byteToDrawSelector;
public static void keyListener(KeyEvent e) {
int code = e.getKeyCode();
//put key if statements here (for example escape to close
//use for testing key name when adding a new if statement
//String character = KeyEvent.getKeyText(code);
//System.out.println("Character: " + KeyEvent.getKeyText(code));
//System.out.println("Code: " + code);
//get key codes at keycode.info
//closes game on escape
if (code == 27) {
//escape
Window.running = false;
}
//movement
// if (code == 87) {
//W
// Game.y = Game.y - 100;
// }
// if (code == 65) {
//A
// Game.x = Game.x - 100;
// }
// if (code == 83) {
//S
// Game.y = Game.y + 100;
// }
// if (code == 68) {
//D
//Game.x = Game.x + 100;
// }
}
public static void mouseListener(MouseEvent e) {
//System.out.println(e.getX());
//System.out.println(e.getY());
//System.out.println(e.getButton());
xTries = 0;
tileX = 0;
yTries = 0;
tileY = 0;
modifyBlock = true;
if (e.getX() < Game.tileSize) {
} else if (e.getX() > Game.tileSize && e.getX() < (Game.tileSize * Game.worldWidth)) {
for (int i = Game.tileSize; i<e.getX(); i = i + Game.tileSize) {
xTries++;
}
//System.out.println(xTries);
tileX = xTries;
} else {
System.err.println("User clicked outside of world");
modifyBlock = false;
}
if (e.getY() < Game.tileSize) {
} else if (e.getY() > Game.tileSize && e.getY() < (Game.tileSize * Game.worldHeight)) {
for (int i = Game.tileSize; i<e.getY(); i = i + Game.tileSize) {
yTries++;
}
//System.out.println(yTries);
tileY = yTries;
} else {
System.err.println("User clicked outside of world");
modifyBlock = false;
}
if (e.getButton() == MouseEvent.BUTTON1) {
mouseButton = 1;
} else if (e.getButton() == MouseEvent.BUTTON3) {
mouseButton = 3;
}
byteToModify = tileY+(tileX * Game.worldWidth);
//System.out.println(tileX);
//System.out.println(tileY);
//System.out.println(byteToModify);
}
public static void mouseMotionListener(MouseEvent e) {
//System.out.println(e.getX());
//System.out.println(e.getY());
xTriesM = 0;
tileXM = 0;
yTriesM = 0;
tileYM = 0;
drawSelector = true;
if (e.getX() < Game.tileSize) {
} else if (e.getX() > Game.tileSize && e.getX() < (Game.tileSize * Game.worldWidth)) {
for (int i = Game.tileSize; i<e.getX(); i = i + Game.tileSize) {
xTriesM++;
}
//System.out.println(xTries);
tileXM = xTriesM;
} else {
drawSelector = false;
}
if (e.getY() < Game.tileSize) {
} else if (e.getY() > Game.tileSize && e.getY() < (Game.tileSize * Game.worldHeight)) {
for (int i = Game.tileSize; i<e.getY(); i = i + Game.tileSize) {
yTriesM++;
}
//System.out.println(yTries);
tileYM = yTriesM;
} else {
drawSelector = false;
}
byteToDrawSelector = tileYM+(tileXM* Game.worldWidth);
}
}
这是我在加载游戏时得到的错误。
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 132
at engine.Game.paint(Game.java:45)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JLayeredPane.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
at java.awt.Container.paint(Unknown Source)
at java.awt.Window.paint(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$1200(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 132
at engine.Game.paint(Game.java:45)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JLayeredPane.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
at java.awt.Container.paint(Unknown Source)
at java.awt.Window.paint(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at javax.swing.RepaintManager$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$1200(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$500(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
它说问题在Game.java
第45行,但我真的不明白是什么原因导致的。
你在for
循环中的计算是错误的。
首先,w
(类Game
中的成员变量)实际上表示[二维]网格中的列数,h
(类Game
中的另一个成员变量)表示行数。您在嵌套的for
循环中使用了错误的方式。所以不用
for(int x = 0; x < w; x++) {
for (int y = 0; y < h; y++) {
你应该有
for(int x = 0; x < h; x++) {
for (int y = 0; y < w; y++) {
所以我只更改了Game
类的代码。为了完整起见,下面是类的完整代码,并进行了上述更改。
package engine;
import java.awt.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class Game extends JPanel {
private Thread thread;
// world settings
static int worldWidth = 12;
static int worldHeight = 11;
public int w = worldWidth;
public int h = worldHeight;
// window settings
private static int windowWidth = 800;
private static int windowHeight = 600;
private static String windowTitle = "Game";
// tile settings
public static int tileSize = 50;
public static int tilex;
public static int tiley;
private static byte[] tiles;
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// set background color
setBackground(new Color(0, 128, 255));
// set color and area of shape
g.setColor(new Color(0, 255, 0));
// checks array every repaint for modified tiles
for (int x = 0; x < h; x++) {
for (int y = 0; y < w; y++) {
int i = y + (x * w);
if (tiles[i] == 1) {
tilex = x * tileSize;
tiley = y * tileSize;
g.fillRect(tilex, tiley, tileSize, tileSize);
}
}
}
}
public static void main(String[] args) throws InterruptedException {
new Game();
}
public void init() {
new Window(windowWidth, windowHeight, windowTitle, this);
Window.running = true;
thread = new Thread();
thread.start();
generate();
}
public void terminate() {
System.exit(0);
}
public Game() throws InterruptedException {
try {
init();
}
catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, e.toString(), "Failed to start " + windowTitle,
JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
while (Window.running) {
Thread.sleep(1);
// closes game if escape is pressed or if window is closed (handled in window
// class)
if (!Window.running) {
System.out.println("Closing " + windowTitle);
terminate();
}
// render
repaint();
}
}
public void generate() {
tiles = new byte[w * h];
for (int x = 0; x < h; x++) {
for (int y = 0; y < w; y++) {
int i = y + (x * w);
// 1 = tile present, 0 = not present
tiles[i] = (byte) 1;
}
}
}
public static void changeSquare() {
if (GameListener.mouseButton == 3 && GameListener.modifyBlock) {
tiles[GameListener.byteToModify] = 1;
}
else if (GameListener.mouseButton == 1 && GameListener.modifyBlock) {
tiles[GameListener.byteToModify] = 0;
}
}
}
您还应该注意到您的设计包含循环依赖关系,因为三个类Game
,GameListener
和Window
中的每一个都引用了其他两个类。这通常是个糟糕的设计。
这个显示中没有行号,也不会计算行数。检查第45行中的代码。我猜是
if (tiles[i] == 1) {
当应用程序崩溃时,你知道它正在尝试访问索引132。检查数组的大小。我猜是11x12=132项,从0到131编号。
有没有可能你对i的计算是错误的?