我目前正在开发Android游戏,并遇到有关Activity和Renderer之间通信的问题。
我有Activity
个GLSurfaceView
作为内容视图,Renderer
附加到GLSurfaceView
。 Renderer
包含游戏循环。它绘制场景并更新游戏状态。这似乎是最好的做法,到目前为止工作顺利。 Activity
还会显示按钮或游戏分数等UI元素。
Activity
在UI线程中运行,Renderer
有自己的线程。所以基本上我必须处理线程间通信。我使用GLSurfaceView.queueEvent(Runnable)
从Renderer
调用Activity
帖子中的内容(例如,开始游戏循环)。要从Renderer
中使用Activity.runOnUiThread(Runnable)
来调用UI线程中的内容(例如更新游戏分数UI元素)。
每次我想与其他线程通信时,必须实例化Runnable
。在某些时候,这将触发垃圾收集,因为VM需要释放内存。这当然会打断游戏。
在没有实例化新对象的情况下还有其他选择吗?目标是在游戏运行时保持内存分配不变。
答案 0 :(得分:2)
不要为每条消息分配Runnables。为接收消息的线程创建一个处理程序,并获取带有例如消息的消息对象。 obtainMessage()
以避免分配。
您可以在Grafika中找到多个此示例,其中包含最小化或消除各种活动分配的步骤。 Android Breakout在游戏过程中没有[*]分配(虽然它在播放时不使用任何View UI)。
切换到本机代码的建议通常是过度的,特别是如果您的唯一目的是避免垃圾回收。
评估游戏状态的最佳工具是DDMS allocation tracker,它显示了N个最近的分配。
[*]我有一段时间没有检查Android Breakout。目标是零分配。
答案 1 :(得分:1)
我不会将Android UI元素与GLSurfaceView混合使用。为什么,你可能会问。好吧,普通的UI元素使用OGL作为尽力而为。如果某些事情无法使用OGL呈现,则会以其他方式呈现它们(例如,软件渲染)。此外,渲染这些元素受Activity活动渲染循环的生命周期影响,从而有效地限制了游戏的性能。
如果您希望最小化GC运行/ queueEvent
来电,可以执行某些操作。
在C ++中,您可以随意分配自己的东西并随意释放它们。本机代码通常用于游戏物理和类似的东西,但你也可以将OpenGL放入其中。
就像我说的那样,我不会使用普通的UI元素,而是使用OGL中的纹理(精灵)来渲染我自己的元素,从而消除了runOnUiThread
的需要。
对于queueEvent
,只有在您调用的代码修改OGL状态机时才需要(基本上所有gl*
调用)。我的猜测是你主要使用这个事件排队将触摸坐标和其他“修饰符”传递给你的游戏逻辑。为了摆脱这种情况,不要直接从调用的方法修改OGL,只需更改模型属性并在下一个渲染循环中绘制/设置新的OGL状态(确保以同步方式进行更改,否则它可以搞乱事情。)
如果您的游戏图形不重并且不需要特殊渲染选项,则可以使用自定义View
的画布,这样您也可以渲染文本。请注意,画布最终可能会使用OGL来处理很多事情,所以对于创建休闲2D游戏,它仍然很好。
使用新的queueEvent
实例调用Runnable
并不一定是件坏事。运行Runnable实例的GLThread在从队列中取出并运行后将其置零(将其设置为null
),这告诉GC它可以随时释放其内存。这是一种在Java编程中广泛使用的优化技术,因为GC不再需要测试关于此对象的某些内容。因此,GC运行不会花费你想象的那么多时间。