java 贪吃蛇之我的实现
来源:互联网 发布:如何网络共享打印机 编辑:程序博客网 时间:2024/05/03 09:55
java 贪吃蛇之我的实现
一、实现原理
- 地图分成等份的点
- 蛇身由很多点组成
- 蛇的移动可以看成头部加了一个点,尾部少了一个点
二、实现细节
- 新建一张600*560的地图,X轴与Y轴各自以10像素为单位等分,分成60*56=3360个点,每个点均为10*10大小
- 用二维数组存放所有的点(或者用LinkedList)
- 细节化点类
- 细节化蛇类
- 添加蛇运动的线程,添加监听器,控制蛇的移动
三、细节优化
- 食物点可以直接画一个矩形,蛇应该怎样画。如果蛇身的点也画成矩形,会造成并排的蛇身之间没有空隙,美感度太差
- 监听器的几种实现方式,各自的优缺点以及bug解决
四、解决方案
- 给点Node加一个属性:direction,初始值为0。当蛇头吃掉某个点后,这个点的direction属性就变成蛇前进的方向(上下左右),当作为蛇尾移除出蛇身后,direction重归于0
- 蛇类也有自己的direction属性,代表蛇下一次移动的方向,需要注意的是,这个direction和蛇头点的direction不一定相同(当不同的时候就说明蛇转弯了嘛)
- 监听的方式大致分两种,一种是按下方向键后蛇立即移动一次,这样做的好处是永远不会出bug,而且还可以实现按住不放加速的效果,但是也会造成转弯速度过快的缺点。二是按下方向键只改变蛇的移动方向,蛇本身还是匀速运动。
- 蛇的画法,蛇身采用每个点的方向,以及它上一个点的方向,来确定画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) { }}
0 0
- java 贪吃蛇之我的实现
- 贪吃蛇的Java实现
- 贪吃蛇的Java实现
- 我的贪吃蛇
- 贪吃蛇实现--Java
- Java实现贪吃蛇
- 高效率的贪吃蛇-Java实现
- JAVA简易贪吃蛇的实现
- Java贪吃蛇的简单实现
- Java实现简单的贪吃蛇
- 毕业设计 贪吃蛇 注释+源代码 我的java学习之路
- Java之贪吃蛇游戏的开发
- 我做的贪吃蛇
- Java贪吃游戏的实现
- Java贪吃游戏的实现!
- JAVA实现贪吃蛇游戏
- Java ,实现贪吃蛇小游戏
- java实现贪吃蛇小游戏
- JS设置cookie、读取cookie、删除cookie
- 自治事务和变异表的行级触发器部分问题
- spark初窥
- Atitti css transition Animation differ区别
- 广度优先搜索
- java 贪吃蛇之我的实现
- eclipse启动错误:Java was started but returned exit code=13
- java中thread的start()和run()的区别
- Atitit数据库层次架构表与知识点 attilax 总结
- No plugin found for prefix ‘war’ in the current project and in the plugin groups
- flask权限管理功能的实现
- 欢迎使用CSDN-markdown编辑器
- python学习日记1
- linux驱动开发:用户空间操作LCD显示简单的图片