论坛首页 Java企业应用论坛

关于在Java游戏中实现暂停的讨论

浏览 14543 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2009-05-15   最后修改:2009-05-23
最近写了一个Swing版本的Snake程序,可是不太清楚怎么样来实现游戏中常见的暂停操作,所以我列出自己的一些方案,大家来讨论下什么样的方式会好些,还有就是如何更好的实现暂停这种方法。

方案1,直接利用状态变量,如果处于暂停状态,则什么也不做(空循环)
public void keyPressed(KeyEvent e) {
		int keyCode = e.getKeyCode();
		int mDirection = sv.getMoveDirection();

		// KEY_START
		//如果是开始键,就设置程序状态为开始
		if (keyCode == SnakeKey.START) {
			gameState == RUNNING;
			return;
		}
		// KEY_PAUSE
		//如果是暂停键,就设置程序状态为开始
		if (keyCode == SnakeKey.PAUSE) {
			gameState == PAUSE;
			return;
		}
		//设置方向
		//省略其它按键的操作
		//...
		return;
	}

更新画面的线程

private Thread mRedrawHandler = new Thread() {
		@Override
		public void run() {
			try {
				while (true) {
					// if pause mode, do nothing
					if (mMode == PAUSE) {
						continue;
					}

					if (mMode == RUNNING) {
						// 进行更新操作
						// 省略部分代码
					}

					Thread.sleep(mMoveDelay);
				}

				if (mMode == LOSE) {
					// TODO sss
					// 重置 mScore
					// 重置 mMoveDelay
					// 记录当前得分,如果有排行榜的话
				}
			} catch (InterruptedException ex) {
			}
		}
	};

觉得这样的话 while 循环会占用大量的 CPU 时间 , 所以在 continue 前加了一个 Thread.sleep(1000); 先让程序停止 1s 钟。虽然不知道系统的原理是什么,但感觉自己写的空循环占用的资源要比 Thread.sleep() 要多吧。
if (mMode == PAUSE) {
        Thread.sleep(1000);
        continue; 
	}

可是觉得这样也不好,会影响程序的响应速度。

后来学习了线程的同步,就想着改成同步,在系统中加入一个锁,平时这个锁可以由画面线程获得,可是当按下 pause 时,就让另外的线程取得锁,这样的话,画面线程取得不到锁,就会自已停下来了。

接收键盘事件的函数

public void keyPressed(KeyEvent e) {
		int keyCode = e.getKeyCode();
		int mDirection = sv.getMoveDirection();
		// KEY_START
		if (keyCode == SnakeKey.START) {
			pauseOrResume();
			return;
		}
		// KEY_PAUSE
		if (keyCode == SnakeKey.PAUSE) {
			pauseOrResume();
			return;
		}

		//设置方向
		//省略其它按键的操作
		//...

		return;
	}

更新画面的线程

	private Thread mRedrawHandler = new Thread() {
		@Override
		public void run() {
			try {
				while (true) {
					synchronized (pauseLock) {
						// if pause mode, wait the lock.
						if (mMode == PAUSE) {
							pauseLock.wait();
						}
						pauseLock.notifyAll();
					}

					if (mMode == RUNNING) {
						// 进行更新操作
						// 省略部分代码
					}

					Thread.sleep(mMoveDelay);
				}
				if (mMode == LOSE) {
					// TODO sss
					// 重置 mScore
					// 重置 mMoveDelay
					// 记录当前得分,如果有排行榜的话
				}
			} catch (InterruptedException ex) {
			}
		}
	};

另外加了一个方法来控制锁:

	private Object pauseLock = new Object();
     /**
	 * Pause or resume the game
	 */
	private void pauseOrResume() {
		while (true)
			synchronized (pauseLock) {
				if (mMode == RUNNING) {
					mMode = PAUSE;
					break;
				}
				if (mMode == PAUSE || mMode == LOSE) {
					mMode = RUNNING;
					 // Tell the screen to run. 
					pauseLock.notifyAll();
					break;
				}
			}
	}

但是不知道在这种情况下会有什么不好,欢迎大家讨论。

