当前位置:   article > 正文

Java代码实现贪吃蛇游戏_纯java实现贪吃蛇代码

纯java实现贪吃蛇代码

一、创建新项目

创建一个新的项目,并命名。创建一个名为images的文件夹用来存放游戏相关图片。然后再在项目的src文件下创建一个com.xxx.view的包用来存放所有的图形界面类,创建一个com.xxx.controller的包用来存放启动的入口类(控制类)。如下所示;

二、主要的游戏界面 

  1. package com.snake.view;
  2. import java.awt.Color;
  3. import java.awt.EventQueue;
  4. import java.awt.Font;
  5. import java.awt.Frame;
  6. import java.awt.Graphics;
  7. import java.awt.Image;
  8. import java.util.ArrayList;
  9. import java.util.List;
  10. import java.util.Random;
  11. import javax.swing.ImageIcon;
  12. import javax.swing.JFrame;
  13. import javax.swing.JOptionPane;
  14. import javax.swing.JPanel;
  15. import javax.swing.Timer;
  16. import javax.swing.border.EmptyBorder;
  17. import java.awt.event.ActionEvent;
  18. import java.awt.event.ActionListener;
  19. import java.awt.event.KeyAdapter;
  20. import java.awt.event.KeyEvent;
  21. public class SnakeJPanel extends JPanel implements ActionListener{
  22. private boolean start;//当前游戏状态
  23. private int speed;//速度
  24. private boolean exist;//当前是否存在食物
  25. private int foodType;//食物种类
  26. private int x;//豆子的横坐标
  27. private int y;//豆子的纵坐标
  28. private ArrayList<int[]> localList;//蛇
  29. public String direction;//方向
  30. private String direction2;//引导方向
  31. public boolean flag;
  32. Random rand = new Random();
  33. private ImageIcon up;
  34. private ImageIcon down;
  35. private ImageIcon right;
  36. private ImageIcon left;
  37. private ImageIcon body;
  38. private ImageIcon food;
  39. private ImageIcon title;
  40. Timer time;
  41. private int score;//当前得分情况
  42. private int num;//吃到的食物个数
  43. // private Image offScreenImage; //图形缓存
  44. //图片绘制
  45. @Override
  46. public void paint(Graphics g) {
  47. direction = direction2;
  48. g.setColor(Color.WHITE);
  49. g.fillRect(0, 0, 900, 700);
  50. //绘制游戏框
  51. //标题框
  52. // g.drawRect(25, 30, 800, 75);
  53. title.paintIcon(this, g, 25, 10);
  54. //内容框
  55. g.setColor(Color.black);
  56. g.fillRect(25, 75, 850, 600);
  57. //绘制食物的坐标位置
  58. if(!exist) {//如果当前不存在豆子,随机绘制一个豆子
  59. if(num % 5 == 0) {
  60. foodType = 1;
  61. }else {
  62. foodType = 0;
  63. }
  64. boolean isProduce = true;
  65. while(isProduce) {
  66. isProduce = false;
  67. x = rand.nextInt(33) * 25 + 25;
  68. y = rand.nextInt(23) * 25 + 75;
  69. for (int[] arr:localList) {
  70. if(x == arr[0] && y == arr[1]) {
  71. isProduce = true;
  72. break;
  73. }
  74. }
  75. }
  76. System.out.println(x + "---" + y);
  77. }
  78. if(eat()) {
  79. exist = false;
  80. }else {
  81. exist = true;
  82. }
  83. if(foodType == 0) {
  84. //绘制食物
  85. g.setColor(Color.blue);
  86. // g.fillRect(x, y, 25, 25);
  87. g.drawImage(food.getImage(),x, y, 25, 25,null);
  88. }else {
  89. //绘制食物
  90. g.setColor(Color.WHITE);
  91. g.fillRect(x, y, 25, 25);
  92. // g.drawImage(food.getImage(),x, y, 25, 25,null);
  93. }
  94. //绘制头
  95. g.setColor(Color.red);
  96. // g.fillRect(localList.get(0)[0], localList.get(0)[1], 25, 25);
  97. ImageIcon head = null;
  98. //判断当前方向
  99. if(direction.equals("R")) {
  100. head = right;
  101. }else if(direction.equals("L")) {
  102. head = left;
  103. }else if(direction.equals("U")) {
  104. head = up;
  105. }else if(direction.equals("D")) {
  106. head = down;
  107. }
  108. // g.drawImage(head.getImage(), localList.get(0)[0], localList.get(0)[1], 25, 25,null);
  109. head.paintIcon(this, g,localList.get(0)[0], localList.get(0)[1]);
  110. //绘制身体
  111. g.setColor(Color.white);
  112. for (int i = 1; i < localList.size(); i++) {
  113. // g.fillRect(localList.get(i)[0], localList.get(i)[1], 25, 25);
  114. // g.drawImage(body.getImage(), localList.get(i)[0], localList.get(i)[1], 25, 25,null);
  115. body.paintIcon(this, g, localList.get(i)[0], localList.get(i)[1]);
  116. }
  117. // g.fillRect(localList.get(1)[0], localList.get(1)[1], 25, 25);
  118. // g.fillRect(localList.get(2)[0], localList.get(2)[1], 25, 25);
  119. //绘制分数和长度
  120. //长度
  121. g.setColor(Color.GREEN);
  122. g.setFont(new Font("宋体", Font.BOLD, 18));
  123. g.drawString("长度:" + (localList.size() - 1), 25, 30);
  124. //分数
  125. g.drawString("分数:" + score, 25, 48);
  126. if(!start) {//如果游戏未启动,结束移动和重绘
  127. g.setColor(Color.white);
  128. g.setFont(new Font("宋体", Font.BOLD, 30));
  129. g.drawString("暂停/开始(请按任意键开始,空格键暂停)", 150, 300);
  130. time.stop();
  131. }else {
  132. time.start();
  133. }
  134. // speed();
  135. //移动后进行下一次绘制
  136. // move();//移动
  137. // repaint();//重新绘制
  138. }
  139. // //解决闪烁问题
  140. // //如果为JFrame 为重量级 程序不会调用update()方法
  141. // //如果为Frame 为轻量级 重写update()方法 做双缓冲
  142. // //如果为JPanel 不会闪烁
  143. // @Override
  144. // public void update(Graphics g)
  145. // {
  146. // System.out.println("update");
  147. // if(offScreenImage == null)
  148. // offScreenImage = this.createImage(900, 700); //新建一个图像缓存空间,这里图像大小为800*600
  149. // Graphics gImage = offScreenImage.getGraphics(); //把它的画笔拿过来,给gImage保存着
  150. // paint(gImage); //将要画的东西画到图像缓存空间去
  151. // g.drawImage(offScreenImage, 0, 0, null); //然后一次性显示出来
  152. // }
  153. @Override
  154. public void actionPerformed(ActionEvent e) {
  155. //移动后进行下一次绘制
  156. move();//移动
  157. repaint();//重新绘制
  158. }
  159. /**
  160. * 绘制速度
  161. */
  162. // private void speed() {
  163. // try {//按一定速度进行移动
  164. // Thread.sleep(speed);//控制移动速度
  165. // } catch (InterruptedException e) {
  166. // // TODO 自动生成的 catch 块
  167. // e.printStackTrace();
  168. // }
  169. // }
  170. /**
  171. * 初始化图片
  172. */
  173. private void drawImage() {
  174. up = new ImageIcon("images/up.png");
  175. down = new ImageIcon("images/down.png");
  176. right = new ImageIcon("images/right.png");
  177. left = new ImageIcon("images/left.png");
  178. body = new ImageIcon("images/body.png");
  179. food = new ImageIcon("images/food.png");
  180. title = new ImageIcon("images/title.jpg");
  181. }
  182. private boolean eat() {
  183. if(localList.get(0)[0] == x && localList.get(0)[1] == y) {//如果当前蛇头吃到了豆子
  184. System.out.println("eat");
  185. num++;
  186. if(foodType == 0) {
  187. score += 10;
  188. }else {
  189. score += (rand.nextInt(5) * 10 + 10);
  190. }
  191. int last = localList.size() - 1;//蛇尾
  192. //在蛇尾后面添加一节身体
  193. localList.add(new int[] {localList.get(last)[0],localList.get(last)[1]});
  194. return true;
  195. }
  196. return false;
  197. }
  198. //移动方法
  199. public void move() {
  200. //判断是否游戏结束
  201. if(isbody()) {
  202. System.out.println("game over");
  203. start = false;//结束游戏移动
  204. JOptionPane.showMessageDialog(null,"游戏已结束!");
  205. time.stop();
  206. init();
  207. }
  208. if(flag && localList != null) {//如果长度不为空且游戏未结束
  209. int last = localList.size() - 1;//记录蛇尾
  210. for (int i = last; i > 0; i--) {//从蛇尾开始,每节身体移动到前一节身体的位置上
  211. localList.set(i,new int[] {localList.get(i - 1)[0],localList.get(i - 1)[1]});
  212. }
  213. //记录头位置
  214. int[] local = localList.get(0);
  215. //判断当前方向,并进行模拟移动,判断是否与边界重合
  216. if(direction.equals("R")) {
  217. if(local[0] >= 850) {
  218. local[0] = 25;
  219. }else {
  220. local[0] += 25;
  221. }
  222. }else if(direction.equals("L")) {
  223. if(local[0] <= 25) {
  224. local[0] = 850;
  225. }else {
  226. local[0] -= 25;
  227. }
  228. }else if(direction.equals("U")) {
  229. if(local[1] <= 75) {
  230. local[1] = 650;
  231. }else {
  232. local[1] -= 25;
  233. }
  234. }else if(direction.equals("D")) {
  235. if(local[1] >= 650) {
  236. local[1] = 75;
  237. }else {
  238. local[1] += 25;
  239. }
  240. }
  241. //更改头的位置
  242. localList.set(0, local);
  243. }
  244. }
  245. //判断下一步是否为蛇身
  246. private boolean isbody() {
  247. // TODO 自动生成的方法存根
  248. //记录头位置
  249. int x = localList.get(0)[0];
  250. int y = localList.get(0)[1];
  251. //判断当前方向,并进行模拟移动,判断是否与边界重合
  252. if(direction.equals("R")) {
  253. x += 25;
  254. }else if(direction.equals("L")) {
  255. x -= 25;
  256. }else if(direction.equals("U")) {
  257. y -= 25;
  258. }else if(direction.equals("D")) {
  259. y += 25;
  260. }
  261. for (int i = 1; i < localList.size(); i++) {
  262. if(localList.get(i)[0] == x && localList.get(i)[1] == y) {
  263. return true;
  264. }
  265. }
  266. return false;
  267. }
  268. // //判断下一步是否为边界
  269. // private boolean isborder() {
  270. // // TODO 自动生成的方法存根
  271. // //记录头位置
  272. // // TODO 自动生成的方法存根
  273. // //记录头位置
  274. // int x = localList.get(0)[0];
  275. // int y = localList.get(0)[1];
  276. //
  277. // //判断当前方向,并进行模拟移动,判断是否与边界重合
  278. // if(direction.equals("R")) {
  279. // x += 25;
  280. // }else if(direction.equals("L")) {
  281. // x -= 25;
  282. // }else if(direction.equals("U")) {
  283. // y -= 25;
  284. // }else if(direction.equals("D")) {
  285. // y += 25;
  286. // }
  287. //
  288. // if(x < 25 || x > (33 * 25 + 25)) {
  289. // return true;//当x坐标超出边界,则返回true
  290. // }
  291. // if(y < 105 || y > (23 * 25 + 105)) {
  292. // return true;//当y坐标超出边界,则返回true
  293. // }
  294. // return false;//蛇头移动后未超出边界,返回false
  295. //
  296. // }
  297. /**
  298. * Create the frame.
  299. */
  300. public SnakeJPanel(int speed) {
  301. this.speed = speed; //初始化速度
  302. //初始化游戏面板的基本信息
  303. this.setSize(900, 700);
  304. this.setLocation(0, 30);
  305. this.setFocusable(true);
  306. init();//初始化界面
  307. drawImage();//绘制图片
  308. moveByKey();//给界面添加一个键盘监听
  309. }
  310. /*
  311. * 键盘监听
  312. * 通过键盘输入上下左右来控制当前蛇头移动的方向
  313. * 先判断当前蛇头方向,再来改变引导方向
  314. * 当进行绘制时再修改蛇的方向
  315. * 保证不会因为在短时间内快速变换方向导致蛇头逆向转向
  316. */
  317. private void moveByKey() {
  318. addKeyListener(new KeyAdapter() {
  319. @Override
  320. public void keyPressed(KeyEvent e) {
  321. int key = e.getKeyCode();
  322. //边界值判断
  323. switch(key) {
  324. case 65:
  325. case 37:{//向左走
  326. if(!direction.equals("R")) {
  327. direction2 = "L";
  328. }
  329. break;
  330. }
  331. case 87:
  332. case 38:{//向上走
  333. if(!direction.equals("D")) {
  334. direction2 = "U";
  335. }
  336. break;
  337. }
  338. case 68:
  339. case 39:{//向右走
  340. if(!direction.equals("L")) {
  341. direction2 = "R";
  342. }
  343. break;
  344. }
  345. case 83:
  346. case 40:{//向下走
  347. if(!direction.equals("U")) {
  348. direction2 = "D";
  349. }
  350. break;
  351. }
  352. case KeyEvent.VK_SPACE:{//如果当前键盘输入为空格
  353. start = !start;//调整游戏状态
  354. System.out.println("暂停/开始");
  355. repaint();//重绘
  356. }
  357. }
  358. //任意键开始
  359. if(!start && key != KeyEvent.VK_SPACE) {//如果当前状态为暂停状态,且键盘输入不是空格
  360. start = true;
  361. repaint();//重绘
  362. }
  363. }
  364. });
  365. }
  366. /**
  367. * 初始化游戏基本信息
  368. */
  369. private void init() {
  370. start = false;
  371. exist = true;
  372. direction2 = "U";
  373. flag = true;
  374. localList = new ArrayList<int[]>();
  375. localList.add(0,new int[] {75,125});//蛇头
  376. localList.add(1,new int[] {75,150});//蛇身1
  377. localList.add(2,new int[] {75,175});//蛇身2
  378. //创建第一个食物的位置
  379. //通过循环保证当前生成的食物不在身体所在的坐标上
  380. boolean isProduce = true;
  381. while(isProduce) {//循环生成食物坐标
  382. isProduce = false;//结束本次循环
  383. x = rand.nextInt(33) * 25 + 25;
  384. y = rand.nextInt(23) * 25 + 75;
  385. for (int[] arr:localList) {//循环遍历蛇头及蛇身的坐标
  386. if(x == arr[0] && y == arr[1]) {//如果食物坐标和蛇的某一节坐标重合
  387. isProduce = true;//跳转循环状态,继续下一次食物生成
  388. break;
  389. }
  390. }
  391. //蛇身遍历完成,没有重合坐标,结束食物坐标生成
  392. }
  393. time = new Timer(speed, this);
  394. setLayout(null);
  395. score = 0;
  396. num = 0;
  397. foodType = 0;
  398. // repaint();
  399. }
  400. }

  三、构造启动类

 

四、游戏测试 

设置贪吃蛇运行速度 

 

 

游戏界面 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/699514
推荐阅读
相关标签
  

闽ICP备14008679号