创建一个蛇游戏,当你按两个方向时,蛇会很快地吃掉自己[Java]
我希望这是有意义的,但我正在尝试用Java制作一个蛇型游戏,如果你同时按两个方向/太快,蛇就会爬到自己的上面,让你输。 举个例子,如果你向下,然后很快地向上打,你会让蛇在同一根柱子上直线上升,然后自杀,但它应该先向右转一圈,然后再向上一圈。如果有人能帮我,那太好了,谢谢创建一个蛇游戏,当你按两个方向时,蛇会很快地吃掉自己[Java],java,user-interface,Java,User Interface,我希望这是有意义的,但我正在尝试用Java制作一个蛇型游戏,如果你同时按两个方向/太快,蛇就会爬到自己的上面,让你输。 举个例子,如果你向下,然后很快地向上打,你会让蛇在同一根柱子上直线上升,然后自杀,但它应该先向右转一圈,然后再向上一圈。如果有人能帮我,那太好了,谢谢 package tk.sketchistgames.Snake; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import
package tk.sketchistgames.Snake;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Board extends JPanel implements ActionListener{
/**
* Main graphical area for Snake
*/
private static final long serialVersionUID = 4085437479211945011L;
private final int WIDTH = 600;
private final int HEIGHT = 600;
private final int DOT_SIZE = 10;
private final int ALL_DOTS = 1200;
private final int RAND_POS = 59;
public static int DELAY = 90;
private int x[] = new int[ALL_DOTS];
private int y[] = new int[ALL_DOTS];
private int dots, food_x, food_y, pdown_x, pdown_y, rdouble_x, rdouble_y, powerUp_x, powerUp_y, half_x, half_y;
private boolean left = false;
private boolean right = true;
private boolean up = false;
private boolean down = false;
private boolean inGame = true;
private int score = 0;
private int fruitEaten = 0;
private boolean Bonus = false;
private boolean RDouble = false;
private boolean bpower = false;
private boolean halfpower = false;
private Timer timer;
private Image food;
private Image head;
private Image body;
private Image pdown;
private Image rdouble;
private Image powerUp;
private Image half;
public Board() {
addKeyListener(new TAdapter());
setBackground(Color.decode("0x3F919E"));
ImageIcon iid = new ImageIcon(this.getClass().getResource("/images/body.png"));
body = iid.getImage();
ImageIcon iia = new ImageIcon(this.getClass().getResource("/images/food.png"));
food = iia.getImage();
ImageIcon iih = new ImageIcon(this.getClass().getResource("/images/head.png"));
head = iih.getImage();
ImageIcon iipd = new ImageIcon(this.getClass().getResource("/images/pdown.png"));
pdown = iipd.getImage();
ImageIcon iird = new ImageIcon(this.getClass().getResource("/images/pup2.png"));
rdouble = iird.getImage();
ImageIcon iipu1 = new ImageIcon(this.getClass().getResource("/images/pup1.png"));
powerUp = iipu1.getImage();
ImageIcon iihd = new ImageIcon(this.getClass().getResource("/images/halfDown.png"));
half = iihd.getImage();
setFocusable(true);
initGame();
}
public void initGame() {
dots = 5;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z*10;
y[z] = 50;
}
locateFood();
timer = new Timer(DELAY, this);
timer.start();
}
public void checkApple() throws UnsupportedAudioFileException, IOException, LineUnavailableException {
if ((x[0] == pdown_x) && (y[0] == pdown_y)){
dots -= 1;
score -= 50;
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/powerdown.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
bpower = false;
}
if ((x[0] == half_x) && (y[0] == half_y)){
dots = dots /2;
score = score /2;
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/powerdown.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
clip.start();
halfpower = false;
}
if ((x[0] == powerUp_x) && (y[0] == powerUp_y)){
dots += 4;
score += 100;
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/powerup1.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
Bonus = false;
}
if ((x[0] == rdouble_x) && (y[0] == rdouble_y)){
dots = dots * 2;
score += 1000;
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/powerup2.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
RDouble = false;
}
if ((x[0] == food_x) && (y[0] == food_y)) {
dots++;
long r = Math.round(Math.random() * 10);
if(r == 4){
locatePowerUp();
Bonus = true;
}
long half = Math.round(Math.random() * 175);
System.out.println(half);
if(half == 89){
locateHalfDown();
halfpower = true;
}
long rdouble = Math.round(Math.random() * 100);
if(rdouble == 50){
locateDoubleUp();
RDouble = true;
}
long badpower = Math.round(Math.random() * 25);
if(badpower == 25 || badpower == 20 || badpower == 15|| badpower == 10 || badpower == 5|| badpower == 0){
locatePowerDown();
bpower = true;
}
score += (50 + fruitEaten);
AudioInputStream audioIn = AudioSystem.getAudioInputStream(Board.class.getResource("/sounds/eat.wav"));
Clip clip = AudioSystem.getClip();
clip.open(audioIn);
clip.start();
fruitEaten++;
locateFood();
}
}
public void paint(Graphics g) {
super.paint(g);
if (inGame) {
if(halfpower){
g.drawImage(half, half_x, half_y, this);
}
if(Bonus){
g.drawImage(powerUp, powerUp_x, powerUp_y, this);
}
if(RDouble){
g.drawImage(rdouble, rdouble_x, rdouble_y, this);
}
if(dots <= 0) gameOver(g);
g.setColor(Color.white);
Font small1 = new Font("arcadepix", Font.PLAIN, 20);
g.setFont(small1);
g.drawString("Score: " + score + " Food Eaten: " + fruitEaten + " Length: " + dots, 15, 15);
g.drawImage(food, food_x, food_y, this);
if(bpower){
g.drawImage(pdown, pdown_x, pdown_y, this);
}
for (int z = 0; z < dots; z++) {
if (z == 0)
g.drawImage(head, x[z], y[z], this);
else g.drawImage(body, x[z], y[z], this);
}
if(Menu.pause){
g.drawString("Paused! 'P' To unpause!", 20, 100);
for (int z = 0; z < dots; z++) {
x[z] = 50 - z*10;
y[z] = 50;
}
}
Toolkit.getDefaultToolkit().sync();
g.dispose();
}else{
gameOver(g);
}
}
public void gameOver(Graphics g) {
if(dots >= 300){
String msg = "You won!";
Font small = new Font("arcadepix", Font.PLAIN, 20);
FontMetrics metr = this.getFontMetrics(small);
g.setColor(Color.white);
g.setFont(small);
g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2, HEIGHT / 2);
g.drawString("Total Score: " + score +"!", (WIDTH - metr.stringWidth(msg)) /2 - 12, (HEIGHT / 2) - 18);
g.drawString("Total Food Eaten: " + dots + "!", (WIDTH - metr.stringWidth(msg)) /2 - 72, (HEIGHT / 2) - 38);
g.drawString("Press Space to play again!", (WIDTH - metr.stringWidth(msg)) /2 - 77, (HEIGHT / 2) + 18);
setBackground(Color.red);
}else{
String msg = "Game Over";
Font small = new Font("arcadepix", Font.PLAIN, 20);
FontMetrics metr = this.getFontMetrics(small);
g.setColor(Color.white);
g.setFont(small);
g.drawString(msg, (WIDTH - metr.stringWidth(msg)) / 2, HEIGHT / 2);
g.drawString("Total Score: " + score, (WIDTH - metr.stringWidth(msg)) /2 - 12, (HEIGHT / 2) - 18);
g.drawString("Press Space to Continue", (WIDTH - metr.stringWidth(msg)) /2 - 77, (HEIGHT / 2) + 18);
setBackground(Color.decode("0x3F919E"));
}
}
public void move() {
for (int z = dots; z > 0; z--) {
x[z] = x[(z - 1)];
y[z] = y[(z - 1)];
}
if (left) {
x[0] -= DOT_SIZE;
}
if (right) {
x[0] += DOT_SIZE;
}
if (up) {
y[0] -= DOT_SIZE;
}
if (down) {
y[0] += DOT_SIZE;
}
}
public void checkCollision() {
for (int z = dots; z > 0; z--) {
if ((z > 4) && (x[0] == x[z]) && (y[0] == y[z])) {
inGame = false;
}
}
if (y[0] > HEIGHT) {
inGame = false;
}
if (y[0] < 0) {
inGame = false;
}
if (x[0] > WIDTH) {
inGame = false;
}
if (x[0] < 0) {
inGame = false;
}
}
public void locateFood() {
int r = (int) (Math.random() * RAND_POS);
food_x = ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
food_y = ((r * DOT_SIZE));
}
public void locatePowerDown() {
int r = (int) (Math.random() * RAND_POS);
pdown_x = ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
pdown_y = ((r * DOT_SIZE));
}
public void locateDoubleUp() {
int r = (int) (Math.random() * RAND_POS);
rdouble_x= ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
rdouble_y = ((r * DOT_SIZE));
}
public void locatePowerUp() {
int r = (int) (Math.random() * RAND_POS);
powerUp_x= ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
powerUp_y = ((r * DOT_SIZE));
}
public void locateHalfDown() {
int r = (int) (Math.random() * RAND_POS);
half_x= ((r * DOT_SIZE));
r = (int) (Math.random() * RAND_POS);
half_y = ((r * DOT_SIZE));
}
public void actionPerformed(ActionEvent e) {
if (inGame) {
if(Menu.pause){
}
try {
checkApple();
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (LineUnavailableException e1) {
e1.printStackTrace();
}
checkCollision();
move();
}
repaint();
}
public void reset(){
left = false;
right = true;
up = false;
down = false;
inGame = true;
score = 0;
fruitEaten = 0;
for (int z = 0; z < dots; z++) {
x[z] = 50 - z*10;
y[z] = 50;
}
dots = 5;
bpower = false;
locatePowerDown();
RDouble = false;
locateDoubleUp();
locatePowerUp();
locateFood();
repaint();
}
private class TAdapter extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_SPACE){
if(inGame){
if(Menu.pause){
Menu.pause = false;
}else if(!Menu.pause){
Menu.pause = true;
}
}
if(!inGame){
reset();
}
}
if(key == KeyEvent.VK_P){
if(Menu.pause){
Menu.pause = false;
}else if(!Menu.pause){
Menu.pause = true;
}
}
if ((key == KeyEvent.VK_LEFT || key == KeyEvent.VK_A) && (!right)) {
left = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_RIGHT ||key == KeyEvent.VK_D) && (!left)) {
right = true;
up = false;
down = false;
}
if ((key == KeyEvent.VK_UP || key == KeyEvent.VK_W) && (!down)) {
up = true;
right = false;
left = false;
}
if ((key == KeyEvent.VK_DOWN || key == KeyEvent.VK_S) && (!up)) {
down = true;
right = false;
left = false;
}
}
}
}
根据您的描述,您的代码正在移动之前更改布尔变量。一个简单的解决方案是将所有移动存储在一个队列中,并通过删除它们进行处理,这样可以确保不会覆盖移动 换句话说,每次记录一个会改变布尔值的关键事件时,在队列中存储某种类型的信号,例如int、字符串、枚举等,在move方法中,只需从队列前面移除信号,并像处理布尔变量一样处理它。如果您要为上下左右使用枚举,那么它将是相当可读的,并且您可以使用开关案例来处理每个移动 前 其中,movement是从队列中移除的信号,上下左右是enum,因此它们可以是int常量,但正如Bloch在effectivejava中所建议的那样,更喜欢enum类型而不是int常量
private enum Movement { UP, DOWN, RIGHT, LEFT }
这允许您在上面的开关中引用这些类型,并按如下方式实例化队列:
Queue<Movement> movementQueue = new ArrayDeque<Movement>();
Movement movement = movementQueue.poll();
当您准备好使用它们时,请按如下方式访问它们:
Queue<Movement> movementQueue = new ArrayDeque<Movement>();
Movement movement = movementQueue.poll();
有关队列的详细信息:
有关枚举的详细信息:
另外,因为您说您是Java新手,所以我建议您首先使用Java作为开销视图,使用有效的Java来学习大量的最佳实践。第一个建议是将您的方法分解为更简单、更易于阅读的方法。这将有助于缩小您的问题范围,并帮助我们更快地帮助您解决问题。在您的按键功能中,你正在检查以确保他们没有按与上次按下的键相反的方向-最好检查他们没有按与蛇实际移动方向相反的方向。顺便说一句,你不应该覆盖SwingComponents中的paint,paint Component阅读此内容,你是忍者你。我也希望发布一些关于队列的信息。我不想问你代码,因为我什么都学不到,但你能帮我多一点吗?我对Java非常陌生,所以我对它不太了解,比如如何使用队列?另外,当你评论向上代码、向左代码、向右代码或向下代码时,你指的是关键代码吗?如果我问得太多,我很抱歉,但正如我之前所说,我还在学习。一点问题都没有,至于向上的代码等等,我的意思是你把你的动作代码放在那些方向上-从左到右-那些注释所在的地方。至于使用队列,我想你从来没有见过一个是彻底的。队列是一种数据结构,您可以在其中向末尾添加一个元素,然后将它们从前端删除?这或多或少是一个等待名单。在java中,队列是一个接口,所以您可以使用实现它的任何类。具体来说,如果您真的选择了以下两个选项之一,则会将其分为两个注释。ArrayDeque-当您在内部需要数组时。LinkedList-当您需要链接列表时。通常,您会发现ArrayDeque速度更快,因此我将在这里使用它。要使用队列,您只需要一个实例变量,如下面的private queue movementQueue;您在构造函数中实例化它,使其成为您想要的实现,在本例中,movementQueue=new ArrayDeque;然后,只需调用offer在末尾添加一个动作,然后轮询从前面删除一个动作。要使用枚举类型,请参阅我将要在原始帖子中进行的编辑。好的,感谢所有帮助,但这似乎不起作用。它解决了这个问题,但也造成了一个新的问题。它走得太慢了。