java - Snake Game -- Can't steer snake
问题描述
Actual question on the bottom of the post!
At first, I want to explain my problem.
I'm writing a basic Snake game and I got the snake to move automatically. It moves automatically to the right of the window when you execute the code, just like intended. However, I can't steer my snake the way I want, it doesn't change its direction at all.
To avoid confusion, player
is an instance of the class Snake
.
To explain the movement of the snake:
The Snake
object has a coordinates
property which is an ArrayList holding SnakePart
objects. Each SnakePart
object has the property x
and y
. Using this ArrayList, the snake is moving by drawing little rectangles on a canvas by using the x
and y
properties on the y- and x-axis of the canvas.
The Snake
object also has a dx
and a dy
property that gets added (or subtracted -- depending on the direction of the snake) to the x
and y
property of the SnakePart
object to move the snake in a direction.
To update the ArrayList in Snake.java
:
public void move() {
SnakePart head = new SnakePart(this.coordinates.get(0).x + this.dx, this.coordinates.get(0).y + this.dy);
this.coordinates.add(0, head);
this.coordinates.remove(this.coordinates.size() - 1);
}
To draw the snake on the canvas in Board.java
(partly, rest of the method is not necessary for now):
@Override
public void paintComponent(Graphics g) {
this.player.coordinates.forEach(snakePart -> {
g.setColor(Color.BLUE);
g.fillRect(snakePart.x, snakePart.y, 10, 10);
});
}
To steer the snake, I want to use the arrow keys. Depending on which arrow key is pressed, the snake's x
and y
coordinates/properties get modified (Board.java
):
@Override
public void keyPressed(KeyEvent event) {
int keyCode = event.getKeyCode();
if (keyCode == 37) {
this.player.dx = -10;
this.player.dy = 0;
} else if (keyCode == 38) {
this.player.dx = 0;
this.player.dy = -10;
} else if (keyCode == 39) {
this.player.dx = 10;
this.player.dy = 0;
} else if (keyCode == 40) {
this.player.dx = 0;
this.player.dy = 10;
}
}
Whole code:
Snake.java
:
package com.codef0x.snake;
import java.util.ArrayList;
public class Snake {
ArrayList < SnakePart > coordinates;
int dx = 10;
int dy = 0;
public Snake(ArrayList < SnakePart > coords) {
this.coordinates = coords;
}
public void move() {
SnakePart head = new SnakePart(this.coordinates.get(0).x + this.dx, this.coordinates.get(0).y + this.dy);
this.coordinates.add(0, head);
this.coordinates.remove(this.coordinates.size() - 1);
}
public void grow() {
SnakePart newPart = new SnakePart(0, 0);
newPart.x = this.coordinates.get(this.coordinates.size() - 1).x - 10;
newPart.y = this.coordinates.get(this.coordinates.size() - 1).y;
this.coordinates.add(this.coordinates.size() - 1, newPart);
}
}
Board.java
(showing only relevant parts, otherwise it would be too much code)
package com.codef0x.snake;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
public class Board extends JPanel implements KeyListener {
Snake player;
ArrayList<SnakePart> snakeCoordinates;
public Board() {
this.snakeCoordinates = new ArrayList<>();
snakeCoordinates.add(new SnakePart(150, 150));
snakeCoordinates.add(new SnakePart(140, 150));
snakeCoordinates.add(new SnakePart(130, 150));
snakeCoordinates.add(new SnakePart(120, 150));
this.player = new Snake(snakeCoordinates);
this.food = new Food();
}
@Override
public void paintComponent(Graphics g) {
clear(g);
this.player.coordinates.forEach(snakePart - > {
g.setColor(Color.BLUE);
g.fillRect(snakePart.x, snakePart.y, 10, 10);
});
}
public void clear(Graphics g) {
g.clearRect(0, 0, getHeight(), getWidth());
}
@Override
public void update(Graphics g) {
paintComponent(g);
}
@Override
public void keyPressed(KeyEvent event) {
int keyCode = event.getKeyCode();
if (keyCode == 37) {
this.player.dx = -10;
this.player.dy = 0;
} else if (keyCode == 38) {
this.player.dx = 0;
this.player.dy = -10;
} else if (keyCode == 39) {
this.player.dx = 10;
this.player.dy = 0;
} else if (keyCode == 40) {
this.player.dx = 0;
this.player.dy = 10;
}
}
@Override
public void keyTyped(KeyEvent event) {
return;
}
@Override
public void keyReleased(KeyEvent event) {
return;
}
public void run(Board board) {
Timer game = new Timer();
game.schedule(new TimerTask() {
boolean initiallySpawned = false;
@Override
public void run() {
Graphics g = board.getGraphics();
if (hitSomething()) { // removed method hitSomething, not relevant
game.cancel();
return;
}
player.move();
update(g);
}
}, 0, 500);
}
}
SnakePart.java
:
package com.codef0x.snake;
public class SnakePart {
int x;
int y;
public SnakePart(int x, int y) {
this.x = x;
this.y = y;
}
}
What am I doing wrong and what do I need to change to steer the snake properly?
In case you still want / need to see all files as a whole, you can have a look at them here:
Snake.java
Board.java
SnakePart.java
Food.java <- Not related, but may prevent confusion about the Food
object
解决方案
问题是主要的。您创建一个board
来托管您的游戏状态,并创建不同的一个来听键盘。
public static void main(String[] args) {
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(3);
Board board = new Board();
frame.add(board);
frame.setSize(500, 500);
frame.addKeyListener(new Board());
frame.setVisible(true);
board.run(board);
}
它应该是:
public static void main(String[] args) {
JFrame frame = new JFrame("Snake");
frame.setDefaultCloseOperation(3);
Board board = new Board();
frame.add(board);
frame.setSize(500, 500);
frame.addKeyListener(board);
frame.setVisible(true);
board.run(board);
}
也board.run(board)
没什么意义,在run
方法的范围内,板子可以换成this
(所以省略)...
推荐阅读
- c# - Windows 10 USB 摄像头无法通过代码工作,但可以通过其他程序工作
- django - Django 在同一模型中只有一个用户/一个日期
- java - 捕捉视频(Camera API)和MediaCodec的简单使用
- git - 如何在网络驱动器上的共享子文件夹中 git init
- c# - 如何在 VSCode 中通过调试/发布移动引用的 DLL?
- scala - 使用结构化 Spark 流在 HBase 中批量插入数据
- javascript - 使用 Mapbox GL JS 为地理编码器补充本地数据
- flutter - 无法在运行发布颤动时发布 https 请求
- javascript - 使用 CodePen 并不能在本地工作?
- python - 从两边都有 Y 的方程生成数据和曲线拟合