在我使用GLKit创建的应用程序中,我有一个滑块拼图,用户点击与空拼贴相邻的拼贴,并且拼贴滑动到新位置。为了减少我必须执行单个任务的方法数量,我决定尝试在一个循环中处理整个滑动动画。
- (void)slideSelectedTile
{
while (!self.selectedTile.hasFinishedMoving)
{
[self.selectedTile moveByVector:self.tileDisplacement];
[self render];
[NSThread sleepForTimeInterval:.1];
}
}
问题是渲染调用在此循环内部不起作用。只有在整个循环结束并且游戏到达下一个glkViewDrawInRect
调用时才会呈现图块,其中我也调用render
,其当然包含用于呈现每个图块的代码。
我已经检查过当前线程是我在循环中的主线程,并且我可以手动调用render而不需要它在任何类型的循环中并且它可以工作。我在这里做错了什么?
答案 0 :(得分:1)
你在这里做错了是你错过了整个概念。您的while循环将阻止您在屏幕上绘制和显示的线程。虽然缓冲区重新绘制了N次,但您的视图却没有。
一些快速修复可能是在render
方法上调用主线程上的执行选择器(并等待它完成)。这样你甚至可能会失去睡眠因素。另一种方法是创建另一个动画师线程,在该线程上将调用slideSelectedTile,但同样必须在主线程上调用render
。
在任何情况下,如果没有做出漂亮的代码设计,您将在以后遇到一些问题。您应该做的是让对象存储源位置,目标位置和当前位置。它应该实现一些move
方法,用插值计算当前位置:线性插值将是source + (target-source)*(currentTime/animationTime)
。在大多数情况下,currentTime
和animationTime
实际上可能是帧数,因为我希望动画在6帧中完成animationTime
为6而currentTime
迭代[ 0,6]并在currentTime==animationTime
时完成动画。因此,最后您可以调用类似animateTo:(CGPoint)location in:(NSInteger)frameCount
的内容,将currentTime
设置为零,将animationTime
设置为frameCount
,将source
设置为当前位置,target
} location
。
此时的问题是调用move
方法以及当前位置的内容:当前位置必须在render方法的主线程上使用。可以在一些新线程上调用move方法,您可以控制它调用它的频率,但也可以在render方法之前(或内部)的每一帧上调用它。
所以我的建议是在动画一些openGL驱动的代码时需要对render
方法进行一些重复调用,例如使用显示链接。使用此调用执行所有渲染,同时将所有移动分离到某些外部方法,该方法与渲染或openGL完全无关。这样,您就可以在单独的线程或同一个线程中控制移动。
关于使运动动画方法和插值复杂化:如果按照我描述的方式实现它,你将能够在动画中停止并将其动画到其他位置而不会出现任何问题。