WWDC 2017 の SceneKit サンプル Fox 2 を調べる その14
Character.swift 過去の記事
今回は Character.swift での他の関数とプロパティを見てゆく。
node
Character クラスの大本となる characterNode ノードを返す。
GameController.swift 上でこの Character クラスのイニシャライズなどの設定し、 こちらを使いノードを取得して Fox2 のシーンのルートノードに追加する。
var node: SCNNode! { return characterNode }
queueResetCharacterPosition()
Max がマップ外に出て Y 座標の値が minAltitude より小さくなった場合、
Max の位置をリセットするフラグを立てる関数。
func queueResetCharacterPosition() { shouldResetCharacterPosition = true }
playFootStep()
walkAnimation のアニメーションの際にアニメーションイベントで呼ばれる足音を再生させる関数。
hitTestWithSegment で取得した地面のジオメトリ groundNode が存在していて、isWalking が true の場合に足跡の音をランダムで足音の入った配列を再生する。
ここでの乱数設定では randSnd は 0 〜 19 の範囲になり、stepSoundIndex は min を使用して配列の総数である 9 と randSnd を比較して、少ない方を取るため、9 番目の音が半数以上になる。
func playFootStep() { if groundNode != nil && isWalking { let randSnd: Int = Int(Float(arc4random()) / Float(RAND_MAX) * Float(Character.stepsCount)) let stepSoundIndex: Int = min(Character.stepsCount - 1, randSnd) characterNode.runAction(SCNAction.playAudio( steps[stepSoundIndex], waitForCompletion: false)) } }
playJumpSound()
jumpAnimation のアニメーションの際にアニメーションイベントで呼ばれるジャンプ音を再生させる関数。
func playJumpSound() { characterNode!.runAction(SCNAction.playAudio(jumpSound, waitForCompletion: false)) }
playAttackSound()
spinAnimation のアニメーションの際にアニメーションイベントで呼ばれる攻撃音を再生させる関数。
func playAttackSound() { characterNode!.runAction(SCNAction.playAudio(attackSound, waitForCompletion: false)) }
isBurning
Max 溶岩に入り燃えているかを表すフラグ。 値をセットした際、過去の値と同じならばスルーし、walkSpeed の値の入れ替えを行う。
溶岩に入っている場合 isBurning が true になり、
true の場合以下の順番で処理がされる。
- catchFireSound の再生
- ouchSound の再生
- Max の点滅(false になるまで繰り返す)
- 白煙を出す whiteSmokeEmitter のパーティクルを birthRate = 0 で再生停止
- fireEmitter の birthRate に本来の値 fireEmitterBirthRate を入れパーティクルを再生開始
- smokeEmitter の birthRate に本来の値 smokeEmitterBirthRate を入れパーティクルを再生開始
false の場合以下の順番で処理がされる。
- Max の全ての音の再生を停止。
- Max の全てのアクション再生を停止。
- Max の透明度を戻す
- aahSound の SE 再生
- SCNTransaction で白煙の whiteSmokeEmitter の birthRate に本来の値 whiteSmokeEmitterBirthRate を入れパーティクルを再生開始
- さらに fireEmitter.birthRate、smokeEmitter.birthRate に 0 を入れ再生停止。
- もう一つの SCNTransaction で5秒後に whiteSmokeEmitter の birthRate に 0 を入れて再生を止める
var isBurning: Bool = false { didSet { if isBurning == oldValue { return } let oldSpeed = walkSpeed walkSpeed = oldSpeed if isBurning { model.runAction(SCNAction.sequence([ SCNAction.playAudio(catchFireSound, waitForCompletion: false), SCNAction.playAudio(ouchSound, waitForCompletion: false), SCNAction.repeatForever(SCNAction.sequence([ SCNAction.fadeOpacity(to: 0.01, duration: 0.1), SCNAction.fadeOpacity(to: 1.0, duration: 0.1) ])) ])) whiteSmokeEmitter.birthRate = 0 fireEmitter.birthRate = fireEmitterBirthRate smokeEmitter.birthRate = smokeEmitterBirthRate } else { model.removeAllAudioPlayers() model.removeAllActions() model.opacity = 1.0 model.runAction(SCNAction.playAudio(aahSound, waitForCompletion: false)) SCNTransaction.begin() SCNTransaction.animationDuration = 0.0 whiteSmokeEmitter.birthRate = whiteSmokeEmitterBirthRate fireEmitter.birthRate = 0 smokeEmitter.birthRate = 0 SCNTransaction.commit() SCNTransaction.begin() SCNTransaction.animationDuration = 5.0 whiteSmokeEmitter.birthRate = 0 SCNTransaction.commit() } } }
directionAngle
ユーザー操作から Max の向きを変え Y 軸に directionAngle を渡し 0.1 えアニメーションさせる。
usesShortestUnitArc が true になっているため、 現在の角度から最も近い角度へ回転する。
(例えば、359度に回転させたい場合は反時計回りで359度ではなく、時計回りに-1度回転する)
private var directionAngle: CGFloat = 0.0 { didSet { characterOrientation.runAction( SCNAction.rotateTo(x: 0.0, y: directionAngle, z: 0.0, duration: 0.1, usesShortestUnitArc:true)) } }
次回は Character クラスの update 関数を見てゆく。