贪吃蛇系列之五——动起来

      今天这篇文章原本应该早些时候就应该发布出来的了,可是今天孤狼去参加颁奖典礼去了,耽搁了些时间,呵呵,因此就晚了一些。今天领奖,很高兴,仍是说出来跟你们分享一下吧,孤狼参加了移动在学校作的比赛,有幸获了奖:


固然,姓名和奖金我给P掉了,呵呵,仍是值得高兴一下的。这款软件呢是基于Android平台的,软件会在以后公布源代码,而且将这个项目的开发过程也挨着挨着分解开给你们探讨和学习。那么说到这里呢,孤狼仍是简单的说一下个人一个简单的计划吧,由于今天也看到了你们给个人留言,很谢谢你们对个人支持与鼓励。贪吃蛇呢只是做为一个引入,或者说是对于J2SE的一个简单的整合,这个游戏自己不是重点。在作完这个游戏的初版以后,孤狼会尝试着和各位一块儿进行更深层次的挖掘,方向呢是关于设计模式和软件架构的,我写项目这么长时间以来,仍是以为这一块颇有学问也颇有意思,也但愿和你们一块儿探讨一下。而后呢,孤狼博客的重点仍是在JavaEE的技术和框架应用上,固然,也会同步更新Android平台上的相关项目的开发过程。这些咱们须要涉及的话题呢,他们都有一个共同点,就是都使用Java做为编程语言,这也就是为何我会选择一个比较的蹩脚的游戏开始的缘由。固然,在进行项目的过程当中,孤狼尽量的会从一个软件代码开发的各个阶段去进行撰文,这里面也包含了UI设计。我我的虽然比不了那些专业的设计师,可是仍是作过不少项目的UI设计,PhotoShop用的也还比较熟练,所以在这方面个人博文也会有所涉及,但愿能够帮助你们对软件开发有一个比较全面的认识。
     
好了,下面咱们进入咱们此次的项目。首先咱们要作的固然是在Snake类中添加蛇运动的方法move,下面是该方法的代码: java

        /**
	 * 蛇移动的方法
	 */
	public void move(){
		//1.去尾。这个很简单,意思就是说去掉咱们snakeList的最后一个元素
		snakeBody.removeLast();
		 //2.加头。这个就相对复杂一点,须要咱们根据蛇当前运动的方向来判断咱们的蛇头应该加在什么位置
		Body head = snakeBody.getFirst();//得到当前蛇头的那个对象
		switch(direction){
		case DIR_UP:
			snakeBody.addFirst(new Body(head.x, head.y - BODY_SIZE));
			break;
		case DIR_DOWN:
			snakeBody.addFirst(new Body(head.x, head.y + BODY_SIZE));
			break;
		case DIR_LEFT:
			snakeBody.addFirst(new Body(head.x - BODY_SIZE, head.y));
			break;
		case DIR_RIGHT:
			snakeBody.addFirst(new Body(head.x + BODY_SIZE, head.y));
			break;
		}
	}
在这个方法中,按照咱们分析的蛇的运动方式的算法,咱们先去掉蛇尾,再在合适的位置加上咱们新的蛇头。
      接下来呢,咱们就要在线程中来不断的调用咱们蛇的move方法而且不断刷新咱们的游戏窗口,这个原理我想你们都很清楚,和动画片的实现是一个道理。仍是先看线程部分的代码:
        /**
	 * 游戏的主线程
	 * @author jiladeyouxiang@qq.com
	 *
	 */
	class GameThread extends Thread{
		
		/** 控制游戏开始于暂停的标志 */
		private boolean isRunning = true;
		
		/**
		 * 设置游戏的运行状态,运行或是暂停
		 * @param isRunning	让游戏运行则传入true,让游戏中止则传入false
		 */
		public void setIsRunning(boolean isRunning){
			this.isRunning = isRunning;
		}
		
		/**
		 * 构造一个游戏的运行线程对象
		 * @param isRunning	让游戏运行则传入true,让游戏中止则传入false
		 */
		public GameThread(boolean isRunning){
			setIsRunning(isRunning);
		}
		
		/**
		 * 线程执行的具体逻辑
		 */
		public void run(){
			//咱们让线程在循环中每隔1000毫秒执行一次
			while(isRunning){
				//更新游戏的数据
				updateGame();
				//刷新游戏界面
				repaint();
				//让线程休眠100毫秒后继续执行
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
	}
这个类呢咱们一样采用内部类的形式来实现,由于咱们的这个线程只须要获取GameView中的数据,而且其余的类也不须要调用它。线程的基本概念呢孤狼就不讲了,但愿不理解线程的同窗本身去查阅相关的资料。在线程中呢,最重要的就是要去重写run方法,在run方法中去实现咱们本身的逻辑。你们能够看到,咱们在run方法中作了这么几件事情,首先是更新游戏的数据,而后是让界面进行重绘。在这里,孤狼解释一下repaint()方法,当咱们调用这个方法的时候,咱们的java虚拟机会去调用咱们的paint(Graphics g)这个方法,也就是咱们写在GameView中的绘制游戏界面的方法。接着,咱们让线程休眠1000毫秒,近似于1秒。这个值主要是咱们来模拟游戏的运行速度,或者说是一个简单的控制游戏的帧数。固然,真实的游戏线程不会这么简单,我只是进行了简单的模拟,在游戏的线程中这部分要复杂的多,光帧数的控制就有多种方式,感兴趣的同窗能够去查阅和游戏线程相关的资料,这不是咱们研究的重点。接着呢,你们能够看到咱们在这个线程中还设置了一个标志来控制游戏的暂停和运行。

      接着,咱们在GameView中写一个新的方法updateGame(),意思就是,咱们全部游戏的数据更新都在这个方法中去完成,有利于咱们的代码维护和管理:
算法

        /**
	 * 刷新游戏的数据
	 */
	public void updateGame(){
		snake.move();
	}

      有了咱们游戏的主线程,那么咱们就只须要在GameView中的initGameData()方法中加上关于线程的部分就能够了,下面是代码:

        /**
	 * 初始化和游戏相关的数据
	 */
	private void initGameData() {
		//构造蛇的对象
		snake = new Snake();
		//初始化游戏的主线程
		gameThread = new GameThread(true);
		//让游戏的主线程开始运行
		gameThread.start();
	}
     到这里呢,基本上咱们的项目已经完成了,最后有一个细节:咱们须要修改paint()方法:

        /**
	 * 绘制界面的方法
	 */
	@Override
	public void paint(Graphics g) {
		//将窗口清空
		g.clearRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
		//绘制蛇的对象
		snake.drawMe(g);
	}
咱们每次绘制以前都须要将窗口清空,要否则你会发现你的蛇会不断边长,缘由是什么呢,就是之前绘制的那些数据没有被清除。       至此,你就能够点击运行试试看了,是否是咱们的蛇就开始运动了,不过貌似咱们的蛇如今一路向东,撞了东墙都不回头,这个呢,咱们在下一个版本中进行修复,好了,就到这吧。       我把代码都放在迅雷快传上了,你们奔走相告吧,这里给出连接,一篇博文对应一个项目文件,你们直接导入工程就能够运行: http://kuai.xunlei.com/d/nNdkCUf1HBXTUAQA44e
相关文章
相关标签/搜索