java 贪吃蛇之我的实现

来源:互联网 发布:如何网络共享打印机 编辑:程序博客网 时间:2024/05/03 09:55

java 贪吃蛇之我的实现

一、实现原理

  1. 地图分成等份的点
  2. 蛇身由很多点组成
  3. 蛇的移动可以看成头部加了一个点,尾部少了一个点

二、实现细节

  1. 新建一张600*560的地图,X轴与Y轴各自以10像素为单位等分,分成60*56=3360个点,每个点均为10*10大小
  2. 用二维数组存放所有的点(或者用LinkedList)
  3. 细节化点类
  4. 细节化蛇类
  5. 添加蛇运动的线程,添加监听器,控制蛇的移动

三、细节优化

  1. 食物点可以直接画一个矩形,蛇应该怎样画。如果蛇身的点也画成矩形,会造成并排的蛇身之间没有空隙,美感度太差
  2. 监听器的几种实现方式,各自的优缺点以及bug解决

四、解决方案

  1. 给点Node加一个属性:direction,初始值为0。当蛇头吃掉某个点后,这个点的direction属性就变成蛇前进的方向(上下左右),当作为蛇尾移除出蛇身后,direction重归于0
  2. 蛇类也有自己的direction属性,代表蛇下一次移动的方向,需要注意的是,这个direction和蛇头点的direction不一定相同(当不同的时候就说明蛇转弯了嘛)
  3. 监听的方式大致分两种,一种是按下方向键后蛇立即移动一次,这样做的好处是永远不会出bug,而且还可以实现按住不放加速的效果,但是也会造成转弯速度过快的缺点。二是按下方向键只改变蛇的移动方向,蛇本身还是匀速运动。
  4. 蛇的画法,蛇身采用每个点的方向,以及它上一个点的方向,来确定画10*10区域的哪些地方,食物就直接填满10*10

五、感悟
永远不要小瞧任何一个project,贪吃蛇最简单的实现只需要100多行代码而已,但是在美观上,在逻辑上,实现的方法可以说海量,如何选取最高效,内存占比最低,最美观的实现方案,这是每一次编写程序的时候需要反复斟酌的。

六、上代码

