我希望这是有道理的,但我正在尝试用Java制作一个蛇式游戏,如果你同时按两个方向/太快,那么蛇就会自行消失。 例如,如果你向下跑,然后向右击,那么你就会让蛇在同一列上直接上升并自杀,但它应该向右然后向上。如果有人能帮助我,那就太好了,谢谢!
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;
}
}
}
}
答案 0 :(得分:7)
根据您的描述,您的代码在移动发生之前更改布尔变量。一个简单的解决方案是将所有移动存储在队列中,并通过删除它们来处理它们,这样就可以确保不会覆盖移动。
换句话说,每当你录制一个会改变布尔值的键事件时,在队列中存储某种信号(int,String,enum等),在你的move方法中,只需删除来自队列前面的信号并像处理布尔变量一样处理它。如果你使用enum for UP DOWN RIGHT LEFT它将是相当可读的,你可以使用switch-case来处理每个动作。
离。
switch (movement) {
case UP: /* up code */ break;
case LEFT: /* left code */ break;
case RIGHT: /* right code */ break;
case DOWN: /* down code */ break;
}
其中,move是从队列中删除的信号,UP DOWN RIGHT LEFT是enum的(就此而言,它们可能是int常量,但正如Bloch在Effective Java中推荐的那样,更喜欢枚举类型为int常量。)
private enum Movement { UP, DOWN, RIGHT, LEFT }
这允许您在上面的开关中引用这些类型,并按如下方式实例化Queue:
Queue<Movement> movementQueue = new ArrayDeque<Movement>();
这反过来意味着您只需执行以下操作即可添加您需要的任何动作:
movementQueue.offer(UP); // or DOWN or RIGHT or LEFT, whichever you want.
当您准备好使用它们时,请按以下方式访问它们:
Movement movement = movementQueue.poll();
有关队列的更多信息:http://docs.oracle.com/javase/6/docs/api/java/util/Queue.html 有关枚举的更多信息:http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html
另外,因为你说你是Java的新手,我建议Head First:Java用于开销视图,而Effective Java用于学习大量的最佳实践。