この記事はQuadアドベントカレンダー10日目の記事です。
前回からの続きです。
別スレッドでループを作ることができたので、ちょっと試してみたいと思います。動くも飲みながらでないとモチベーションも下がってしまうので...
シンプルエンジンクラスを作る
簡易なエンジンクラスを作ります。シングルトンかstaticクラスがやりやすいと思います。
class SimpleAnimationEngine {
public static let shared: SimpleAnimationEngine = SimpleAnimationEngine()
private var thread:Thread?
private var isRunning:Bool = true
private var fps:TimeInterval = 0
private var displayLink:CADisplayLink?
}
とりあえずこんな感じ。
必要なインターフェイスを定義を追加
まずは、実行と停止を用意します。
func start() -> Void {
self.isRunning = true
self.thread = Thread(target: self, selector: #selector(self.threadLoop(_:)), object: nil)
self.thread?.start()
}
func stop() -> Void {
self.isRunning = false
self.displayLink?.remove(from: RunLoop.current, forMode: .defaultRunLoopMode)
self.displayLink = nil
}
ループ部分は前回と同じです。
@objc func threadLoop(_ sender:AnyObject) -> Void {
self.displayLink = CADisplayLink(target: self, selector: #selector(self.engineLoop(_:)))
self.displayLink?.preferredFramesPerSecond = Int(self.fps)
self.displayLink?.add(to: RunLoop.current, forMode: .defaultRunLoopMode)
while self.isRunning {
RunLoop.current.run(until: Date(timeIntervalSinceNow: 1/fps))
}
}
delegateを用意する
アニメーションは同時に複数実行することもあると思うので、delegate用に配列を用意します。
private var listeners:[EnableAnimation] = []
プロトコロルも定義します。
protocol EnableAnimation {
func update() -> Void
func draw() -> Void
}
登録メソッドを用意します。
func addAnimation(listener:EnableAnimation) -> Void {
self.listeners.append(listener)
}
updateとdrawの追加
数値計算と描画のメソッドを追加します。登録されているオブジェクトのメソッドを順番に実行しています。
@objc func engineLoop(_ sender:AnyObject) -> Void {
self.update()
self.draw()
}
private func update() -> Void {
self.listeners.forEach { (animation: EnableAnimation) in
animation.update()
}
}
private func draw() -> Void {
self.listeners.forEach { (animation: EnableAnimation) in
animation.draw()
}
}
とりあえず準備はできました。あとは、EnableAnimationを実装した型を用意して試すだけです。
試してみる
Engineのインスタンスを取得
var engine:SimpleAnimationEngine = SimpleAnimationEngine.shared
FPSを設定し、実行。
self.engine.initalize(fps: 60)
self.engine.addAnimation("ここでEnableAnimation型のオブジェクトを渡します。")
self.engine.start()
サンプルも作りました。
簡単なサンプルを作ってみました。