小小贪吃蛇——JAVA
来源:互联网 发布:西宁网络电视台 编辑:程序博客网 时间:2024/06/06 19:35
回顾了一下JavaSE基础,顺便用一下午的时间写了一个小小贪吃蛇
本篇文章献给Java初学者,或者大一大二的学生朋友们。
因为当时大一下学期学习Java基础后,期末要求做一个小项目,都是一些小游戏,比如俄罗斯方块,贪吃蛇什么的。当时博主太菜了,累死累活整了4天,才弄一个半成品,而且学习效果也不咋地。。到时到处找资源,看教学视频都看不懂,。。
不过博主经过不懈的努力,终于从一个菜鸟变成了 小白(笑哭)。
希望本篇文章可以对你有帮助。每行代码几乎都有注释,我就不再多做解释了,文章末尾我会奉上源码,和马士兵的贪吃蛇教程,还有直接可以运行的程序(个人感觉他的小蛇部分做的有些复杂,我的比他的简单一些,功能也差不多)
博主这次做的算是1.0的版本吧!
界面一般,功能一般,如果你有兴趣,可以继续完善,做出 属于你自己的小蛇吧!
我的贪吃蛇除了具备一般小蛇的特性以外,有以下特性: 1、左右可穿墙(上下的墙碰到就死) 2、速度随着吃的蛋蛋的数目加快,就是吃的越多,速度越快(分数也是)咱们自己做的游戏,规则咱们可以随便定。
附上几个图片,真图为证:
可以穿墙的呦!
GAME OVER:
首先是院子,也就是地图。
废话不多说,附上代码(引入的包太占位置了,我给去了):
public class Yard extends JFrame{ //定义院子的大小 public static final int ROWS = 40; //行数 public static final int COLS = 50; //列数 public static final int BLOCK_SIZE = 20; //每个小格子的尺寸 private static int score = 0; //分数 private static int count = 0; //吃蛋蛋的次数 private static int speed = 10; //速度 Snake snake = new Snake(this); //初始化一条小蛇 Egg egg = new Egg(); //初始化一个蛋蛋 public static void main(String[] args){ new Yard().launch(); //启动游戏 } Image offScreenImage = null; //解决闪烁 @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 launch(){ this.setLocation(500, 200); //设置窗口初始位置 this.setSize(COLS*BLOCK_SIZE,ROWS*BLOCK_SIZE); //设置窗口大小 this.addWindowListener(new WindowAdapter(){ //当关闭窗口时,同时关闭java正在运行的虚拟机 @Override public void windowClosing(WindowEvent e) { System.exit(0); //关闭虚拟机 } }); this.setVisible(true); //让窗口可显示 new Thread(new PaintThread()).start(); //开启线程,让小蛇动起来 this.addKeyListener(new KeyMonitor()); //加入监听器 } //画板 @Override public void paint(Graphics g) { // TODO Auto-generated method stub Color c = g.getColor(); //获取画板color,用于设置颜色 g.setColor(c.gray); //设置当前颜色为灰色 g.fillRect(0, 0, COLS*BLOCK_SIZE, ROWS*BLOCK_SIZE); //把颜色填充到整个窗口 for (int i = 1; i < COLS-1; i++) { g.setColor(c.white); //设置当前颜色为白色 g.fill3DRect(i*BLOCK_SIZE,2*BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE,true); //上边的墙 g.fill3DRect(i*BLOCK_SIZE,(ROWS-2)*BLOCK_SIZE,BLOCK_SIZE,BLOCK_SIZE,true); //上边的墙 } g.setColor(c.darkGray); //画横线 for (int i = 1; i < ROWS; i++) { g.drawLine(BLOCK_SIZE, i*BLOCK_SIZE, (COLS-1)*BLOCK_SIZE, i*BLOCK_SIZE); } //画竖线 for (int i = 1; i < COLS; i++) { g.drawLine(i * BLOCK_SIZE, BLOCK_SIZE*2, i * BLOCK_SIZE, (ROWS-1) * BLOCK_SIZE); } g.setColor(c.yellow); g.setFont(new Font("宋体",Font.BOLD,25)); //设置上下文字体 g.drawString("score:"+score, 20, 80); //用于显示score分数 g.drawString("speed:"+speed, 20, 110); //用于显示speed速度 snake.paint(g); //在这个画板中画一条小蛇 if(snake.eat(egg)){ //如果小蛇吃到了蛋蛋 count++; //吃蛋蛋的次数+1, score += 10*count;//加分,吃的越多,分加的越高 speed += 5; //速度增加 } egg.draw(g); //画一个蛋蛋 if(snake.isGameOver()){ //如果GAME OVER了,在中间显示一个GANE OVER g.setColor(c.yellow); g.setFont(new Font("宋体",Font.BOLD,80)); g.drawString("GAME OVER!", 300, 400); } } //线程内部类,本线程用于整个游戏的运行 private class PaintThread implements Runnable{ @Override public void run() { // TODO Auto-generated method stub while(!snake.isGameOver()){ repaint(); //刷新页面 try { snake.move(); //蛇移动 Thread.sleep(300/speed*10); //这里控制蛇移动的速度 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } repaint(); //游戏结束后刷新一下页面,用于显示GAME OVER } } //监听器 private class KeyMonitor extends KeyAdapter{ //监听键盘的指令 @Override public void keyPressed(KeyEvent e) { snake.keyPressed(e); } }}
接着是小蛇:
public class Snake { //一下分别是四个方向的状态码,用来标识方向 public static final int DIR_UP = 1; //向上走 public static final int DIR_DOWN = 2; //向下走 public static final int DIR_LEFT = 3; //向左走 public static final int DIR_RIGHT = 4; //像右走 //默认的DIR为4,即往右走 public static int DIR = 4; //size标识每个小格子的大小 int size = Yard.BLOCK_SIZE; private Yard yard; //用来绑定对应的院子 LinkedList<Point> snake = new LinkedList<Point>(); //用链表来存储蛇身子,方便加头去尾 public Snake(Yard yard){//用来绑定对应的院子 initSnake(); //初始化小蛇 this.yard = yard; //绑定院子 } //初始化蛇 public void initSnake(){ //先来三个节点,作为初始的身子 snake.addFirst(new Point(Yard.BLOCK_SIZE*(Yard.COLS-2)/2,Yard.BLOCK_SIZE*Yard.ROWS/2)); snake.addFirst(new Point(Yard.BLOCK_SIZE*(Yard.COLS)/2,Yard.BLOCK_SIZE*Yard.ROWS/2)); snake.addFirst(new Point(Yard.BLOCK_SIZE*(Yard.COLS+2)/2,Yard.BLOCK_SIZE*Yard.ROWS/2)); } //创建蛇的头,方便使用 Point head = new Point(); //画蛇 public void paint(Graphics g){ Color c = g.getColor(); g.setColor(c.darkGray); head = this.snake.getFirst(); //单独做了一个蛇头,用圆角矩形表示 g.fillRoundRect(head.x, head.y, Yard.BLOCK_SIZE, Yard.BLOCK_SIZE,10,10); g.setColor(c.black); //遍历链表,来画出整条小蛇 for (int i = 1; i < snake.size(); i++) { //蛇身子用普通的矩形表示 g.fillRect(snake.get(i).x, snake.get(i).y, Yard.BLOCK_SIZE, Yard.BLOCK_SIZE); } } //蛇移动 //移动的原理就加头去尾 //用链表可以很轻松的实现,他封装了一些的方法,使用起来很方便,可以查一下api文档 //在这里,如果到左右边界了,可以穿过去,实现穿墙操作 public void move(){ head = this.snake.getFirst(); //获取当前的头节点 switch (DIR) { //根据不同的方向,对应不同的移动方案 case DIR_UP: this.snake.addFirst(new Point(head.x,head.y-size)); //添加一个头节点 this.snake.removeLast(); //去尾操作,去掉尾巴节点 break; case DIR_DOWN: this.snake.addFirst(new Point(head.x,head.y+size)); this.snake.removeLast(); break; case DIR_LEFT: if(head.x == size){ //到了左边的边界 this.snake.addFirst(new Point((yard.COLS-2)*size,head.y)); //穿墙 }else{ this.snake.addFirst(new Point(head.x-size,head.y)); } this.snake.removeLast(); break; case DIR_RIGHT: if(head.x == (yard.COLS-2)*size){ //到了右边边界 this.snake.addFirst(new Point(size,head.y)); //穿墙 }else{ this.snake.addFirst(new Point(head.x+size,head.y)); } this.snake.removeLast(); break; default: break; } } //判断是否撞墙或者咬到自己,游戏结束 public boolean isGameOver(){ head = this.snake.getFirst(); //撞墙(上下的墙)(左右的墙可以穿过去) if( head.y <= 2*size || head.y >= (yard.ROWS-2)*size){ return true; } //咬到自己 for (int i = 1; i < this.snake.size(); i++) { if(head.x == this.snake.get(i).x && head.y == this.snake.get(i).y){ return true; } } return false; } //监听键盘,用来改变方向 public void keyPressed(KeyEvent e) { switch (e.getKeyCode()){ //获取键的对应的码 case KeyEvent.VK_UP: //向上的键,下面的同理 if(DIR != DIR_DOWN){ //这里控制不能直接反方向走 DIR = DIR_UP; } break; case KeyEvent.VK_DOWN: if(DIR != DIR_UP) DIR = DIR_DOWN; break; case KeyEvent.VK_LEFT: if(DIR != DIR_RIGHT) DIR = DIR_LEFT; break; case KeyEvent.VK_RIGHT: if(DIR != DIR_LEFT) DIR = DIR_RIGHT; break; } } //吃蛋蛋 //吃着了就加一个尾巴,就可以实现变长了 public boolean eat(Egg egg){ if(egg.x == this.head.x && egg.y == this.head.y){ egg.createFood(); //重新创建一个蛋蛋 Point last = this.snake.getLast(); //获取当前的尾巴节点 this.snake.addLast(last); //添加一个新的尾巴节点 return true; } return false; }}
最后是要吃的食物(蛋蛋):
package MySnake;import java.awt.Color;import java.awt.Graphics;import java.awt.Point;import java.util.Random;public class Egg { private static Random random = new Random(); //用来随机产生蛋蛋的对象 int size = Yard.BLOCK_SIZE; //每个小格子的大小 //食物的坐标 public int x; public int y; public Egg(){ //构造方法,产生一个蛋蛋 createFood(); } //创建食物 public void createFood(){ this.x = (random.nextInt(Yard.COLS-3)+2)*size; //因为边框的问题,所以这里有改动,可以试验一下 this.y = (random.nextInt(Yard.ROWS-5)+3)*size; } //画出食物 public void draw(Graphics g){ Color c = g.getColor(); g.setColor(c.red); g.fillOval(x, y, size, size); //画一个圆形来表示蛋蛋 }}
目前这个版本还是1.0,仅供初学者参考,(写太复杂了反而违背了本意)
以上是全部代码。。可能你还是看不懂,没关系,源码给你,慢慢研究:
http://pan.baidu.com/s/1hsjApxU
并附上马士兵的教程以及源码:
http://pan.baidu.com/s/1nvHVWYP
我顺便把程序打包了 ,双击直接运行,下面这个是在有JRE环境的电脑上可以运行:
http://pan.baidu.com/s/1geHmby7
后来考虑到个别小伙伴想在没有jre环境的电脑上运行,于是我花了半下午的时间又打包成真正的桌面应用程序,安装之后,随处都可运行:
http://pan.baidu.com/s/1eRJpTIE
个人感觉马士兵老师讲的这个贪吃蛇的小蛇部分有些复杂繁琐,可以参考我的代码结合着老师的视频,做出属于自己的贪吃蛇吧!!
拯救不开心!!!
- 小小贪吃蛇——JAVA
- 小小的贪吃蛇
- 童年时光,小小贪吃蛇
- 小小项目4:贪吃蛇
- 贪吃蛇的进阶——智能贪吃蛇
- java贪吃蛇-一步一步写贪吃蛇
- LittleGame——贪吃蛇
- 小游戏——贪吃蛇
- 游戏——贪吃蛇
- 贪吃蛇—C语言
- 字符游戏—贪吃蛇
- java贪吃蛇
- 关于java“贪吃蛇”
- java 贪吃蛇1.0
- java贪吃蛇
- 贪吃蛇java代码
- Java贪吃蛇游戏
- java贪吃蛇
- 假设在 n 进制下,下面的等式成立,n 的值是? 567*456=150216
- Dropping tests [二分]
- UML类图符号 各种关系说明以及举例
- ionic2 封装重构http+自定义http拦截器
- eclipse中格式化代码快捷键Ctrl+Shift+F失效的解决办法
- 小小贪吃蛇——JAVA
- 关于一个需求引发的事务操作和锁-记录解决过程和思路
- 1.3 运算符和表达式
- javaseday30(简单客户端 服务端 tomcat)
- [NOIP模拟赛]点染色问题
- 【背包专题】I
- 那些千奇百怪的视频直播延时测试方法,论正确姿势是什么?
- TensorFlow不同交叉熵计算方式
- Arduino与上STM32之I2C