******************贪吃蛇*************** 1 图形界面基础 如何显示和控制窗口,swing API的使用 2 图形界面的绘图技术,用于绘制舞台,蛇和食物 如何进行自定义绘制,swing API 的使用 3 图形界面的事件响应,用于控制蛇的运行方向 如何处理键盘事件,swing API 的使用 (1 2 3 是舞台的功能) 4 蛇的运行算法,是蛇的功能 爬行 创建两个方法: 1,爬行creep() 2,创建新头节点createHead() 吃食物 1,创建新头节点 2,检查是否吃到食物 3,如果吃到食物,就复制数组(扩容,丢弃原数组) 4,向后移动点 5,插入到新节点[0] 碰撞检测(边界,自身碰撞) 5 在舞台上定时驱动蛇的运行 **************单元测试工具**************** 测试要新建个类,在这个新的类中测试 如果是测试主函数中的代码,则要在主函数外建一个test()方法,把主函数中的代码移到test()中,如果是在类中的方法可以直接调用,如果类中没有new的话,则需要在测试这个类中new下. 在项目点击右键选择properties---->左边框内选择Java Build Path选项--->右边选择Libraries--->Add Library--->Junit 4 导入包:import org.junit.Test; 单元测试工具注释 在方法前@Test 在一个测试类中有多个测试,所以会输出多个测试结果,如果只想看一个测试结果,可以在你想看到结果之外的其他测试上//@Test **************爬行********** 创建两个方法: 1,爬行creep() 2,创建新头节点createHead() /** 按照默认方向爬行一步 */ public void creep(){ for(int i=this.cells.length-1; i>=1;i-- ){ cells[i] = cells[i-1]; } cells[0] = createHead(currentDirection); } /** 根据方向,和当前(this)的头节点,创建新的头节点 */ private Cell createHead(int direction){ Cell head = this.cells[0];//临时创建头节点 int x = head.getX(); int y = head.getY(); switch(direction){ case DOWN: y++; break; case UP: y--; break; case RIGHT: x++; break; case LEFT: x--; break; } return new Cell(x,y);//返回新的节点 } 在测试类中调用着两个方法并测试 @Test//爬行测试 creep 爬行 public void creepTest(){ Worm worm = new Worm(); System.out.println(worm); //[[0,0], [1,0], [2,0], [3,0], [4,0], [5,0], //[6,0], [7,0], [8,0], [9,0], [10,0], [11,0]] worm.creep(); System.out.println(worm); //[[0,1], [0,0], [1,0], [2,0], [3,0], [4,0], // [5,0], [6,0], [7,0], [8,0], [9,0], [10,0]] /** 第二次输出的结果与第一次的比较表示蛇的爬行 */ } **************吃食物**************** 爬行的时候检查是否能够吃到food,food是参数 如吃到食物,蛇的长度会增加 1,创建新头节点 2,检查是否吃到食物 3,如果吃到食物,就复制数组(扩容,丢弃原数组) 4,向后移动点 5,插入到新节点[0] public boolean creep(Cell food){ Cell head = createHead(currentDirection); boolean eat = head.getX()==food.getX()//检查是否吃到食物 && head.getY()==food.getY(); if(eat){//如果吃到食物就复制数组 Cell[] ary = Arrays.copyOf(cells, cells.length+1); cells = ary;//丢弃源数组 }//向后移动节点 for(int i=cells.length-1;i>=1;i--){ cells[i] = cells[i-1]; } cells[0] = head;//插入头节点 return eat; } 在测试类中调用方法并测试 @Test public void creepWithFoodTest(){ Worm worm = new Worm(); Cell food = new Cell(0,2); System.out.println(worm); //蛇的默认长度, //[[0,0], [1,0], [2,0], [3,0], [4,0], [5,0], //[6,0], [7,0], [8,0], [9,0], [10,0], [11,0]] System.out.println(worm.creep(food)); //false,表示蛇爬行一步,但没有吃到食物 System.out.println(worm); //蛇爬行后的长度, //[[0,1], [0,0], [1,0], [2,0], [3,0], [4,0], //[5,0], [6,0], [7,0], [8,0], [9,0], [10,0]] System.out.println(worm.creep(food)); //true,表示蛇再次爬行后吃到了食物 System.out.println(worm); //蛇吃到食物后的长度,蛇吃到食物后蛇的长度增加(数组的扩容) //[[0,2], [0,1], [0,0], [1,0], [2,0], [3,0], //[4,0], [5,0], [6,0], [7,0], [8,0], [9,0], [10,0]] } ***********更换方向************ public boolean creep(int direction,Cell food){ if(currentDirection+direction==0){//反向 return false;//如果反向,就不进行任何动作 } this.currentDirection = direction;//换方向 Cell head = createHead(currentDirection); boolean eat = head.getX()==food.getX()//检查是否吃到食物 && head.getY()==food.getY(); if(eat){//如果吃到食物就复制数组 Cell[] ary = Arrays.copyOf(cells, cells.length+1); cells = ary;//丢弃源数组 }//向后移动节点 for(int i=cells.length-1;i>=1;i--){ cells[i] = cells[i-1]; } cells[0] = head; return eat; } 在测试类中调用方法并测试 @Test//更换方向爬行测试 public void creepWithDirFoodTest(){ System.out.println("更换方向爬行测试"); Worm worm = new Worm(); Cell food = new Cell(1,2); System.out.println(worm); //[[0,0], [1,0], [2,0], [3,0], [4,0], //[5,0], [6,0], [7,0], [8,0], [9,0], [10,0], [11,0]] System.out.println(worm.creep(food));//false System.out.println(worm); //[[0,1], [0,0], [1,0], [2,0], [3,0], [4,0], //[5,0], [6,0], [7,0], [8,0], [9,0], [10,0]] System.out.println(worm.creep(food));//flase System.out.println(worm); //[[0,2], [0,1], [0,0], [1,0], [2,0], [3,0], //[4,0], [5,0], [6,0], [7,0], [8,0], [9,0]] System.out.println(worm.creep(Worm.UP,food)); //false,调用方向向上 System.out.println(worm); //反向无动作.蛇的默认方向是向下,而调用的方向向上,与默认方向相反, 所以没有任何动作 //[[0,2], [0,1], [0,0], [1,0], [2,0], [3,0], //[4,0], [5,0], [6,0], [7,0], [8,0], [9,0]] System.out.println(worm.creep(Worm.RIGHT,food)); //true,调用的方向向右,吃到食物 System.out.println(worm);//吃到食物 //[[1,2], [0,2], [0,1], [0,0], [1,0], [2,0], [3,0], //[4,0], [5,0], [6,0], [7,0], [8,0], [9,0]] } **************碰撞检测(边界,自身碰撞)********** 检查在新的运行方向上是否能够碰撞到边界和自己this 0 反向不检查返回false 1 生成下个新头节点位置 2 如果新头节点出界,返回true,表示碰撞边界 3 如果新头节点包含在蛇的前n-1节点范围,表示吃到自己返回true 4 否则返回false public boolean hit(int direction){ if(currentDirection + direction==0){//反向 return false;//如果反向,就不进行任何动作 } Cell head = createHead(direction);//创建新的头节点 //判断新的头节点是否出界 if(head.getX()<0 || head.getX()>=WormStage.COLS || head.getY()<0 ||head.getY()>=WormStage.ROWS){ return true; }//判断新头节点是否包含在自己体内,表示吃到自己 for(int i=0;i<cells.length-1;i++){ if(cells[i].getX()==head.getX() && cells[i].getY()==head.getY()){ return true; } } return false; } 在测试类中调用方法并测试 @Test public void hitTest(){ System.out.println("碰撞方法的检测"); Worm worm = new Worm(); System.out.println(worm); worm.creep(); System.out.println(worm); System.out.println(worm.hit(Worm.LEFT)); //true,因为蛇的默认方向是向下的,调用向左的方向,则会碰撞边界,返回true System.out.println(worm.hit(Worm.RIGHT)); //false,因为蛇的默认方向是向下的,调用向右的方向,则不会碰撞边界,返回false Cell food = new Cell(4,5); worm.creep(Worm.RIGHT,food); //改变默认方向,使蛇的方向由默认的向下改为向右 System.out.println(worm); System.out.println(worm.hit(Worm.UP)); //true,因为蛇的默认方向是向右的,调用向上的方向,则会碰撞边界,返回true System.out.println(worm.hit(Worm.DOWN)); //false,因为蛇的默认方向是向右的,调用向下的方向,则不会碰撞边界,返回false } *************显示和控制窗口*************** 显示窗口需要导入包: import javax.swing.JFrame; 导入包后就可以调用此包中的方法 1.frame.setSize(width,height); 调整组件的大小,使其宽度为 width,高度为 height。 2.frame.setLocation(x,y); 将组件移到新位置。通过此组件父级坐标空间中的 x 和 y 参数来指定新位置的左上角 3.frame.setLocationRelativeTo(null); 则此窗口将置于屏幕的中央。 4.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 设置默认的关闭操作为在关闭时候离开软件,单窗口软件这样设置最简单,多窗口软件另有其他设法 5.frame.setLayout(null) 关闭默认布局管理,避免面板充满窗口 6.frame.setVisible(true) 设置可见的窗口 ************自定义绘制*************** /**重写JPanal绘制方法*/ 先导入包:import java.awt.Graphics; 允许应用程序在组件以及在闭屏图像上进行绘制 public void paint(Graphics g){ //添加自定义绘制 //先绘制背景 g.setColor(Color.darkGray);//把背景涂成深灰色 g.fillRect(0, 0, getWidth(), getHeight());//填充指定矩形 g.setColor(Color.RED); //draw 绘制 Rect矩形,绘制指定矩形的边框 g.drawRect(0, 0, this.getWidth()-1, this.getHeight()-1); //绘制食物 g.setColor(food.getColor()); //fill 填充 3D 3维 Rect矩形 突起的立体按钮形状 g.fill3DRect(food.getX()*CELL_SIZE, food.getY()*CELL_SIZE, CELL_SIZE, CELL_SIZE, true); //绘制蛇 worm.paint(g);//让蛇自己利用画笔绘制//调用worm类中paint()方法 } 在Worm类中的paint()方法,表示为蛇添加绘制方法,也就是利用来自舞台面板的画笔(Graphics)绘制蛇到舞台上 public void paint(Graphics g){ g.setColor(this.color);//设置当前蛇的颜色 for(int i= 0;i<cells.length;i++){ Cell cell = cells[i];//临时创建一个格子 //绘制一个填充当前颜色的矩形 g.fill3DRect(cell.getX()*WormStage.CELL_SIZE, cell.getY()*WormStage.CELL_SIZE, WormStage.CELL_SIZE, WormStage.CELL_SIZE, true); } } ***********在舞台上定时驱动蛇的运行************ 启动定时器驱动蛇的运行 1 检查碰撞是否将要发生 2 如果发生碰撞:创建新的蛇和食物,重写开始 3 如果没有碰撞就爬行,并检查是否能够吃到食物 4 如果吃到食物:重新创建新的食物 5 启动重新绘制界面功能 repaint() 更新界面显示效果! repaint() 方法会尽快调用 paint() 更新界面! private Timer timer; private void go(){ if(timer==null){ timer = new Timer(); timer.schedule(new TimerTask(){ public void run(){ if(worm.hit()){//如果蛇碰到边界或自己 worm = new Worm();//创建新蛇 food = createFood();//创建新食物 }else{//如果没有碰到自己 boolean eat = worm.creep(food); //蛇向前(当前方向)爬行,返回结果表示是否吃到食物 if(eat){//如果吃到食物,就生成新食物 food = createFood(); //不能new一个,要把蛇躲过去 } } repaint(); //不加repaint()会造成只有在拉画框是才会动 } }, 0, 1000/10); } } *********paint方法************ package com.tarena.worm; import java.awt.Color; import java.awt.Graphics; import java.util.Timer; import java.util.TimerTask; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.LineBorder; /** * 如何绘图 */ public class PaintDemo { public static void main(String[] args) { JFrame frame = new JFrame("绘图演示"); frame.setSize(300, 200); frame.setLayout(null);//取消默认布局管理 //窗口中的组件,需要自定义位置和大小 MyPane panel = new MyPane(); panel.setSize(280, 150); panel.setLocation(20, 20);//设置面板的位置 panel.setBorder(new LineBorder(Color.BLACK)); frame.add(panel); frame.setVisible(true); panel.go(); } } class MyPane extends JPanel{ String[] s = {".o0o....","..o0o...","...o0o..", "....o0o.",".....o0o","o.....0o","0o.....o"}; int i = 0; //方法重写:子类修改父类的功能 //paint是swing 默认调用绘制面板的方法 public void paint(Graphics g){ super.paint(g);//调用父类的paint方法,包含绘制边框功能 g.drawString(s[i++%s.length], 20, 20);//自定义绘制 } public void go(){ Timer timer = new Timer(); timer.schedule(new TimerTask(){ public void run(){ repaint();//在JPanel中定义,尽快的启动界面绘制功能, //界面绘制功能会调用paint方法 } }, 0,1000/10); } }
贪吃蛇
原创
©著作权归作者所有:来自51CTO博客作者neal2004的原创作品,请联系作者获取转载授权,否则将追究法律责任
下一篇:我的友情链接
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章
-
贪吃蛇实现
快期末了,来水个项目吧..........
#include 初始化 数组