使用Java 语言编写一个贪吃蛇游戏

使用 Java 语言编写一个贪吃蛇游戏,代码如下: GreedSnake .java

1 2public class GreedSnake { 3 public static void main(String[] args) { 4 SnakeModel model = new SnakeModel(20, 30); 5 SnakeControl control = new SnakeControl(model); 6 SnakeView view = new SnakeView(model, control); 7 // 添加一个观察者,让view成为model的观察者 8 model.addObserver(view); 9 new Thread(model).start(); 10 } 11}

SnakeControl.java

1import java.awt.event.KeyEvent; 2import java.awt.event.KeyListener; 3 4public class SnakeControl implements KeyListener{ 5 SnakeModel model; 6 7 public SnakeControl(SnakeModel model){ 8 this.model = model; 9 } 10 11 public void keyPressed(KeyEvent e) { 12 int keyCode = e.getKeyCode(); 13 if (model.running){ // 运行状态下,处理的按键 14 switch (keyCode) { 15 case KeyEvent.VK_UP: 16 model.changeDirection(SnakeModel.UP); 17 break; 18 case KeyEvent.VK_DOWN: 19 model.changeDirection(SnakeModel.DOWN); 20 break; 21 case KeyEvent.VK_LEFT: 22 model.changeDirection(SnakeModel.LEFT); 23 break; 24 case KeyEvent.VK_RIGHT: 25 model.changeDirection(SnakeModel.RIGHT); 26 break; 27 case KeyEvent.VK_ADD: 28 case KeyEvent.VK_PAGE_UP: 29 model.speedUp(); 30 break; 31 case KeyEvent.VK_SUBTRACT: 32 case KeyEvent.VK_PAGE_DOWN: 33 model.speedDown(); 34 break; 35 case KeyEvent.VK_SPACE: 36 case KeyEvent.VK_P: 37 model.changePauseState(); 38 break; 39 default: 40 } 41 } 42 43 // 任何情况下处理的按键,按键导致重新启动游戏 44 if (keyCode == KeyEvent.VK_R || 45 keyCode == KeyEvent.VK_S || 46 keyCode == KeyEvent.VK_ENTER) { 47 model.reset(); 48 } 49 } 50 51 public void keyReleased(KeyEvent e) { 52 } 53 54 public void keyTyped(KeyEvent e) { 55 } 56}

SnakeModel.java

1 2import javax.swing.*; 3import java.util.Arrays; 4import java.util.LinkedList; 5import java.util.Observable; 6import java.util.Random; 7class SnakeModel extends Observable implements Runnable { 8 boolean[][] matrix; // 指示位置上有没蛇体或食物 9 LinkedList nodeArray = new LinkedList(); // 蛇体 10 Node food; 11 int maxX; //横列 12 int maxY; //纵列 13 int direction = 2; // 蛇运行的方向 14 boolean running = false; // 运行状态 15 16 int timeInterval = 200; // 时间间隔,毫秒 17 double speedChangeRate = 0.75; // 每次得速度变化率 18 boolean paused = false; // 暂停标志 19 20 int score = 0; // 得分 21 int countMove = 0; // 吃到食物前移动的次数 22 23 // UP and DOWN should be even 24 // RIGHT and LEFT should be odd 25 public static final int UP = 2; 26 public static final int DOWN = 4; 27 public static final int LEFT = 1; 28 public static final int RIGHT = 3; 29 30 public SnakeModel( int maxX, int maxY) { 31 this.maxX = maxX; 32 this.maxY = maxY; 33 reset(); 34 } 35 36 public void reset(){ 37 direction = SnakeModel.UP; // 蛇运行的方向 38 timeInterval = 200; // 时间间隔,毫秒 39 paused = false; // 暂停标志 40 score = 0; // 得分 41 countMove = 0; // 吃到食物前移动的次数 42 43 // initial matirx, 全部清0 44 matrix = new boolean[maxX][]; 45 for (int i = 0; i < maxX; ++i) { 46 matrix[i] = new boolean[maxY]; 47 Arrays.fill(matrix[i], false); 48 } 49 50 // initial the snake 51 // 初始化蛇体,如果横向位置超过20个,长度为10,否则为横向位置的一半 52 int initArrayLength = maxX > 20 ? 10 : maxX / 2; 53 nodeArray.clear(); 54 for (int i = 0; i < initArrayLength; ++i) { 55 int x = maxX / 2 + i;//maxX被初始化为20 56 int y = maxY / 2; //maxY被初始化为30 57 //nodeArray[x,y]: [10,15]-[11,15]-[12,15]~~[20,15] 58 //默认的运行方向向上,所以游戏一开始nodeArray就变为: 59 // [10,14]-[10,15]-[11,15]-[12,15]~~[19,15] 60 nodeArray.addLast(new Node(x, y)); 61 matrix[x][y] = true; 62 } 63 64 // 创建食物 65 food = createFood(); 66 matrix[food.x][food.y] = true; 67 } 68 69 public void changeDirection(int newDirection) { 70 // 改变的方向不能与原来方向同向或反向 71 if (direction % 2 != newDirection % 2) { 72 direction = newDirection; 73 } 74 } 75 76 public boolean moveOn() { 77 Node n = (Node) nodeArray.getFirst(); 78 int x = n.x; 79 int y = n.y; 80 81 // 根据方向增减坐标值 82 switch (direction) { 83 case UP: 84 y--; 85 break; 86 case DOWN: 87 y++; 88 break; 89 case LEFT: 90 x--; 91 break; 92 case RIGHT: 93 x++; 94 break; 95 } 96 97 // 如果新坐标落在有效范围内,则进行处理 98 if ((0 <= x && x < maxX) && (0 <= y && y < maxY)) { 99 100 if (matrix[x][y]) { // 如果新坐标的点上有东西(蛇体或者食物) 101 if (x == food.x && y == food.y) { // 吃到食物,成功 102 nodeArray.addFirst(food); // 从蛇头赠长 103 104 // 分数规则,与移动改变方向的次数和速度两个元素有关 105 int scoreGet = (10000 - 200 * countMove) / timeInterval; 106 score += scoreGet > 0 ? scoreGet : 10; 107 countMove = 0; 108 109 food = createFood(); // 创建新的食物 110 matrix[food.x][food.y] = true; // 设置食物所在位置 111 return true; 112 } else // 吃到蛇体自身,失败 113 return false; 114 115 } else { // 如果新坐标的点上没有东西(蛇体),移动蛇体 116 nodeArray.addFirst(new Node(x, y)); 117 matrix[x][y] = true; 118 n = (Node) nodeArray.removeLast(); 119 matrix[n.x][n.y] = false; 120 countMove++; 121 return true; 122 } 123 } 124 return false; // 触到边线,失败 125 } 126 127 public void run() { 128 running = true; 129 while (running) { 130 try { 131 Thread.sleep(timeInterval); 132 } catch (Exception e) { 133 break; 134 } 135 136 if (!paused) { 137 if (moveOn()) { 138 setChanged(); // Model通知View数据已经更新 139 notifyObservers(); 140 } else { 141 JOptionPane.showMessageDialog(null, 142 "you failed", 143 "Game Over", 144 JOptionPane.INFORMATION_MESSAGE); 145 break; 146 } 147 } 148 } 149 running = false; 150 } 151 152 private Node createFood() { 153 int x = 0; 154 int y = 0; 155 // 随机获取一个有效区域内的与蛇体和食物不重叠的位置 156 do { 157 Random r = new Random(); 158 x = r.nextInt(maxX); 159 y = r.nextInt(maxY); 160 } while (matrix[x][y]); 161 162 return new Node(x, y); 163 } 164 165 public void speedUp() { 166 timeInterval *= speedChangeRate; 167 } 168 169 public void speedDown() { 170 timeInterval /= speedChangeRate; 171 } 172 173 public void changePauseState() { 174 paused = !paused; 175 } 176 177 public String toString() { 178 String result = ""; 179 for (int i = 0; i < nodeArray.size(); ++i) { 180 Node n = (Node) nodeArray.get(i); 181 result += "[" + n.x + "," + n.y + "]"; 182 } 183 return result; 184 } 185} 186 187class Node { 188 int x; 189 int y; 190 191 Node(int x, int y) { 192 this.x = x; 193 this.y = y; 194 } 195}

SnakeView.java

1 2import javax.swing.*; 3import java.awt.*; 4import java.util.Iterator; 5import java.util.LinkedList; 6import java.util.Observable; 7import java.util.Observer; 8 9public class SnakeView implements Observer { 10 SnakeControl control = null; 11 SnakeModel model = null; 12 13 JFrame mainFrame; 14 Canvas paintCanvas; 15 JLabel labelScore; 16 17 public static final int canvasWidth = 200; 18 public static final int canvasHeight = 300; 19 20 public static final int nodeWidth = 10; 21 public static final int nodeHeight = 10; 22 23 public SnakeView(SnakeModel model, SnakeControl control) { 24 this.model = model; 25 this.control = control; 26 27 mainFrame = new JFrame("贪吃蛇"); 28 29 Container cp = mainFrame.getContentPane(); 30 31 // 创建顶部的分数显示 32 labelScore = new JLabel("Score:"); 33 cp.add(labelScore, BorderLayout.NORTH); 34 35 // 创建中间的游戏显示区域 36 paintCanvas = new Canvas(); 37 paintCanvas.setSize(canvasWidth + 1, canvasHeight + 1); 38 paintCanvas.addKeyListener(control); 39 cp.add(paintCanvas, BorderLayout.CENTER); 40 41 // 创建底下的帮助栏 42 JPanel panelButtom = new JPanel(); 43 panelButtom.setLayout(new BorderLayout()); 44 JLabel labelHelp; 45 labelHelp = new JLabel("PageUp, PageDown for speed;", JLabel.CENTER); 46 panelButtom.add(labelHelp, BorderLayout.NORTH); 47 labelHelp = new JLabel("ENTER or R or S for restart;", JLabel.CENTER); 48 panelButtom.add(labelHelp, BorderLayout.CENTER); 49 labelHelp = new JLabel("SPACE or P for pause", JLabel.CENTER); 50 panelButtom.add(labelHelp, BorderLayout.SOUTH); 51 cp.add(panelButtom, BorderLayout.SOUTH); 52 53 mainFrame.addKeyListener(control); 54 mainFrame.pack(); 55 mainFrame.setResizable(false); 56 mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 57 mainFrame.setVisible(true); 58 } 59 60 void repaint() { 61 Graphics g = paintCanvas.getGraphics(); 62 63 // draw background 64 g.setColor(Color.WHITE); 65 g.fillRect(0, 0, canvasWidth, canvasHeight); 66 67 // draw the snake 68 g.setColor(Color.BLACK); 69 LinkedList na = model.nodeArray; 70 Iterator it = na.iterator(); 71 while (it.hasNext()) { 72 Node n = (Node) it.next(); 73 drawNode(g, n); 74 } 75 76 // draw the food 77 g.setColor(Color.RED); 78 Node n = model.food; 79 drawNode(g, n); 80 81 updateScore(); 82 } 83 84 private void drawNode(Graphics g, Node n) { 85 g.fillRect(n.x * nodeWidth, n.y * nodeHeight, nodeWidth - 1, 86 nodeHeight - 1); 87 } 88 89 public void updateScore() { 90 String s = "Score: " + model.score; 91 labelScore.setText(s); 92 } 93 94 public void update(Observable o, Object arg) { 95 repaint(); 96 } 97}

运行结果如下: image image

更多知识欢迎关注微信公众号“51学代码”

网址:www.51xcode.com链接

作者博客:https://hello1024.world (你好1024的世界)链接 image

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )