所以,我正在开发一款游戏,并且每次使用一个对象移动时我都会使用Canvas和SurfaceHolder来更新屏幕。到目前为止,工作得很好。现在,问题发生在我想要停止绘制到Canvas并根据最后的绘图命令保留它时。
所以我试过的一种方法是简单地从满足结束条件时绘制时调用的函数返回。但是,当我这样做时,画布会在满足条件时发送的命令之间快速交替,并且命令在之前发送一次迭代。我不知道如何或为什么会发生这种情况,因为绘图功能在满足条件后没有执行任何绘制命令。任何人都可以解释当画布没有获得任何绘制命令时画布如何保持刷新?
用于锁定和解锁的线程中的代码非常简单:
public void run() {
Canvas c = null;
try {
c = sh.lockCanvas(null);
synchronized(sh) {
drawCan(c);
}
}
finally {
if(c!=null) {
sh.unlockCanvasAndPost(c);
}
}
}
并且drawCan函数的结构如下:
public void drawCan(Canvas c) {
/* Check if user's health is greater than 0. Don't draw anything if it is less */
if(userHealth<=0) {
return;
}
/* Drawing commands - drawRect(), drawBitmap(), etc are run here */
}
现在正常情况下,运行正常。但是当满足userHealth条件时,Canvas会在发送的最后一个命令和之前的命令之间不断交替。我知道没有调用draw函数,因为我在代码的那个区域使用了Log.d(),并且在满足条件后LogCat上没有出现任何消息。有人可以解释为什么会这样,解决方案会是什么?
答案 0 :(得分:0)
Canvas
是双缓冲或三缓冲的,不会在帧之间擦除。当您调用锁定/解锁时,您需要在先前渲染的缓冲区之间切换。
如果您将if(userHealth<=0)
测试移至run()
并使用它来避免调用锁定/解锁,则应获得所需的效果。
有关正在进行的内容的更长时间的解释,请参阅this post。
更新:我今天意识到我省略了一个细节(来自答案和随后的评论)。它并没有改变答案,但知道它可能是有用的。
lockCanvas()
方法采用可选的&#34;脏&#34; rect允许您进行部分更新。如果您使用此功能,Surface
能够跟踪前线&#34;刚刚渲染的缓冲区,系统会将前缓冲区的非脏内容复制到后缓冲区,作为锁定Surface
的一部分(参见Surface.cpp中的copyBlt()
)。
系统并不保证这会起作用,这就是&#34;脏&#34; rect是一个输入输出参数。如果前端缓冲区无法复制,则lock方法只会展开脏矩形以覆盖整个屏幕。在任何一种情况下,您的应用都有责任更新&#34;脏&#34; RECT;如果你没有,你会得到你观察到的效果。
这确实意味着Surface
在与Canvas
一起使用时明确尝试进行双重缓冲,这可以解释为什么您会看到两个帧交替而不是三个,即使SurfaceView
{1}}通常是三重缓冲的。 (自从我写这篇文章以来,我一直在唠叨这一事。)如果你不能快速生成足以需要三重缓冲的帧,那么它也可能是双缓冲的。