创建一个蛇游戏,当你按两个方向快速蛇吃自己[Java]

时间:2013-06-15 04:21:13

标签: java user-interface

我希望这是有道理的,但我正在尝试用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;
            }
        }


                }
    }

1 个答案:

答案 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用于学习大量的最佳实践。