在不阻塞游戏线程的情况下等待触摸输入
Waiting for touch input without blocking game thread
我最近在为 android 开发一款游戏。该游戏的格式类似于 classic Pokemon 游戏(相当复杂)。我已经走了很远没有任何问题。但是,我发现很难开发有人说话时出现在屏幕底部的对话(打字机文本)框。我一直在等待任何输入而不阻塞渲染和更新方法(因为它们都在同一个线程上运行)。
这是我的游戏循环的简化版本,概述了结构以及我在每一帧中所做的事情。显示的更新方法是通过 View#onDraw 方法调用的。
public static void update(Canvas canvas, GameView view){
//time operations (calculating delta etc.)
long cTime = System.currentTimeMillis();
delta = cTime - time;
time = cTime;
globals.put("time", time);
globals.put("delta", delta);//set vars for scripts
camera.applyToCanvas(canvas);//apply camera matrix to canvas
if(map != null)map.update();
if(battle != null)map.update();
Effect.updateAll();//update everything (game logic)
render.load(canvas);//load the canvas into my custom render engine
render();//call render method (shown below)
view.invalidate();//reset view for redraw
}
public static void render(){
render.reset();//clears the canvas using canvas.setColor(Color.BLACK)
if(map != null)map.draw();
if(battle != null)battle.draw();
if(dialog != null)dialog.draw();
if(gui != null)gui.draw(); //draw everything using the renderengine
}
如您所见,这些操作会更新所有游戏组件(地图、战斗、GUI 等),然后将它们渲染到屏幕上。通过查看代码,很明显我运行在同一个线程上执行这些操作,所以这个线程显然不能被阻塞(否则游戏将停止)。
这就是我的问题所在。我使用带有几个按钮的游戏图形用户界面。这些按钮被分配给 8 个整数 (0-8),例如,当按下向上按钮时,该输入数据将通过游戏传递到现有对话或战斗或任何需要它的地方。这些按钮依赖于主要 activity 的触摸事件,其中 MotionEvent 作为 运行 将游戏循环从 onDraw 方法关闭的结果,在与游戏本身相同的线程上进行调整。以下是我处理对话框的方式:
我使用javascript(rhino 解析器)如下(将对话框对象传递给变量'dialog'中的脚本):
var d = dialog.show("Hello! How are you.");
为了获取输入,我调用了接受对话框的 getInput 方法,以及最多 4 个字符串作为 selection 选项。此方法应该 return 一个整数值。这可以通过脚本调用如下:
var response = dialog.getInput(d, "I'm fine, thank you!", "Who wants to know.");
getInput方法在我的Dialog中如下class:
public static int getInput(Dialog d, String... args){
d.waitingForInput = true;
d.lastInput = -1;
while(d.waitingForInput || d.lastInput == -1){
//render options
//main thread is obviously blocked here.
}
return d.getLastInput();//returns the d.lastInput and resets waitingForInput and lastInput. The script can then use this value to decide what to do.
}
现在我的主要问题是如何在不阻塞渲染和更新线程的情况下运行这个方法。更具体地说,当用户触摸屏幕的某个区域(gui select 按钮所在的位置)时,设置 d.lastInput 和 d.waitingForInput 的值。
如果对我在这个问题中想问的问题有任何疑问,请发表评论,因为我很累并且花了一些时间来解决这个问题。
编辑:
我考虑过 运行 在一个单独的线程上输入,但这仍然会导致阻止调用其他输入法(例如更改对话框中的 selected 选项) .
如果您不想停止线程并且您已经完成了一半
方法 1: 使用 ConcurrentLinkedQueue、ArrayBlockingQueue 及其家族作为静态变量并将您的值放入其中。
Method2: 你可以使用 TCP/UDP 套接字 使用 localhost 适配器就像消息队列系统一样,并尝试使用相同的 ConcurrentLinkedQueue、ArrayBlockingQueue 技术获取这些值
尝试参考任何开源 java 游戏引擎源代码并确定它们是如何工作的,或者您可以使用这些游戏引擎,例如 "jMonkeyEngine" "LWJGL" ...等
我决定通过一种事件处理程序的形式来解决这个问题。当要求输入down时,游戏指定脚本为运行
我最近在为 android 开发一款游戏。该游戏的格式类似于 classic Pokemon 游戏(相当复杂)。我已经走了很远没有任何问题。但是,我发现很难开发有人说话时出现在屏幕底部的对话(打字机文本)框。我一直在等待任何输入而不阻塞渲染和更新方法(因为它们都在同一个线程上运行)。
这是我的游戏循环的简化版本,概述了结构以及我在每一帧中所做的事情。显示的更新方法是通过 View#onDraw 方法调用的。
public static void update(Canvas canvas, GameView view){
//time operations (calculating delta etc.)
long cTime = System.currentTimeMillis();
delta = cTime - time;
time = cTime;
globals.put("time", time);
globals.put("delta", delta);//set vars for scripts
camera.applyToCanvas(canvas);//apply camera matrix to canvas
if(map != null)map.update();
if(battle != null)map.update();
Effect.updateAll();//update everything (game logic)
render.load(canvas);//load the canvas into my custom render engine
render();//call render method (shown below)
view.invalidate();//reset view for redraw
}
public static void render(){
render.reset();//clears the canvas using canvas.setColor(Color.BLACK)
if(map != null)map.draw();
if(battle != null)battle.draw();
if(dialog != null)dialog.draw();
if(gui != null)gui.draw(); //draw everything using the renderengine
}
如您所见,这些操作会更新所有游戏组件(地图、战斗、GUI 等),然后将它们渲染到屏幕上。通过查看代码,很明显我运行在同一个线程上执行这些操作,所以这个线程显然不能被阻塞(否则游戏将停止)。
这就是我的问题所在。我使用带有几个按钮的游戏图形用户界面。这些按钮被分配给 8 个整数 (0-8),例如,当按下向上按钮时,该输入数据将通过游戏传递到现有对话或战斗或任何需要它的地方。这些按钮依赖于主要 activity 的触摸事件,其中 MotionEvent 作为 运行 将游戏循环从 onDraw 方法关闭的结果,在与游戏本身相同的线程上进行调整。以下是我处理对话框的方式:
我使用javascript(rhino 解析器)如下(将对话框对象传递给变量'dialog'中的脚本): var d = dialog.show("Hello! How are you.");
为了获取输入,我调用了接受对话框的 getInput 方法,以及最多 4 个字符串作为 selection 选项。此方法应该 return 一个整数值。这可以通过脚本调用如下:
var response = dialog.getInput(d, "I'm fine, thank you!", "Who wants to know.");
getInput方法在我的Dialog中如下class:
public static int getInput(Dialog d, String... args){ d.waitingForInput = true; d.lastInput = -1; while(d.waitingForInput || d.lastInput == -1){ //render options //main thread is obviously blocked here. } return d.getLastInput();//returns the d.lastInput and resets waitingForInput and lastInput. The script can then use this value to decide what to do. }
现在我的主要问题是如何在不阻塞渲染和更新线程的情况下运行这个方法。更具体地说,当用户触摸屏幕的某个区域(gui select 按钮所在的位置)时,设置 d.lastInput 和 d.waitingForInput 的值。
如果对我在这个问题中想问的问题有任何疑问,请发表评论,因为我很累并且花了一些时间来解决这个问题。
编辑:
我考虑过 运行 在一个单独的线程上输入,但这仍然会导致阻止调用其他输入法(例如更改对话框中的 selected 选项) .
如果您不想停止线程并且您已经完成了一半
方法 1: 使用 ConcurrentLinkedQueue、ArrayBlockingQueue 及其家族作为静态变量并将您的值放入其中。
Method2: 你可以使用 TCP/UDP 套接字 使用 localhost 适配器就像消息队列系统一样,并尝试使用相同的 ConcurrentLinkedQueue、ArrayBlockingQueue 技术获取这些值
尝试参考任何开源 java 游戏引擎源代码并确定它们是如何工作的,或者您可以使用这些游戏引擎,例如 "jMonkeyEngine" "LWJGL" ...等
我决定通过一种事件处理程序的形式来解决这个问题。当要求输入down时,游戏指定脚本为运行