我正在尝试制作一款安卓游戏。
我有一个扩展活动并处理所有用户输入的游戏类。然后我有一个missionView类,它扩展了视图,并在屏幕上绘制了级别。
当用户点击门时,我想添加一些动画。
会发生什么:游戏叫门。打开。更改状态,以便view.onDraw函数将门打开半开。游戏调用view.invalidate,它应该重绘屏幕。然后游戏睡了半秒钟。然后再次打电话给door.open。第二次调用该函数时,它会更改状态,以便view.onDraw函数完全打开门。然后游戏再次调用view.invalidate。
问题是当它进入view.invalidate时它不会重绘屏幕。如果我在行上设置断点并运行调试器并单击步骤,则不会进入我的view.onDraw函数。它甚至无法显示它正在执行的代码。
我拥有的是: 门类:
public boolean open()
{
if (doorState == DoorState.Closed)
{
doorState = DoorState.Opening;
return true;
}
else if (doorState == DoorState.Opening)
{
doorState = doorState.Open;
return true;
}
else
{
return false;
}
}
游戏课程:
if (tile instanceof DoorTile)
{
DoorTile doorTile = (DoorTile) tile;
Door door = doorTile.getDoor();
if (door.isClosed())
{
door.open();
selectedEntity.openDoor();
view.invalidate(); // This line does not work
try
{
Thread.sleep(500);
}
catch (InterruptedException e1)
{
// TODO Auto-generated catch block
e1.printStackTrace();
}
door.open();
// Handled touch event so break switch statement
break;
}
}
答案 0 :(得分:22)
View#invalidate告诉系统一旦主线程空闲就重绘(通过onDraw)视图。也就是说,调用invalidate会在所有其他即时工作完成后重新绘制您的视图。如果从主线程中调用Game类中的代码并将该线程置于休眠状态,那么您不仅仅是暂停渲染,而是将所有输入处理暂停(通常是一个坏主意)。根据经验,除非你知道自己在做什么,否则永远不要忘记自己没有产生的线程。
如果你想让你的游戏逻辑定期延迟使用Thread#sleep,那么在另一个线程中运行它并使用view.postInvalidate()来指示主线程唤醒并调用onDraw。
答案 1 :(得分:14)
对于游戏,我实际上会使用较低级别的图形访问权限。来自Google的LunarLander就是一个很好的例子。基本上你需要做两件事:
使用包含
的自定义方法repaint()替换view.invalidate()private void repaint() {
Canvas c = null;
try {
c = surfaceHolder.lockCanvas();
paint(c);
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
Paint方法将包含目前在View.onDraw中的内容
答案 2 :(得分:0)
我在申请中遇到了同样的问题。
就我而言,我试图通过invalidate()
的{{1}}方法拨打[doInBackground()][1]
。
通过将[AsyncTask][2]
方法invalidate()
移至[onProgressUpdate()][3]
来解决问题。即您无法使用AsyncTask
的{{1}}方法更新用户界面。在Android文档中提到它,但它很容易忘记它...所以,不要忘记检查它。
答案 3 :(得分:0)
我可能会迟到,但是我确定这对您有用。
我与科特林做到了。您可以根据 Java 进行修改。
将代码放入runOnUIThread()
中。
示例代码:
activity?.runOnUiThread {
// Your code goes here
}
希望这会有所帮助。