使用Java中Frame来实现一个简单的贪吃蛇小游戏,游戏中使用了线程、内部类、双向链表等。
主要包含四个类:
Snake:生成蛇、蛇的移动、添加、碰撞判断
Egg:生成一个食物、画出食物
Yard:生成一个窗体、实现贪吃蛇的主要功能
Dir:四个方向,上下左右
实现效果图:
Snake.java
import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.util.Map; /** * * @Description * @author CCQ * @date 2017年6月22日 下午5:22:03 * */ public class Snake { private Node head = null; //蛇头 private Node tail = null; //蛇尾 private int size = 0; //蛇长度 private Node n = new Node(20,20, Dir.L); //初始化蛇的位子 private Yard y; public Snake(Yard y) { head = n; tail = n; size = 1; this.y = y; } /** * 加一段在尾巴上 */ public void addToTail() { Node node = null; switch (tail.dir) { case L: node = new Node(tail.row, tail.col + 1, tail.dir); break; case U: node = new Node(tail.row + 1, tail.col, tail.dir); break; case R: node = new Node(tail.row, tail.col - 1, tail.dir); break; case D: node = new Node(tail.row - 1, tail.col, tail.dir); break; } tail.next = node; node.prev = tail; tail = node; size++; } /** * 加一段在头上 */ public void addHead() { Node node = null; switch (head.dir) { case L: node = new Node(head.row, head.col - 1, head.dir); break; case U: node = new Node(head.row - 1, head.col, head.dir); break; case R: node = new Node(head.row, head.col + 1, head.dir); break; case D: node = new Node(head.row + 1, head.col, head.dir); break; } node.next = head; head.prev = node; head = node; size++; } //画出一条蛇 public void drow(Graphics g) { if (size <= 0) { return; } move(); for (Node n = head; n != null; n = n.next) { n.drow(g); } } //蛇移动 public void move() { addHead(); deleteFromTail(); checkDead(); } //检查是否碰撞 public void checkDead() { if (head.row <3 || head.col < 1 || head.row > Yard.ROWS - 2 || head.col > Yard.COLS - 2) { y.stop(); } for (Node n = head.next; n != null; n = n.next) { if (head.row == n.row && head.col == n.col) { y.stop(); } } } //删出蛇尾 public void deleteFromTail() { if (size == 0) return; tail = tail.prev; tail.next = null; } //定义一个内部类,实现蛇的生成,双向链表 private class Node { int w = Yard.BLOCK_SIZE; int h = Yard.BLOCK_SIZE; int row, col; Dir dir = Dir.L; Node next = null; //链表,后一个指针 Node prev = null; //链表,前一个指针 public Node(int row, int col, Dir dir) { super(); this.row = row; this.col = col; this.dir = dir; } void drow(Graphics g) { Color c = g.getColor(); g.setColor(Color.BLACK); g.fillRect(Yard.BLOCK_SIZE * col, Yard.BLOCK_SIZE * row, w, h); g.setColor(c); } } //吃食物 public void eat(Egg e) { if (this.getRect().intersects(e.getRect())) { boolean isSuccess = false; while(!isSuccess){ Map<String, Integer> map = e.reAppear(); for(Node n = head;n!=null;n=n.next){ if(n.row != map.get("row") || n.col != map.get("col")){ isSuccess = true; } } } this.addToTail(); y.setScore(y.getScore() + 5); } } public Rectangle getRect() { return new Rectangle(Yard.BLOCK_SIZE * head.col, Yard.BLOCK_SIZE * head.row, head.w, head.h); } // 键盘事件,控制蛇的方向 public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); switch (key) { case KeyEvent.VK_LEFT: if (head.dir != Dir.R) head.dir = Dir.L; break; case KeyEvent.VK_UP: if (head.dir != Dir.D) head.dir = Dir.U; break; case KeyEvent.VK_RIGHT: if (head.dir != Dir.L) head.dir = Dir.R; break; case KeyEvent.VK_DOWN: if (head.dir != Dir.U) head.dir = Dir.D; break; } } }
Egg.java
import java.awt.Color; import java.awt.Graphics; import java.awt.Rectangle; import java.util.HashMap; import java.util.Map; import java.util.Random; /** * * @Description 生成食物 * @author CCQ * @date 2017年6月23日 上午9:23:59 * */ public class Egg { int row, col; int w = Yard.BLOCK_SIZE; int h = Yard.BLOCK_SIZE; private static Random r = new Random(); public Egg(int row, int col) { super(); this.row = row; this.col = col; } public Egg() { this(r.nextInt(Yard.ROWS - 5) +3, r.nextInt(Yard.COLS - 3) +2); } //重新设计生成食物 public Map<String, Integer> reAppear() { this.row = r.nextInt(Yard.ROWS - 5) +3; this.col = r.nextInt(Yard.COLS - 3) +2; Map<String, Integer> map = new HashMap<String, Integer>(); map.put("row", this.row); map.put("col", this.col); return map; } public Rectangle getRect() { return new Rectangle(Yard.BLOCK_SIZE * this.col, Yard.BLOCK_SIZE * this.row, this.w, this.h); } //画出食物 public void drow(Graphics g) { Color c = g.getColor(); g.setColor(Color.GREEN); g.fillOval(Yard.BLOCK_SIZE * col, Yard.BLOCK_SIZE * row, w, h); g.setColor(c); } }
Yard.java
import java.awt.Color; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; import java.awt.Image; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; /** * * @Description * @author CCQ * @date 2017年6月23日 下午6:24:06 * */ public class Yard extends Frame { private static final long serialVersionUID = 1L; public static final int ROWS = 30; //定义行数 public static final int COLS = 30; //定义列数 public static final int BLOCK_SIZE = 15; private Font fontGameOver = new Font("宋体", Font.BOLD, 50); private int score= 0; //计算获得分数 private boolean gameOver = false; //是否死亡 Snake s = new Snake(this); Egg e = new Egg(); Image offScreenImage = null; PaintThread paintThread = new PaintThread(); public int getScore() { return score; } public void setScore(int score) { this.score = score; } /** * 生成一个窗口 */ public void launch() { this.setLocation(450, 150); this.setSize(COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); this.setVisible(true); this.addKeyListener(new KeyMonitor()); new Thread(paintThread).start(); } //解决窗口闪烁 @Override public void update(Graphics g) { if (offScreenImage == null) { offScreenImage = this.createImage(COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); } Graphics goff = offScreenImage.getGraphics(); paint(goff); g.drawImage(offScreenImage, 0, 0, null); } //停止 public void stop() { this.gameOver = true; } //画出方格 @Override public void paint(Graphics g) { Color c = g.getColor(); g.setColor(Color.GRAY); g.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE); g.setColor(Color.DARK_GRAY); // 画出横线 for (int i = 3; i <= ROWS -1; i++) { g.drawLine(BLOCK_SIZE, BLOCK_SIZE * i, (COLS - 1) * BLOCK_SIZE, BLOCK_SIZE * i); } // 画竖线 for (int j = 1; j <= COLS -1; j++) { g.drawLine(BLOCK_SIZE * j, BLOCK_SIZE * 3, BLOCK_SIZE * j, (ROWS - 1)* BLOCK_SIZE); } g.setColor(Color.YELLOW); g.drawString("分数:"+score+" 按F5可以重新开始", 10, 40); if(gameOver){ g.setColor(Color.RED); g.setFont(fontGameOver); g.drawString("GAME OVER",85, 225); paintThread.pause(); } g.setColor(c); s.eat(e); e.drow(g); s.drow(g); } private class PaintThread implements Runnable { private boolean pause = false; private boolean running = true; @Override public void run() { while (running) { try { if(pause) continue; else repaint(); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public void pause() { this.pause = true; } public void reStart() { this.pause = false; new Yard().launch(); gameOver = false; } } //绑定键盘事件 private class KeyMonitor extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); if(key == KeyEvent.VK_F5) { paintThread.reStart(); } s.keyPressed(e); } } public static void main(String[] args) { new Yard().launch(); } }
Dir.java
/** * * @Description 蛇的方向 * @author CCQ * @date 2017年6月22日 下午5:33:05 * */ public enum Dir { //左 上 右 下 L,U,R,D }
原文链接:https://blog.csdn.net/qq_27717967/article/details/73655611
© 版权声明
声明📢本站内容均来自互联网,归原创作者所有,如有侵权必删除。
本站文章皆由CC-4.0协议发布,如无来源则为原创,转载请注明出处。
THE END