[Java] 图形编程,Snake Game

avatarplhDigital nomad

Snake Game

Preview

Image

Code

import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class SnakeGame {
    public static void main(String[] args) {
        SnakeFrame frame = new SnakeFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }

}

class StatusRunnable implements Runnable {
    public StatusRunnable(Snake snake, JLabel statusLabel, JLabel scoreLabel) {
        this.snake = snake;
        this.statusLabel = statusLabel;
        this.scoreLabel = scoreLabel;
    }

    public void run() {
        String sta = "";
        String spe = "";
        while (true) {
            switch (snake.status) {
                case Snake.RUNNING:
                    sta = "Running";
                    break;
                case Snake.PAUSED:
                    sta = "Paused";
                    break;
                case Snake.GAMEOVER:
                    sta = "Game Over";
                    break;
            }
            statusLabel.setText("Status: " + sta);
            scoreLabel.setText("Score: " + snake.score);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private JLabel scoreLabel;
    private JLabel statusLabel;
    private Snake snake;
}

class SnakeRunnable implements Runnable {
    public SnakeRunnable(Snake snake, Component component) {
        this.snake = snake;
        this.component = component;
    }

    public void run() {
        while (true) {
            try {
                snake.move();
                component.repaint();
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    private Snake snake;
    private Component component;
}

class Snake {
    boolean isRun = false;
    ArrayList<Node> body = new ArrayList<>();
    Node food = null;
    int direction;
    int score;
    int status;
    int speed;
    public static final int SLOW = 500;
    public static final int MID = 300;
    public static final int FAST = 100;
    public static final int RUNNING = 1;
    public static final int PAUSED = 2;
    public static final int GAMEOVER = 3;
    public static final int LEFT = 1;
    public static final int UP = 2;
    public static final int RIGHT = 3;
    public static final int DOWN = 4;

    public Snake() {
        speed = Snake.SLOW;
        score = 0;
        isRun = false;
        status = Snake.PAUSED;
        direction = Snake.RIGHT;
        body = new ArrayList<>();
        body.add(new Node(60, 20));
        body.add(new Node(40, 20));
        body.add(new Node(20, 20));
        makeFood();
    }

    private boolean isEaten() {
        Node head = body.get(0);
        if (direction == Snake.RIGHT && (head.x + Node.W) == food.x && head.y == food.y) {
            return true;
        } else if (direction == Snake.LEFT && (head.x - Node.W) == food.x && head.y == food.y) {
            return true;
        } else if (direction == Snake.UP && head.x == food.x && (head.y - Node.H) == food.y) {
            return true;
        } else if (direction == Snake.DOWN && head.x == food.x && (head.y + Node.H) == food.y) {
            return true;
        } else {
            return false;
        }
    }

    private boolean isCollision() {
        Node node = body.get(0);
        if (direction == Snake.RIGHT && node.x == 280) {
            return true;
        } else if (direction == Snake.LEFT && node.x == 0) {
            return true;
        } else if (direction == Snake.UP && node.y == 0) {
            return true;
        } else if (direction == Snake.DOWN && node.y == 380) {
            return true;
        }
        Node temp = null;
        int i = 0;
        for (i = 3; i < body.size(); i++) {
            temp = body.get(i);
            if (node.x == temp.x && node.y == temp.y) {
                return true;
            }
        }
        if (i == body.size()) {
            return true;
        } else {
            return false;
        }
    }

    public void makeFood() {
        Node node = new Node(0, 0);
        boolean isInBody = true;
        int x = 0;
        int y = 0;
        int X = 0;
        int Y = 0;
        int i = 0;
        while (isInBody) {
            x = (int) (Math.random() * 15);
            y = (int) (Math.random() * 20);
            X = x * Node.W;
            Y = y * Node.H;
            for (i = 0; i < body.size(); i++) {
                if (X == body.get(i).x && Y == body.get(i).y) {
                    break;
                }
            }
            if (i < body.size()) {
                isInBody = true;
            } else {
                isInBody = false;
            }
        }
        food = new Node(X, Y);
    }

    public void changeDirection(int newDer) {
        if (direction % 2 != newDer % 2) {
            direction = newDer;
        }
    }

    public void move() {
        if (isEaten()) {
            body.add(0, food);
            score += 10;
            makeFood();
        // } else if (isCollision()) {
        //     isRun = false;
        //     status = Snake.GAMEOVER;
        } else if (isRun) {
            Node node = body.get(0);
            int X = node.x;
            int Y = node.y;
            switch (direction) {
                case Snake.LEFT:
                    X -= Node.W;
                    break;
                case Snake.UP:
                    Y -= Node.H;
                    break;
                case Snake.RIGHT:
                    X += Node.W;
                    break;
                case Snake.DOWN:
                    Y += Node.H;
                    break;
            }
            body.add(0, new Node(X, Y));
            body.remove(body.size() - 1);
        }
    }
}

class Node {
    public static final int W = 20;
    public static final int H = 20;
    public int x;
    public int y;

    public Node(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

class SnakePanel extends JPanel {
    Snake snake;

    public SnakePanel(Snake snake) {
        this.snake = snake;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Node node = null;
        for (int i = 0; i < snake.body.size(); i++) {
            g.setColor(Color.BLACK);
            node = snake.body.get(i);
            g.fillRect(node.x, node.y, Node.W, Node.H);
        }
        node = snake.food;
        g.setColor(Color.RED);
        g.fillRect(node.x, node.y, Node.W, Node.H);
    }
}

class SnakeFrame extends JFrame {

    private JLabel statusLabel;
    private JLabel speedLabel;
    private JLabel scoreLabel;
    private JPanel snakePanel;
    private Snake snake;
    private JMenuBar bar;
    JMenu gameMenu;
    JMenu helpMenu;
    JMenu speedMenu;
    JMenuItem newItem;
    JMenuItem pauseItem;
    JMenuItem beginItem;
    JMenuItem helpItem;
    JMenuItem aboutItem;
    JMenuItem slowItem;
    JMenuItem midItem;
    JMenuItem fastItem;

    public SnakeFrame() {
        init();
        ActionListener l = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == pauseItem) {
                    snake.isRun = false;
                }
                if (e.getSource() == beginItem) {
                    snake.isRun = true;
                }
                if (e.getSource() == newItem) {
                    newGame();
                }
                // menu controller speed
                if (e.getSource() == slowItem) {
                    snake.speed = Snake.SLOW;
                    speedLabel.setText("Speed: Slow");
                }
                if (e.getSource() == midItem) {
                    snake.speed = Snake.MID;
                    speedLabel.setText("Speed: Mid");
                }
                if (e.getSource() == fastItem) {
                    snake.speed = Snake.FAST;
                    speedLabel.setText("Speed: Fast");
                }
            }
        };
        pauseItem.addActionListener(l);
        beginItem.addActionListener(l);

        newItem.addActionListener(l);

        aboutItem.addActionListener(l);

        slowItem.addActionListener(l);
        midItem.addActionListener(l);
        fastItem.addActionListener(l);

        addKeyListener(new KeyListener() {
            public void keyPressed(KeyEvent e) {
                int keyCode = e.getKeyCode();
                switch (keyCode) {
                    case java.awt.event.KeyEvent.VK_LEFT:
                        snake.changeDirection(Snake.LEFT);
                        break;
                    case java.awt.event.KeyEvent.VK_UP:
                        snake.changeDirection(Snake.UP);
                        break;
                    case java.awt.event.KeyEvent.VK_RIGHT:
                        snake.changeDirection(Snake.RIGHT);
                        break;
                    case java.awt.event.KeyEvent.VK_DOWN:
                        snake.changeDirection(Snake.DOWN);
                        break;
                    case java.awt.event.KeyEvent.VK_SPACE:
                        if (snake.isRun) {
                            snake.isRun = false;
                            snake.status = Snake.PAUSED;
                        } else {
                            snake.isRun = true;
                            snake.status = Snake.RUNNING;
                        }
                }
            }

            public void keyReleased(java.awt.event.KeyEvent e) {
            }

            public void keyTyped(KeyEvent e) {
            }
        });
    }

    private void init() {
        speedLabel = new JLabel();
        snake = new Snake();
        setSize(380, 460);
        setLayout(null);
        this.setResizable(false);
        bar = new JMenuBar();
        gameMenu = new JMenu("Game");
        newItem = new JMenuItem("New Game");
        gameMenu.add(newItem);
        pauseItem = new JMenuItem("Pause");
        gameMenu.add(pauseItem);
        beginItem = new JMenuItem("Continue");
        gameMenu.add(beginItem);
        helpMenu = new JMenu("Help");
        aboutItem = new JMenuItem("About");
        helpMenu.add(aboutItem);
        speedMenu = new JMenu("Speed");
        slowItem = new JMenuItem("Slow");
        midItem = new JMenuItem("Mid");
        fastItem = new JMenuItem("Fast");
        speedMenu.add(slowItem);
        speedMenu.add(midItem);
        speedMenu.add(fastItem);
        bar.add(gameMenu);
        bar.add(helpMenu);
        bar.add(speedMenu);
        this.setJMenuBar(bar);

        statusLabel = new JLabel();
        scoreLabel = new JLabel();
        snakePanel = new JPanel();
        snakePanel.setBounds(0, 0, 300, 400);
        snakePanel.setBorder(BorderFactory.createLineBorder(Color.darkGray));
        add(snakePanel);
        statusLabel.setBounds(300, 25, 60, 20);
        add(statusLabel);
        scoreLabel.setBounds(300, 20, 60, 20);
        add(scoreLabel);
        JLabel temp = new JLabel("Status");
        temp.setBounds(310, 5, 60, 20);
        add(temp);
        temp = new JLabel("Score");
        temp.setBounds(310, 105, 60, 20);
        add(temp);
        temp = new JLabel("Speed");
        temp.setBounds(310, 55, 60, 20);
        add(temp);
        speedLabel.setBounds(310, 75, 60, 20);
        add(speedLabel);
    }

    private void newGame() {
        this.remove(snakePanel);
        this.remove(statusLabel);
        this.remove(scoreLabel);
        speedLabel.setText("Slow");
        statusLabel = new JLabel();
        scoreLabel = new JLabel();
        snakePanel = new JPanel();
        snake = new Snake();
        snakePanel = new SnakePanel(snake);
        snakePanel.setBounds(0, 0, 380, 400);
        snakePanel.setBorder(BorderFactory.createLineBorder(Color.darkGray));
        Runnable r1 = new SnakeRunnable(snake, snakePanel);
        Runnable r2 = new StatusRunnable(snake, statusLabel, scoreLabel);
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
        add(snakePanel);
        statusLabel.setBounds(310, 25, 60, 20);
        add(statusLabel);
        scoreLabel.setBounds(310, 125, 60, 20);
        add(scoreLabel);
    }
}