您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息
免费发信息
三六零分类信息网 > 金华分类信息网,免费分类信息发布

java实现贪吃蛇的代码实例

2024/6/26 5:28:44发布94次查看
用几天的空闲时间写个贪吃蛇。
下面的代码都打了注释,如果有什么问题或者有什么指点的地方希望留言不吝赐教!
下载地址(需要1积分,如果不想用积分,直接拷贝下面的代码即可)
board类:
import java.awt.eventqueue;import java.awt.keyeventpostprocessor;import javax.swing.*;import java.awt.*;import java.awt.event.keyevent;/** * * @author quinnnorris * * */public class board { /** * @param args */ public static void main(string[] args) { // todo auto-generated method stub // 开启一个线程,所有的swing组件必须由事件分派线程进行配置,线程将鼠标点击和按键控制转移到用户接口组件。 eventqueue.invokelater(new runnable() { // 匿名内部类,是一个runnable接口的实例,实现了run方法 public void run() { jframe frame = new boardframe(); // 创建下面自己定义的simpleframe类对象,以便于调用构造器方法 frame.settitle("retro snake"); // 设置标题 frame.setdefaultcloseoperation(jframe.exit_on_close); // 选择当用户关闭框架的时候进行的操作 ,在有些时候需要将窗口隐藏,不能直接退出需要用到这个方法 frame.setvisible(true); // 将窗口可见化,这样以便用户在第一次看见窗口之前我们能够向其中添加内容 } }); } } class boardframe extends jframe { private snake snk; // 在我们绘图的工作区域创建一个蛇对象引用 public static final int interval = configure.interval; // 需要用到的睡眠间隔,决定了蛇的移动速度 // 从configure文件中读取的游戏时间间隔 public boardframe() { snk = new snake(); snk.setfood(new food().getsnake(snk.getsnakebody())); // 创建一个食物对象,调用getsnake方法判断该食物生成点不在蛇的身体上 // getsnake的返回类型是food,可以这样直接调用 final keyboardfocusmanager manager = keyboardfocusmanager .getcurrentkeyboardfocusmanager(); // 创建一个键盘监听相关类 // 因为我们要在下面开启线程,线程中只能获得final修饰的局部变量,所以这个变量是不可变的 new thread(new runnable() { // 开启线程来不断重绘蛇 // 之所以采用多线程,是为了让代码更加灵活,如果要改编成双人贪吃蛇更方便 public void run() { while (true) { boardcomponent bc = new boardcomponent(); bc.setsnake(snk); add(bc); // 创建jcomponent的实例,将上面创建的蛇对象传入 mykeyeventpostprocessor mke = new mykeyeventpostprocessor(); mke.setsnk(snk); manager.addkeyeventpostprocessor(mke); // 创建监听键盘的实例,同样将蛇对象传入 try { thread.sleep(interval); // 在运动之间需要间隔,用sleep方法达到停顿的效果 } catch (interruptedexception e) { e.printstacktrace(); } snk.snakemove(); // 调用移动方法 pack(); // 绘制默认大小的窗口 } } }).start(); } } class mykeyeventpostprocessor implements keyeventpostprocessor { private snake snk; public boolean postprocesskeyevent(keyevent e) { direction dir = null; // 创建一个direction枚举类引用 switch (e.getkeycode()) { case keyevent.vk_up: dir = direction.up; break; case keyevent.vk_down: dir = direction.down; break; case keyevent.vk_left: dir = direction.left; break; case keyevent.vk_right: dir = direction.right; break; } // 根据不同的方向键,将获取的值存放在dir中 if (dir != null) snk.setmovedir(dir); // 如果获取到的值是上下左右四个方向键中一个,那么将dir存放到snake类的movedir变量中 return true; } public void setsnk(snake snk) { this.snk = snk; } } class boardcomponent extends jcomponent { public static final int width = configure.width; public static final int height = configure.heigth; public static final int tilewidth = configure.tile_width; public static final int tileheight = configure.tile_height; public static final int row = configure.row; public static final int column = configure.col; private static final int xoffset = (width - column * tilewidth) / 2; private static final int yoffset = (height - row * tileheight) / 2; // 从configure文件中读取的游戏数据 private snake snk; public void setsnake(snake snk) { this.snk = snk; } /** * 我们覆盖了这个以用来打印 * * @param g */ public void paintcomponent(graphics g) { drawdecoration(g); drawfill(g); } /** * 绘制实心的蛇身体以及食物 * * @param g */ public void drawfill(graphics g) { g.setcolor(color.green); for (snakepos sp : snk.getsnakebody()) g.fillrect(sp.col * tilewidth + xoffset, sp.row * tileheight + yoffset, tilewidth, tileheight); // 遍历蛇的身体,将每一块蛇都上色 food fd = snk.getfood(); g.setcolor(color.blue); // 将当前的食物上色 g.fillrect(fd.col * tilewidth + xoffset, fd.row * tileheight + yoffset, tilewidth, tileheight); } /** * 绘制游戏的边界红色框 * * @param g */ public void drawdecoration(graphics g) { g.setcolor(color.red); g.drawrect(xoffset, yoffset, column * tilewidth, row * tileheight); } /** * 我们覆盖了这个方法来表示出这个类的组件的大小 * * @return 返回这个类的组件本身应该有多大 */ public dimension getpreferredsize() { return new dimension(width, height); // 返回一个dimension对象,表示这个组件的大小 } }
snake类:
import java.util.linkedlist;/** * * @author quinnnorris * * 蛇的实现类 */public class snake { private direction snakedir; // 当前蛇头所向的方向 private direction movedir; // movedir是从board类中读取到的方向 // movedir是在run方法的一个周期中,通过键盘读取的,蛇头想要改变的方向 // 这段的逻辑是:我们先从board的键盘监听处读取玩家想要改变的蛇的方向,但是我们不直接把蛇的方向设置成获取的方向 // 因为如果玩家在run方法的一个周期中多次按下不同的方向键,可能会导致一些bug,我们先记录“玩家想要改变成”的方向 // 然后在移动的时候,获取这个想要改变的方向(movedir)与现在的方向(snakedir)进行判断后再处理。 private food food; // 当前蛇在游戏中的食物,会随着蛇吃下一个食物进行刷新 private linkedlist<snakepos> snakebody; // 蛇的身体,由一个个snakepos单元构成 // 数据结构是链表,因为随机访问次数少,插入删除次数多 public static final int row = configure.row; public static final int column = configure.col; // 从configure文件中读取的游戏行列 public snake() { snakebody = new linkedlist<snakepos>(); reset(); // 初始化蛇 } public direction getsnakedir() { return snakedir; } public void setsnakedir(direction snakedir) { this.snakedir = snakedir; } public linkedlist<snakepos> getsnakebody() { return snakebody; } public food getfood() { return food; } public void setfood(food food) { this.food = food; } public void setmovedir(direction dir) { this.movedir = dir; } /** * 此方法用来初始化蛇,让蛇变成一条竖直3格长度,方向向上的随机位置新蛇 */ public void reset() { snakebody.clear(); // 清空链表 snakepos beginpos = null; // 创建一格蛇头的引用 setmovedir(null); // 将键盘监听的方向设置为null do { beginpos = this.randompos(); // 调用方法随机放置蛇头位置 } while (beginpos.row + 3 > row); // 如果蛇头向下三行没接触到底边,这个生成是可以被接受的 snakebody.add(beginpos); snakebody.add(new snakepos(beginpos.row + 1, beginpos.col)); snakebody.add(new snakepos(beginpos.row + 2, beginpos.col)); // 将三格蛇(包括蛇头)添加到snakebody链表中 setsnakedir(direction.up); // 设置方向为向上 } /** * 创建一个蛇身体(snakepos类)对象并随机设置行列,将其返回 * * @return 行列被随机的一个蛇身体对象 */ private snakepos randompos() { int randomrow = (int) (math.random() * row); int randomcol = (int) (math.random() * column); return new snakepos(randomrow, randomcol); } /** * 控制蛇的移动 */ public void snakemove() { int addrow = snakebody.getfirst().row; int addcol = snakebody.getfirst().col; // 想要添加的新蛇头必定是原蛇头相邻某个方向的一块 // 先将新蛇头的行列设置为原蛇头的行列 direction up = direction.up; direction down = direction.down; direction left = direction.left; direction right = direction.right; // 创建direction枚举类的四个引用,为了少写几个字(嘿嘿) if ((movedir != null) && !((snakedir == up && movedir == down) || (snakedir == down && movedir == up) || (snakedir == left && movedir == right) || (snakedir == right && movedir == left))) snakedir = movedir; // 如果符合条件,就将键盘监听的movedir方向设置为最新的蛇头方向 switch (snakedir) { case up: addrow--; break; case down: addrow++; break; case left: addcol--; break; case right: addcol++; break; } // 根据最新蛇头方向,确定新的蛇头在哪个块生成,修改新蛇头的行列坐标 snakepos addpos = new snakepos(addrow, addcol); // 根据这个行列坐标,创建一个蛇身体(snakepos)对象 if (!isfood(addpos)) snakebody.removelast(); // 如果不是食物,则去掉snakebody链表中最后一个节点 else setfood(new food().getsnake(snakebody)); // 是食物就重新设置一个食物,不用去掉最后一个节点 if (iscollision(addpos)) reset(); // 如果碰撞了,把这条蛇重置 else snakebody.addfirst(addpos); // 没碰撞就将刚才设置的新蛇头放进链表中 // 注意,即使是食物也会执行这一句话,因为遇到食物不算是碰撞 } /** * 判断一个格是不是食物 * * @param addpos * 要判断的格子 * @return 返回true表示是食物 */ private boolean isfood(snakepos addpos) { if (food.row == addpos.row && food.col == addpos.col) return true; // 如果传入的行列坐标和这个类中的food变量的行列一样就表示是食物 return false; } /** * 碰撞检测,如果遇到墙壁或者蛇身体就认为碰撞 * * @param addpos * 要判断是否为墙壁(或蛇身体)的格子 * @return 会发生碰撞返回true */ private boolean iscollision(snakepos addpos) { if (addpos.row < 0 || addpos.row > row - 1 || addpos.col < 0 || addpos.col > column - 1) return true; // 如果是墙壁返回true for (snakepos sp : snakebody) if ((sp.row == addpos.row) && (sp.col == addpos.col)) return true; // 如果是蛇身体返回true return false; } }
snakepos类:
/** * * @author quinnnorris * * 格子类 (或者可以理解成表示蛇的一块身体的类) */public class snakepos { public int col; public int row; // 一块蛇身体的位置坐标 // 设置为public方便调用 /** * 行列构造器,表示这一块身体在游戏盘中所处的行列 * * @param row * 所在的行 * @param col * 所在的列 */ snakepos(int row, int col) { this.col = col; this.row = row; } /** * 留下一个无参的构造器,不是为了调用,而是为了为food类做方便 */ snakepos() { col = 0; row = 0; } }
food类:
import java.util.linkedlist;/** * * @author quinnnorris * * 食物类 */public class food extends snakepos { public int row; public int col; // 表示食物所在的行列 public static final int row = configure.row; public static final int column = configure.col; // 从configure文件中读取的游戏行列 food() { randompos(); // 随机设置这个对象的行列变量 } /** * 获取蛇的snakebody链表,让食物与蛇身不重叠 * * @param snakebody * 表示蛇身体的链表 * @return 返回这个类实例化的对象本身 */ public food getsnake(linkedlist<snakepos> snakebody) { while (checksame(snakebody)) randompos(); // 如果发现食物的位置和蛇身体重叠,则重新随机食物的位置 return this; // 返回这个对象本身,为创建实例时带来方便 } /** * 检查蛇身体链表中是否有一块与当前食物坐标相同 * * @param snakebody * 表示蛇身体的链表 * @return 如果有重复返回true */ private boolean checksame(linkedlist<snakepos> snakebody) { for (snakepos sp : snakebody) if (sp.row == this.row && sp.col == this.col) return true; // 循环遍历是否有重复 return false; } /** * 随机该对象的行和列变量 */ private void randompos() { this.row = (int) (math.random() * row); this.col = (int) (math.random() * column); } }
configure类:
/** * * @author quinnnorris * * configuration information */public class configure { public static final int width = 400; public static final int heigth = 300; // height and width of window. public static final int tile_width = 16; public static final int tile_height = 16; // the height and width of each snakepos. public static final int row = 15; public static final int col = 20; // the number of rows and columns of the game. public static final int interval = 300; // snake moving time interval.}
direction类:
/** * * @author quinnnorris * */public enum direction { up, down, left, right; // 上下左右四个方向}
以上就是java实现贪吃蛇的代码实例的详细内容。
金华分类信息网,免费分类信息发布

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录