`
iceliushuai
  • 浏览: 27361 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

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

    博客分类:
  • JAVA
阅读更多
最近写了一个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
分享到:
评论
21 楼 shily 2009-05-26  
liuxuan620 写道
用wait 和 notify就挺好的呀。

只是为了学习讨论一下能用的方式,在信号量的示例中,使用的也是wait()和notify()方式,只是封装一下而已。
20 楼 liuxuan620 2009-05-25  
用wait 和 notify就挺好的呀。
19 楼 neora 2009-05-24  
wjyjimy 写道
怕麻烦的话就用thread.sleep();好了。。。虽然会出现很多不良效果。。

什么不良后果?
18 楼 shily 2009-05-23  
使用信号量来实现暂停的方式

画面更新进程中
class TrafficLightRunnable implements Runnable {
		public void run() {
			try {
				while (true) {

					if (mode == PAUSE) {
						// just for wait
						gate.acquire();

						// release it
						gate.release();
					}

					tl.updatePanel();
					Thread.sleep(1000);
				}
			} catch (InterruptedException ex) {
				System.out.println(ex.getMessage());
			}
		}
	}


在事件响应方法中
//信号量
private Semaphore gate = new Semaphore(1);

public void actionPerformed(ActionEvent e) {
			if (btn.getText().equals("Pause")) {
				btn.setText("Start");
				try {
					gate.acquire();
					mode = PAUSE;
				} catch (InterruptedException e) {
				}
			} else {
				btn.setText("Pause");
				mode = RUNNING;
				gate.release();
			}
		}

17 楼 wjyjimy 2009-05-22  
javaeye里怎么不加个“最让人吐血的楼主”评选栏目呢,不多说了,上面代码改为


package thread睡眠与唤醒;

/**
*
* @author Administrator
*/
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here

        compute t=new compute();
        t.start();
        t.interrupt();

    }

}

///创建一个线程类,在这个类中,通过休眠,让线程运行输出不同的结果
class compute extends Thread
{
    int i=0;
    public void run()
    {
        System.out.println("在工作中,不要打扰");
        try
        {
            sleep(1000000);
        }
        catch(Exception e){}
        System.out.println("哦,电话来了");
    }
}
16 楼 iceliushuai 2009-05-22  
wjyjimy 写道
我实在很无语,,你动手试试下面的代码输出了什么,然后把t.interrupt();注释掉,再看看输出的是什么,我不多说了,可能你想得太多了,不是有句话叫做“什么都别想------直接去做”吗?

public class thread6
{
    public static void main(String[] args)
    {
        compute t=new compute();
        t.start();
        t.interrupt();
    }
}
///创建一个线程类,在这个类中,通过休眠,让线程运行输出不同的结果
class compute extends Thread 
{
    int i=0;
    public void run()
    {
        System.out.println("在工作中,不要打扰");
        try
        {
            sleep(10000000);
        }
        catch(Exception e){System.out.println("哦,电话来了");}
    }
}

这种方式是可行的,但是这并不是interrupt的用途,就像API中所说的,它只是通知相应的线程而已。同时会引起sleep()函数出现异常,在这种情况下就变成用异常来控制程序了。
15 楼 wjyjimy 2009-05-22  
我实在很无语,,你动手试试下面的代码输出了什么,然后把t.interrupt();注释掉,再看看输出的是什么,我不多说了,可能你想得太多了,不是有句话叫做“什么都别想------直接去做”吗?

public class thread6
{
    public static void main(String[] args)
    {
        compute t=new compute();
        t.start();
        t.interrupt();
    }
}
///创建一个线程类,在这个类中,通过休眠,让线程运行输出不同的结果
class compute extends Thread 
{
    int i=0;
    public void run()
    {
        System.out.println("在工作中,不要打扰");
        try
        {
            sleep(10000000);
        }
        catch(Exception e){System.out.println("哦,电话来了");}
    }
}
14 楼 iceliushuai 2009-05-22  
insiku 写道
唉 基础不是一般般的差

大哥,不要光感叹,基础也是慢慢练出来的啊。
13 楼 iceliushuai 2009-05-22  
liujunsong 写道
我就简单说一句.
先别搞那个多线程,用一个线程先把程序写出来.
然后慢慢改成多线程的,啥问题都可以解决了.

就有两个线程而已,一个用来接收用户输入,一个用来更新画面,我觉得这样至少两个线程吧。
12 楼 iceliushuai 2009-05-22  
wjyjimy 写道

看清楚你的API呀,

如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。    
意思就是如果正在SLEEP(),就先把SLEEP()干掉,而不是干掉thread。

无语了,interrupt()函数根本就不是中断线程的,它只是设置线程的一个中断变量,由程序来决定是否使用这个变量,但是如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法时,中断变量被置位,则这些方法会抛出InterruptedException这个异常。

这个函数只是通知一个线程结束而已,如下代码
private Thread eventHandler = new Thread(eventRunnable);
	
private Runnable eventRunnable = new TrafficLightRunnable();
class TrafficLightRunnable implements Runnable {
		public void run() {
		while (true) {
                    // Do something
                    // for example repaint the panel
		    tl.repaint();
		}
		}
}

你即使调用了eventHandler.interrupt();它也不会停止。
11 楼 wjyjimy 2009-05-22  

看清楚你的API呀,

如果线程在调用 Object 类的 wait()、wait(long) 或 wait(long, int) 方法,或者该类的 join()、join(long)、join(long, int)、sleep(long) 或 sleep(long, int) 方法过程中受阻,则其中断状态将被清除,它还将收到一个 InterruptedException。    
意思就是如果正在SLEEP(),就先把SLEEP()干掉,而不是干掉thread。
10 楼 liujunsong 2009-05-22  
我就简单说一句.
先别搞那个多线程,用一个线程先把程序写出来.
然后慢慢改成多线程的,啥问题都可以解决了.
9 楼 insiku 2009-05-21  
唉 基础不是一般般的差
8 楼 iceliushuai 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 - 如果当前线程无法修改该线程
7 楼 wjyjimy 2009-05-20  
iceliushuai 写道
wjyjimy 写道
你最多可以thread.sleep(922337203685477587);哦~

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


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



晕哦,,还说我不用脑子呢,你怎么连线程睡眠和唤醒都不知呢,你想什么时候不SLEEP(),就是直接调用interrupt() 终止睡眠咯,别告诉我你不会用,太没礼貌了。
6 楼 iceliushuai 2009-05-20  
wjyjimy 写道
你最多可以thread.sleep(922337203685477587);哦~

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


兄弟, 用点头脑好不好,你让它sleep了这么久,当你点开始的时候它还会反应么~~
5 楼 wjyjimy 2009-05-20  
你最多可以thread.sleep(922337203685477587);哦~

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

4 楼 iceliushuai 2009-05-19  
wjyjimy 写道
怕麻烦的话就用thread.sleep();好了。。。虽然会出现很多不良效果。。
已经说明了Thread.sleep()有很多的不好,不知道其它的程序是如何实现的,如果使用这个的话,时间设置多少才会好些呢?
3 楼 iceliushuai 2009-05-19  
Saito 写道
Memento模式.

不太了解设计模式,不过我看这个模块好像是保存状态的,在网上找了一下,好像做Undo操作的啊。不知道如果实现暂停。
2 楼 wjyjimy 2009-05-19  
怕麻烦的话就用thread.sleep();好了。。。虽然会出现很多不良效果。。

相关推荐

    生命游戏javaGUI实现界面十分美观

    本文将详细讨论如何使用Java图形用户界面(GUI)技术来实现一个美观的生命游戏界面。Java GUI为我们提供了丰富的组件和工具,可以创建出互动性强、视觉效果良好的应用程序。我们将主要关注以下几点: 1. **Java GUI...

    基于JAVA的飞机大战游戏的设计与实现计算机毕业设计论文

    - **游戏难点分析**:讨论在开发过程中可能遇到的技术难题,如性能优化、多线程处理等。 #### 飞机大战功能实现 - **游戏首页的实现**:设计游戏的启动页面,包括游戏logo、开始按钮等元素,为用户提供友好的界面...

    用java做的对对碰游戏

    在这个项目中,我们讨论的是一个基于Java实现的“对对碰”游戏。对对碰游戏是一种流行的小型休闲游戏,玩家需要通过交换相邻的图标来匹配三个或更多相同的图标,以消除它们并得分。 首先,我们需要了解Java的基础...

    关于用Java手机游戏

    1. **图形和动画**: 在Java游戏中,图形和动画是至关重要的。开发者通常会使用Java的AWT或Swing库进行2D图形绘制,或者使用Android的OpenGL ES API进行3D图形渲染。通过帧动画和精灵(Sprite)技术,可以实现角色和...

    Java2游戏编程源码

    总的来说,《Java2游戏编程源码》第四章深入浅出地介绍了Java游戏开发的关键技术,不仅让读者能够理解游戏开发的基本流程,还提供了实际操作的机会,是学习Java游戏编程的宝贵资料。通过实践这些源代码,读者不仅...

    Java实现生命游戏.zip

    在这个项目中,Java被用来编写代码,实现生命游戏的规则和交互功能。开发者可能使用了Java的基础语法,包括类、对象、变量、条件语句、循环、异常处理等,来构建游戏的核心逻辑。 生命游戏的规则相当简洁:在一个二...

    java实现超级玛丽小游戏.zip

    Java 实现超级玛丽小游戏是一个基于Java编程语言的项目,展示了游戏开发的基本原理和技术。这个项目不仅为学习者提供了深入理解Java编程的机会,还让他们能够接触到游戏设计的核心概念,包括对象定位、碰撞检测、...

    用 JAVA 开发游戏连连看 实现游戏的算法

    在JAVA中开发一款游戏,如“连连看”,涉及到多个编程技术与算法的综合应用。首先,我们要理解连连看的基本规则:玩家需要找到并消除一对相同的图案,这些图案必须通过不超过两条直线连接,且直线不能穿过其他图案。...

    基于java的坦克大战游戏的设计与实现-毕业论文

    《基于Java的坦克大战游戏的设计与实现》是一篇深度探讨如何使用Java编程语言来构建一款坦克大战游戏的毕业论文。...通过阅读这篇论文,读者不仅能了解Java游戏开发的基本流程,还能深入理解游戏设计背后的技术原理。

    Java.awt实现的符合面向对象思想的贪吃蛇游戏.zip

    在本项目中,"Java.awt实现的符合面向对象思想的贪吃蛇游戏.zip" 是一个使用Java编程语言,特别是Java AWT(Abstract Window Toolkit)库创建的贪吃蛇游戏。贪吃蛇游戏是一款经典的休闲游戏,玩家通过控制一条蛇来吃...

    java swing 小游戏 俄罗斯方块

    在这个场景中,我们讨论的是使用Java Swing实现的经典小游戏——俄罗斯方块。俄罗斯方块是一款流行的世界级益智游戏,由不同形状的方块组成,玩家需要控制这些方块在屏幕上自由下落,并尽可能地填满一整行来消除得分...

    java小游戏 -java拼图源码 java拼图.rar

    【标题】中的“java小游戏 -java拼图源码”指的是一个使用Java编程语言开发的小游戏,具体来说是一款拼图游戏。在Java编程中,开发这样的游戏通常...对于想要深入学习Java游戏开发的人来说,这是一个很好的实践项目。

    雷电游戏JAVA代码

    【雷电游戏JAVA代码】 在Java编程领域,雷电游戏是...总之,"雷电游戏JAVA代码"是一个展示Java游戏开发能力的实例,它涵盖了面向对象设计、图形绘制、输入处理等多个关键知识点,对于学习和提升Java编程技能大有裨益。

    雷电游戏JAVA版源程序资料

    这个压缩包包含的文件详细讲解了如何使用Java来创建雷电风格的射击游戏,是学习Java游戏开发的宝贵资料。 Java是一种广泛使用的面向对象的编程语言,以其跨平台性和高效性能闻名。在游戏开发领域,Java不仅适用于...

    使用Java实现的拼图游戏,有音乐播放.zip

    在本项目中,我们讨论的是一个使用Java编程语言实现的拼图游戏,它还具备音乐播放功能。这个项目可以从其压缩包文件名“使用Java实现的拼图游戏,有音乐播放.zip”中得到基本信息。解压后的主要文件目录是“jigsaw-...

    Java坚持玩20秒小游戏

    在本项目中,我们讨论的是一个使用Java编程语言开发的简单20秒小游戏。这个小游戏是作者基于经典游戏的灵感,通过自我探索和实践编写的。对于初学者和对小游戏开发感兴趣的人来说,这是一个很好的学习资源,可以理解...

    Java毕业设计-基于Java ME无线网络移动端的俄罗斯方块游戏的实现(源代码+论文).rar

    《基于Java ME无线网络移动端的俄罗斯方块游戏实现》 Java ME(Micro Edition)是Java技术在移动设备和嵌入式设备上的应用平台,它为开发面向小型设备的应用提供了强大的框架。本项目主要探讨如何利用Java ME技术在...

    java RPG 源码 建筑菜单制作中

    通过分析这个“java RPG 源码 建筑菜单制作中”的项目,开发者可以深入学习到如何在Java环境中实现RPG游戏的菜单系统,以及如何处理游戏中的交互逻辑和资源管理。对于初学者来说,这是一个极好的实践和学习机会。

    JAVA打飞机游戏设计与实现(论文+源代码).zip

    在打飞机游戏中,Java的面向对象特性将被用来创建游戏对象,如飞机、子弹、敌人等,每个对象都有自己的属性和行为。 其次,游戏设计涉及到的主要概念包括游戏循环(Game Loop)、事件处理、碰撞检测和图形绘制。...

Global site tag (gtag.js) - Google Analytics