1、摘要 2、 代码 特别注意:调用repaint()这个回调函数的时候,paint(Graphics g)就被调用了。方法在线程里控制,一般都要不断刷屏来显示画面,我们不用理会。 3、运行图片: 4、icon素材: 5、寄语:
特别感谢上面链接的作者,让我快速理清思路。
我将该作者的代码做了不少改动,转化为我自己的思考。
我的工作如下:
1)设置游戏的等级,让贪吃蛇的运行速度随着等级的变化而改变。
2) 设置了路障,和装饰的草地,以及与贪吃蛇触碰的条件。
3) 设置了三种不同的食物,并考虑了食物和路障的摆放。
4)修复了该作者的bug,包括页面的框架,贪吃蛇移动/死亡的条件等。
5)做了不少UI的调整,包括JPanel背景色、食物、蛇的身体、提示字的位置等。
这份代码只是起到抛转引玉的作用,方便我们了解一个简单的小游戏是如何开发的(感兴趣的朋友可以在web上尝试贪吃蛇游戏)
首先需要根据你们的eclipse版本下载相应版本的WindowBuilder,然后新建一个JPanel部署程序;
值得注意的是,我在工程中新建(或者直接复制粘贴)了一个/pic文件夹,用来存放icon,请大家在学习的时候务必注意图片路径:
package Jpanel; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Random; import javax.swing.Timer; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JPanel; /* * Part1: * 设计游戏图纸:画一张900*700的白色窗口 * 在窗口上添加画布,并在画布上添加标题和游戏区域 * 第一个问题:蛇的图片如何和画布适应,如何让图片移动 * Part2: 初始化放置静态的蛇:一个头、一个身体、一个尾巴 加上开始提示:按空格键开始游戏 让蛇动起来:监听Timer事件,平移数据(蛇的身体) 实现游戏暂停 实现转向功能(需要蛇头部图片的四个方向) Part3: 添加食物 吃掉食物 添加死亡条件 实现“重新开始”功能 添加分数、长度和等级(有兴趣的朋友可以增加游戏时间的选项) */ public class SnakePanel extends JPanel implements KeyListener, ActionListener { //初始化图片 ImageIcon up = new ImageIcon("pic/_up.png"); ImageIcon down = new ImageIcon("pic/_down.png"); ImageIcon left = new ImageIcon("pic/_left.png"); ImageIcon right = new ImageIcon("pic/_right.png"); ImageIcon food = new ImageIcon("pic/strawberry.png"); ImageIcon food1 = new ImageIcon("pic/apple.png"); ImageIcon food2 = new ImageIcon("pic/orange.png"); ImageIcon body = new ImageIcon("pic/_body.png"); ImageIcon stone = new ImageIcon("pic/stone.png"); ImageIcon grass = new ImageIcon("pic/grass.png"); ImageIcon tail = new ImageIcon("pic/_tail.png"); ImageIcon title = new ImageIcon("pic/title.jpg"); int[] snakex = new int[751]; int[] snakey = new int[651]; int[] stonex = new int[31]; int[] stoney = new int[31]; int[] grassx = new int[11]; int[] grassy = new int[11]; Random rand = new Random(); int foodx = rand.nextInt(34) * 25 + 25; int foody = rand.nextInt(24) * 25 + 75; int len = 3;// 一开始只有三节,一个头,一个身体、一个尾巴 int score = 0;//初始化分数 int level = 1; static int time = 500;//初始化延迟的时间 int n = 0;// 控制石头 String direction = "R";//初始化方向 boolean isStarted = false;// 判断游戏是否开始 boolean isFailed = false;// 判断游戏是否结束 Timer timer = new Timer(time, this);// 控制游戏的快慢 public SnakePanel() { this.setFocusable(true);// 获取焦点 /* 所谓焦点就是被选中的意思,或者说是“当前正在操作的组件”的意思。 * 如果一个组件被选中,或者正在被操作者,就是得到了焦点,而相反的,一个组件没有被选中或者失去操作,就是被转移了焦点,焦点已经到 别的组件上去了。 * 最明显的两个例子: 一个按钮(button)一旦被选中,就会有一个虚线框在按钮中,并且环绕着按钮的文字,一旦失去焦点,不被操作了,这个虚线框就消失了。 * 一个文本框(textfield)一旦被选中,就会有一个“|”在文本框里面闪动,提示可以输入信息,一旦失去或者转移焦点了,这个“|”就没有了,不闪动, * 表示这个文本框你没有在操作。*/ this.addKeyListener(this);// 监听键盘事件 //下面都是初始化操作 setup(); StoneInitial(); GrassInitial(); } public void GrassInitial() { Random rand = new Random(); for(int i=0;i<11;i++) { grassx[i] = rand.nextInt(34) * 25 + 25; grassy[i] = rand.nextInt(24) * 25 + 75; } } public void GrassPaint(Graphics g) { for (int i = 0; i < 11; i++) { grass.paintIcon(this, g, grassx[i], grassy[i]); } } public void StoneInitial() { Random rand = new Random(); for (int i = 0; i < 31; i++) { stonex[i] = rand.nextInt(34) * 25 + 25; stoney[i] = rand.nextInt(24) * 25 + 75; while ((stonex[i] == 100 && stoney[i] == 100) || (stonex[i] == 75 && stoney[i] == 100) || (stonex[i] == 50 && stoney[i] == 100)) {//防止与初始化的蛇的身体碰撞,并以此为基准放置石头 stonex[i] = rand.nextInt(34) * 25 + 25; stoney[i] = rand.nextInt(24) * 25 + 75; i = 0; } } } public void StonePaint(Graphics g) { for (int i = 0; i < 31; i++) { stone.paintIcon(this, g, stonex[i], stoney[i]); } } public void Level() {//设置游戏的等级 if (score > 5 && score <= 10 && level == 1) { timer.stop();//timer其实也调用了线程,我们首先要暂定之前的线程再开启新的 time -= 40; level++; timer = new Timer(time, this); } else if (score > 10 && score <= 20 && level == 2) { timer.stop(); time -= 40; level++; timer = new Timer(time, this); } else if (score > 20 && score <= 30 && level == 3) { timer.stop(); time -= 50; level++; timer = new Timer(time, this); } else if (score > 30 && score <= 40 && level == 4) { timer.stop(); time -= 50; level++; timer = new Timer(time, this); } else if (score > 40 && score <= 50 && level == 5) { timer.stop(); time -= 60; level++; timer = new Timer(time, this); } else if (score > 50 && score <= 60 && level == 6) { timer.stop(); time -= 60; level++; timer = new Timer(time, this); } } public void food() {// 要改进 Random rand = new Random(); for (int i = 0; i < len; i++) { if ((snakex[i] == foodx && snakey[i] == foody)) { foodx = rand.nextInt(34) * 25 + 25;// 返回一个大于等于0小于34的随机整数 foody = rand.nextInt(24) * 25 + 75; i = 0; continue;//从头开始 } for (int j = 0; j < 31; j++) { if ((stonex[j] == foodx && stoney[j] == foody)||Dilemma()) { foodx = rand.nextInt(34) * 25 + 25; foody = rand.nextInt(24) * 25 + 75; j = 0; i = 0; break; } } } } public boolean Dilemma() {//食物的放置可能出现困境 for(int i=0;i<29;i++) {//以下是全排列 for(int j=i+1;j<30;j++) { for(int k=j+1;k<31;k++) { if ((stonex[i]+25 == foodx && stonex[j]-25 == foodx && stoney[k]-25==foody)|| (stonex[i]+25 == foodx && stonex[j]-25 == foodx && stoney[k]+25==foody)) { return true; } } } } return false; } public void setup() {// 游戏初始化 isStarted = false; isFailed = false; len = 3; score = 0; level=1; n=0; time=500; direction = "R"; snakex[0] = 100; snakex[1] = 75; snakex[2] = 50; snakey[0] = 100; snakey[1] = 100; snakey[2] = 100; GrassInitial();//草和石头放置的初始化 StoneInitial(); timer.start(); } @Override public void keyPressed(KeyEvent e) {//控制键盘的上下左右 int KeyCode = e.getKeyCode(); if (isStarted) { if (KeyCode == KeyEvent.VK_SPACE) { if (isFailed) { setup(); } else { isStarted = !isStarted;// 暂停和开始 } } else if (KeyCode == KeyEvent.VK_UP && direction != "D") { direction = "U"; } else if (KeyCode == KeyEvent.VK_DOWN && direction != "U") { direction = "D"; } else if (KeyCode == KeyEvent.VK_RIGHT && direction != "L") { direction = "R"; } else if (KeyCode == KeyEvent.VK_LEFT && direction != "R") { direction = "L"; } } else { if (KeyCode == KeyEvent.VK_SPACE) { if (isFailed) { setup(); } else { isStarted = !isStarted;// 暂停和开始 } } } } public void paint(Graphics g) {// Graphics 画笔 g.setColor(Color.orange); // 设置画布背景颜色 title.paintIcon(this, g, 25, 11);// 放置主题图片,从(25,11)处为title的左上角,放置图片 g.fillRect(25, 75, 850, 600); // 用画笔设置游戏方框 //画草 GrassPaint(g); // 画石头 StonePaint(g); // 画蛇头(注意判断蛇头的方向) if (direction.equals("R")) right.paintIcon(this, g, snakex[0], snakey[0]); else if (direction.equals("L")) left.paintIcon(this, g, snakex[0], snakey[0]); else if (direction.equals("U")) up.paintIcon(this, g, snakex[0], snakey[0]); else if (direction.equals("D")) down.paintIcon(this, g, snakex[0], snakey[0]); // 画蛇的身体 for (int i = 1; i < len-1; i++) body.paintIcon(this, g, snakex[i], snakey[i]); //画蛇尾 tail.paintIcon(this, g, snakex[len-1],snakey[len-1]); // 判断如果游戏没开始,需要显示的字段 if (!isStarted) { g.setColor(Color.WHITE); g.setFont(new Font("arial", Font.BOLD, 28)); g.drawString("Press Space to start / pause", 250, 320); } // 判断如果游戏失败,需要显示的字段 if (isFailed) { timer.stop(); g.setColor(Color.WHITE); g.setFont(new Font("arial", Font.BOLD, 28)); g.drawString("Game Over ! Press space to restart", 250, 320); } // 显示食物 food(); if(foodx % 3 == 0) food.paintIcon(this, g, foodx, foody); else if((foodx+1) % 3==0) food1.paintIcon(this, g, foodx, foody); else food2.paintIcon(this, g, foodx, foody); // 设置分数和蛇的长度,以及等级,我最高设置了等级七 g.setColor(Color.WHITE); g.setFont(new Font("arial", Font.PLAIN, 15)); g.drawString("Score : " + score, 650, 37); g.drawString("SnakeLength :" + len, 650, 57); g.drawString("Level :" + level, 725, 37); } @Override public void actionPerformed(ActionEvent e) { // 1.再定义一个闹钟 Level(); timer.start(); // 2.移动 if (isStarted && !isFailed) { // 移动身体 for (int i = len; i > 0; i--) { snakex[i] = snakex[i - 1]; snakey[i] = snakey[i - 1]; } // 移动头 if (direction.equals("R")) { snakex[0] = snakex[0] + 25; if (snakex[0] > 850) snakex[0] = 25; } else if (direction.equals("L")) { snakex[0] = snakex[0] - 25; if (snakex[0] < 25) snakex[0] = 850; } else if (direction.equals("U")) { snakey[0] = snakey[0] - 25; if (snakey[0] < 75) snakey[0] = 650; } else if (direction.equals("D")) { snakey[0] = snakey[0] + 25; if (snakey[0] > 650) // 底下应该是650 snakey[0] = 75; } if (snakex[0] == foodx && snakey[0] == foody) { len++; score++; foodx = rand.nextInt(34) * 25 + 25; foody = rand.nextInt(24) * 25 + 75; } for (int i = 1; i < len; i++) { if (snakex[0] == snakex[i] && snakey[0] == snakey[i]) { isFailed = true; } } for (int i = 0; i < len; i++) { for (int j = 1; j < 31; j++) { if (stonex[j] == snakex[i] && stoney[j] == snakey[i]) { isFailed = true; } } } } // 3. repaint() repaint(); } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub } public static void main(String[] args) { JFrame frame = new JFrame(); // 创建一个游戏界面的框架 frame.setBounds(0, 0, 900, 720); // 设置框架的大小 java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();//下面的代码是让框架在屏幕正中间 Dimension screenSize = toolkit.getScreenSize(); double screenWidth = screenSize.getWidth(); double screenHeight = screenSize.getHeight(); frame.setLocation((int) (screenWidth - frame.getWidth()) / 2, (int) (screenHeight - frame.getHeight()) / 2); frame.setResizable(false); // 设置框架大小为不能改变 // 点击关闭按钮 关闭游戏界面 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); SnakePanel panel = new SnakePanel(); // 添加画布 frame.add(panel); // 刚添加时画布是空的看不到 frame.setVisible(true); // 允许显示游戏界面 } }
链接:[百度网盘图片下载地址] https://pan.baidu.com/s/1UlfcIzKBysqUv4cG89VHfg 提取码:bl42
希望大家共同进步,如有不足,希望可以指正!转载请注明出处,谢谢!!!
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算