import java.awt.Color;import java.awt.Cursor;import java.awt.Font;import java.awt.Graphics;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.util.LinkedList;import java.util.Random;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JLayeredPane;import javax.swing.JOptionPane;import javax.swing.JPanel;public class RetroSnaker extends JFrame implements Runnable {    private static final long serialVersionUID = 1L;    private JLayeredPane rootpane;    private JLabel label_restart;    private JLabel label_score;    private SnakerGame snaker;    public static void main(String[] args) {        new RetroSnaker();    }    public RetroSnaker() {        init();    }    private void init() {        setTitle("Retro Snaker");        setSize(670, 680);        setBackground(Color.BLACK);        setLocationRelativeTo(null);        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        setResizable(false);        setLayout(null);        rootpane = new JLayeredPane();        rootpane.setBackground(Color.BLACK);        snaker = new SnakerGame();        snaker.setLocation(35, 60);        snaker.setDoubleBuffered(true);        rootpane.add(snaker);        label_restart = new JLabel("Restart");        label_restart.setBounds(400, 15, 150, 40);        label_restart.setFont(new Font("Times New Roman", Font.PLAIN, 30));        label_restart.setForeground(Color.LIGHT_GRAY);        rootpane.add(label_restart);        label_score = new JLabel("score: 0");        label_score.setFont(new Font("Times New Roman", Font.PLAIN, 30));        label_score.setForeground(Color.WHITE);        label_score.setBounds(200, 15, 150, 40);        rootpane.add(label_score);        setLayeredPane(rootpane);        setVisible(true);        new Thread(this).start();        addKeyListener(snaker);        label_restart.addMouseListener(new MouseListener() {            public void mouseReleased(MouseEvent e) {            }            public void mousePressed(MouseEvent e) {            }            public void mouseExited(MouseEvent e) {                label_restart.setForeground(Color.LIGHT_GRAY);                setCursor(new Cursor(Cursor.DEFAULT_CURSOR));            }            public void mouseEntered(MouseEvent e) {                label_restart.setForeground(Color.RED);                setCursor(new Cursor(Cursor.HAND_CURSOR));            }            public void mouseClicked(MouseEvent e) {                dispose();                new RetroSnaker();            }        });    }    @Override    public void run() {        while (true) {            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }            label_score.setText("score: " + snaker.snake.size() * 10);            snaker.repaint();            int res = snaker.move();            if (res == -1) {                JOptionPane.showMessageDialog(RetroSnaker.this, "Game Over\n本次得分:" + label_score.getText());                break;            }        }    }}class Node {    public int x, y, direction;    public final int UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4;    public Node(int x, int y, int direction) {        this.x = x;        this.y = y;        this.direction = direction;    }    public Node reDirection(){        this.direction = 0;        return this;    }    public void draw(Graphics g) {        if (direction == LEFT || direction == RIGHT) {            g.fillRect(x, y + 1, 10, 8);        } else {            g.fillRect(x + 1, y, 8, 10);        }    }    public void drawFood(Graphics g) {        g.setColor(Color.RED);        g.fillRect(x, y, 10, 10);    }    public boolean isSame(Node node) {        if (x == node.x && y == node.y)            return true;        return false;    }}class SnakerGame extends JPanel implements KeyListener {    private static final long serialVersionUID = 1L;    private LinkedList<Node> nodes = new LinkedList<>();    public LinkedList<Node> snake = new LinkedList<>();    public static final int UP = 1, DOWN = 2, LEFT = 3, RIGHT = 4;    public int direction = RIGHT;    private Node food;    private Random random = new Random();    public SnakerGame() {        setSize(601, 561);        for (int i = 0; i < 600; i += 10) {            for (int j = 60; j < 560; j += 10) {                nodes.add(new Node(i, j, 0));            }        }        food = nodes.remove(random.nextInt(nodes.size()));        Node node = nodes.remove(random.nextInt(nodes.size()));        node.direction = RIGHT;        snake.addFirst(node);    }    @Override    protected void paintComponent(Graphics g) {        super.paintComponent(g);        setOpaque(false);        g.setColor(Color.WHITE);        g.drawRect(0, 0, 600, 560);        for (int i = 0; i < snake.size(); i++) {            Node node = snake.get(i);            if (i != 0) {                Node n = snake.get(i - 1);                if (node.direction == UP) {                    if (n.direction == LEFT) {                        g.fillRect(node.x, node.y + 1, 9, 9);                        continue;                    }                    if (n.direction == RIGHT) {                        g.fillRect(node.x + 1, node.y + 1, 9, 9);                        continue;                    }                }                if (node.direction == DOWN) {                    if (n.direction == LEFT) {                        g.fillRect(node.x, node.y, 9, 9);                        continue;                    }                    if (n.direction == RIGHT) {                        g.fillRect(node.x + 1, node.y, 9, 9);                        continue;                    }                }                if (node.direction == LEFT) {                    if (n.direction == UP) {                        g.fillRect(node.x + 1, node.y, 9, 9);                        continue;                    }                    if (n.direction == DOWN) {                        g.fillRect(node.x + 1, node.y + 1, 9, 9);                        continue;                    }                }                if (node.direction == RIGHT) {                    if (n.direction == UP) {                        g.fillRect(node.x, node.y, 9, 9);                        continue;                    }                    if (n.direction == DOWN) {                        g.fillRect(node.x, node.y + 1, 9, 9);                        continue;                    }                }            }            node.draw(g);        }        food.drawFood(g);    }    public int move() {        Node node = snake.getFirst();        Node n = null;        switch (direction) {        case UP:            n = new Node(node.x, node.y - 10, UP);            if (n.x < 0 || n.x > 600 || n.y < 0 || n.y > 560)                return -1;            snake.addFirst(n);            nodes.remove(new Node(node.x, node.y - 10, 0));            if (!node.isSame(food))                nodes.add(snake.removeLast().reDirection());            else {                food = nodes.remove(random.nextInt(nodes.size()));                repaint();            }            break;        case DOWN:            n = new Node(node.x, node.y + 10, DOWN);            if (n.x < 0 || n.x > 600 || n.y < 0 || n.y > 560)                return -1;            snake.addFirst(n);            nodes.remove(new Node(node.x, node.y + 10, 0));            if (!node.isSame(food))                nodes.add(snake.removeLast().reDirection());            else {                food = nodes.remove(random.nextInt(nodes.size()));                repaint();            }            break;        case LEFT:            n = new Node(node.x - 10, node.y, LEFT);            if (n.x < 0 || n.x > 600 || n.y < 0 || n.y > 560)                return -1;            snake.addFirst(n);            nodes.remove(new Node(node.x - 10, node.y, 0));            if (!node.isSame(food))                nodes.add(snake.removeLast().reDirection());            else {                food = nodes.remove(random.nextInt(nodes.size()));                repaint();            }            break;        case RIGHT:            n = new Node(node.x + 10, node.y, RIGHT);            if (n.x < 0 || n.x > 590 || n.y < 0 || n.y > 550)                return -1;            snake.addFirst(n);            nodes.remove(new Node(node.x + 10, node.y, 0));            if (!node.isSame(food))                nodes.add(snake.removeLast().reDirection());            else {                food = nodes.remove(random.nextInt(nodes.size()));                repaint();            }            break;        }        int i = 0;        for (Node s : snake) {            if (s.isSame(n))                i++;        }        if (i >= 2)            return -1;        return 0;    }    @Override    public void keyTyped(KeyEvent e) {    }    @Override    public void keyPressed(KeyEvent e) {        switch (e.getKeyCode()) {        case KeyEvent.VK_UP:            if (snake.getFirst().direction != DOWN)                direction = UP;            break;        case KeyEvent.VK_DOWN:            if (snake.getFirst().direction != UP)                direction = DOWN;            break;        case KeyEvent.VK_LEFT:            if (snake.getFirst().direction != RIGHT)                direction = LEFT;            break;        case KeyEvent.VK_RIGHT:            if (snake.getFirst().direction != LEFT)                direction = RIGHT;            break;        }    }    @Override    public void keyReleased(KeyEvent e) {    }}

Retro Snaker 一种实现方式

0 0
原创粉丝点击