附件是一个小的示例程序,大家可以看一下,可以是因为代码贴多了,不好容易看,可以下载附件看看示例。
=================================================
2009-05-23
1.更新了代码,删除了无用的部分代码
2.更新了TrafficLightsDemo.jar代码,修正原来的代码,使用在暂停时的响应时间减少。
3.贪吃蛇的程序已经放到论坛上,可以去下载看全部代码http://www.iteye.com/topic/393669
  • TrafficLightsDemo.jar (28.9 KB)
  • 描述: 小示例程序 wait()和notifyAll()来实现暂停
  • 下载次数: 101
   发表时间:2009-05-16  
Memento模式.

       
0 请登录后投票
   发表时间:2009-05-19   最后修改:2009-05-19
怕麻烦的话就用thread.sleep();好了。。。虽然会出现很多不良效果。。
0 请登录后投票
   发表时间:2009-05-19  
Saito 写道
Memento模式.

不太了解设计模式,不过我看这个模块好像是保存状态的,在网上找了一下,好像做Undo操作的啊。不知道如果实现暂停。
0 请登录后投票
   发表时间:2009-05-19  
wjyjimy 写道
怕麻烦的话就用thread.sleep();好了。。。虽然会出现很多不良效果。。
已经说明了Thread.sleep()有很多的不好,不知道其它的程序是如何实现的,如果使用这个的话,时间设置多少才会好些呢?
0 请登录后投票
   发表时间:2009-05-20  
你最多可以thread.sleep(922337203685477587);哦~

你直接就填10000000好了,以前学Midlet的时候老师好象说不要用pauseApp()来暂
停,要用就用thread.Sleep(),现在我都忘了Midlet怎么个写法了,呵呵~

0 请登录后投票
   发表时间:2009-05-20  
wjyjimy 写道
你最多可以thread.sleep(922337203685477587);哦~

你直接就填10000000好了,以前学Midlet的时候老师好象说不要用pauseApp()来暂
停,要用就用thread.Sleep(),现在我都忘了Midlet怎么个写法了,呵呵~


兄弟, 用点头脑好不好,你让它sleep了这么久,当你点开始的时候它还会反应么~~
0 请登录后投票
   发表时间:2009-05-20  
iceliushuai 写道
wjyjimy 写道
你最多可以thread.sleep(922337203685477587);哦~

你直接就填10000000好了,以前学Midlet的时候老师好象说不要用pauseApp()来暂
停,要用就用thread.Sleep(),现在我都忘了Midlet怎么个写法了,呵呵~


兄弟, 用点头脑好不好,你让它sleep了这么久,当你点开始的时候它还会反应么~~



晕哦,,还说我不用脑子呢,你怎么连线程睡眠和唤醒都不知呢,你想什么时候不SLEEP(),就是直接调用interrupt() 终止睡眠咯,别告诉我你不会用,太没礼貌了。
0 请登录后投票
   发表时间:2009-05-21   最后修改:2009-05-21
wjyjimy 写道

晕哦,,还说我不用脑子呢,你怎么连线程睡眠和唤醒都不知呢,你想什么时候不SLEEP(),就是直接调用interrupt() 终止睡眠咯,别告诉我你不会用,太没礼貌了。

首先对我说有话表示歉意,说的有点重了。

在JAVA的API中,interrupt()是用来中断一个线程的,而不是中断睡眠的,如果调用了这个方法,这个线程就已经停止了,这和暂停的这种说法已经不同了。当然喽,经过你的启发,我想也可以设计成在点击”暂停“时直接中断“刷新界面”的线程,在点击”开始“时再次启动一个新线程,做同样的工作,但这和当前的讨论无关。
Java2 Platform Standard Ed. 6 写道

interrupt
public void interrupt()中断线程。
如果当前线程没有中断它自己(这在任何情况下都是允许的),则该线程的 checkAccess 方法就会被调用,这可能抛出 SecurityException。

如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。

如果该线程在可中断的通道上的 I/O 操作中受阻,则该通道将被关闭,该线程的中断状态将被设置并且该线程将收到一个 ClosedByInterruptException。

如果该线程在一个 Selector 中受阻,则该线程的中断状态将被设置,它将立即从选择操作返回,并可能带有一个非零值,就好像调用了选择器的 wakeup 方法一样。

如果以前的条件都没有保存,则该线程的中断状态将被设置。

中断一个不处于活动状态的线程不需要任何作用。


抛出:
SecurityException - 如果当前线程无法修改该线程
0 请登录后投票
   发表时间:2009-05-21  
唉 基础不是一般般的差
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics