iOS 5.xv 6.xの違いについて話すことはできませんが、を使用するときはCADisplayLink
、反復ごとに「xピクセル/ポイントを移動する」などのハードコーディングを行うことはありませんtimestamp
。私の初期timestamp
と現在の間timestamp
)そして、経過したフレーム数ではなく、経過した時間に基づいて位置を計算します。このように、フレームレートはモーションの速度に影響を与えるのではなく、モーションの滑らかさに影響を与えます。(そして、30と29の違いは見分けがつかない可能性があります。)
CADisplayLinkクラスリファレンスから引用するには:
表示リンクが実行ループに関連付けられると、画面のコンテンツを更新する必要があるときに、ターゲットのセレクターが呼び出されます。ターゲットは、表示リンクのタイムスタンププロパティを読み取って、前のフレームが表示された時刻を取得できます。たとえば、映画を表示するアプリケーションは、タイムスタンプを使用して、次に表示されるビデオフレームを計算する場合があります。独自のアニメーションを実行するアプリケーションは、タイムスタンプを使用して、表示されるオブジェクトが次のフレームのどこにどのように表示されるかを決定する場合があります。期間_プロパティは、フレーム間の時間を提供します。アプリケーションでこの値を使用して、表示のフレームレート、次のフレームが表示されるおおよその時間を計算し、次のフレームが表示に間に合うように描画動作を調整できます。
ランダムな例として、ここUIBezierPath
では、経過した秒数をパラメーターとして使用してアニメーション化しています。
または、一連のUIImage
フレームを処理している場合は、次のようにフレーム番号を計算できます。
@property (nonatomic) CFTimeInterval firstTimestamp;
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
if (!self.firstTimestamp)
self.firstTimestamp = displayLink.timestamp;
CFTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp);
NSInteger frameNumber = (NSInteger)(elapsed * kFramesPerSecond) % kMaxNumberOfFrames;
// now do whatever you want with this frame number
}
または、フレームを失うリスクを回避するために、先に進んでこれを60 fpsで実行し、フレームを更新する必要があるかどうかを判断するだけで、フレームをドロップするリスクを減らすことができます。
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
if (!self.firstTimestamp)
self.firstTimestamp = displayLink.timestamp;
CFTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp);
NSInteger frameNumber = (NSInteger)(elapsed * kFramesPerSecond) % kMaxNumberOfFrames;
if (frameNumber != self.lastFrame)
{
// do whatever you want with this frame number
...
// now update the "lastFrame" number property
self.lastFrame = frameNumber;
}
}
しかし、多くの場合、フレーム番号はまったく必要ありません。たとえば、UIView
aを円で移動するには、次のようにします。
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
if (!self.firstTimestamp)
self.firstTimestamp = displayLink.timestamp;
CFTimeInterval elapsed = (displayLink.timestamp - self.firstTimestamp);
self.animatedView.center = [self centerAtElapsed:elapsed];
}
- (CGPoint)centerAtElapsed:(CFTimeInterval)elapsed
{
CGFloat radius = self.view.bounds.size.width / 2.0;
return CGPointMake(radius + sin(elapsed) * radius,
radius + cos(elapsed) * radius);
}
ちなみに、計測器を使用してフレームレートを測定すると、実際のデバイスよりも遅く見える場合があります。マットのコメントとして、正確なフレームレートを得るには、リリースビルドを使用して実際のデバイスでプログラムで測定する必要があります。