【Swift】SpriteKitの使い方。鳥ノードをパタパタさせながら移動方向に合わせて身体の角度を変える。(Swift 2.2、XCode 7.3)
今までの鳥ノード
前回記事までの鳥ノードは、ポーズや向きはまったく変わらないので、まるで壁に貼り付けた鳥のマグネットを指で動かしているかのような感覚だった。もう少し生きてる感が欲しい。
そこで、本記事ではノードのポーズや向きをアクションで変化させる方法を説明する。
以降の手順を行う前のXcodeプロジェクトをGitHubに置いたので、試してみる方はご利用下さい。
⇒「テスト用プロジェクト」
鳥ノードを配置し、ドラッグで移動できるようにしておいた。この段階では鳥のポーズや向きは変わらない。
羽ばたかせる
まずは鳥ノードをバタバタと羽ばたかせよう。羽を上げたときと、下げたときの2枚の画像を切り替えるアクションをループさせて羽ばたかせる。
SpriteKit Sceneファイル(以下、SKSファイル)に鳥ノードを配置しているので、まずはSKSファイルを編集して羽ばたかせてみよう。
下図赤枠のSKSファイルを選択するとシーンエディタが表示される。黄緑枠のボタンを押すと、アニメーションのタイムラインが下からニョキっと現れる。
下図紫枠のオブジェクトライブラリボタンを押して部品の一覧を表示する。一覧の中にある「AnimateWithTextures Action」をドラッグ&ドロップで鳥ノードのタイムラインに運ぶ(下図赤矢印)。
下図水色枠のメディアライブラリボタンを押して画像の一覧を表示する。黄枠のアトリビュートインスペクタボタンを押して設定画面を表示し、画像一覧の2つの茶鳥をTexturesにドラッグ&ドロップで入れる(下図赤矢印)。Durationに「0.2」を入力する。
ちなみに、アトリビュートインスペクタの設定画面が表示されない場合は、別のファイル(ViewController.swiftなど)に一旦表示を切り替えてからTextScene.sksに戻ると表示される。XCodeの表示上のバグと思われる(Swift 2.2、XCode 7.3で確認)。
タイムラインの左隅(下図赤枠)をクリックすると吹き出しのメニューが表示されるので「∞」を選択する。これで、鳥ノードの羽ばたきが無限で繰り返されるようになった。
以下は実際のプレイ動画
ソースコードで羽ばたきアクションを実装する場合は以下のコードのようにする。試してみる場合は、上記手順でSKSファイルに追加したアクションを削除してから行うこと。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { //SKSファイルに配置した鳥ノードを取得する。 birdBrown = self.childNodeWithName("bird") as? SKSpriteNode //画像2枚のテクスチャを作成する。 let img1 = SKTexture(imageNamed: "bird_brown") let img2 = SKTexture(imageNamed: "bird_brown2") //テクスチャを切り替えるアクションを作成する let action = SKAction.animateWithTextures([img1,img2], timePerFrame: 0.2) //無限ループのアクションにする。 let loopAction = SKAction.repeatActionForever(action) //アクションを実行する。 birdBrown.runAction(loopAction) } |
鳥の向きを変える
ずっと左を向いたままでは、右に移動したときは飛びながらバックしているように見えるので、右に移動したら右を向くように変更する。
TestScene.swiftのtouchesMovedメソッドを以下のコードに変更する。移動後と移動前のX座標の大小比較から鳥ノードの右向き、左向きを切り替えている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//画面タッチ移動時の呼び出しメソッド override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { //移動後の座標を取得する。 let location = touches.first!.locationInNode(self) //移動前の座標を取得する. let prevLocation = touches.first!.previousLocationInView(self.view) if(location.x - prevLocation.x > 0) { //右に移動した場合は右向きにする。 birdBrown.xScale = fabs(birdBrown.xScale) * -1.0 } else { //左に移動した場合は左向きにする。 birdBrown.xScale = fabs(birdBrown.xScale) } //移動後の座標に移動するアクションを作成する。 let action = SKAction.moveTo(CGPoint(x:location.x, y:location.y+20), duration:0.1) //アクションを実行する。 birdBrown.runAction(action) } |
以下は実際のプレイ動画
鳥の角度を変える
右または左を向くだけではなく、移動方向に体の角度を変えることで、もっと飛んでいる感を出そう。
角度の求めるには保存座標とタッチ座標の2つを利用する。逆三角関数(atan)メソッドに2つの座標を与えると基準点0からの角度がラジアンで取得できる。
取得した角度を使って鳥ノードを回転させるアクションを実行する。ただし、鳥ノードが右を向いている状況では回転させる角度が逆向きになるので注意が必要だ。鳥ノードを回転したら保存座標に今回のタッチ座標を保存する。
具体的にはTestScene.swiftを以下のコードに変更する。
touchesMovedメソッドの引数からタッチ座標と前回のタッチ座標を取得することができるが、この2つで角度を計算して回転させると、指の微弱な揺れで角度が急激に変わってしまうことがある。
そこで、タッチした座標を保存しておき、保存座標とタッチ座標の距離がXまたはY方向に10ポイント以上離れてから回転をするようにした。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
// // TestScene.swift // import Foundation import SpriteKit class TestScene:SKScene { var birdBrown:SKSpriteNode! //保存座標 var savePos:(x:CGFloat, y:CGFloat)! //現在シーン設定時の呼び出しメソッド override func didMoveToView(view: SKView) { //SKSファイルに配置した鳥ノードを取得する。 birdBrown = self.childNodeWithName("bird") as? SKSpriteNode //保存座標を鳥ノードの位置にしておく。 savePos = (birdBrown.position.x, birdBrown.position.y) } //画面タッチ移動時の呼び出しメソッド override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) { //タッチ座標を取得する。 let location = touches.first!.locationInNode(self) //前回保存座標とタッチ座標の角度を算出する。 let r = atan2(savePos.y - location.y, savePos.x - location.x) //前回保存座標よりXまたはY座標が10ポイント以上離れたか if(fabs(location.y - savePos.y) > 10.0 || fabs(location.x - savePos.x) > 10.0) { if(location.x - savePos.x > 0) { //右に移動した場合は右向きにする。 birdBrown.xScale = fabs(birdBrown.xScale) * -1.0 //回転のアクションを実行する。 let rotateAction = SKAction.rotateToAngle( r - CGFloat(M_PI), duration: 0) birdBrown.runAction(rotateAction) } else { //左に移動した場合は左向きにする。 birdBrown.xScale = fabs(birdBrown.xScale) //回転のアクションを実行する。 let rotateAction = SKAction.rotateToAngle(r , duration: 0) birdBrown.runAction(rotateAction) } //座標を保存する. savePos = (location.x, location.y) } //タッチ座標に移動するアクションを実行する。 let action = SKAction.moveTo(CGPoint(x:location.x, y:location.y+20), duration:0.1) birdBrown.runAction(action) } } |
以下は実際のプレイ動画
羽ばたきを止める
ループ実行している鳥の羽ばたきのアクションを止めるにはremoveAllActionメソッドを利用する。
以下のコードは画面タッチが終了した時点で鳥の羽ばたきを停止し、鳥ノードに物理ボディを設定して重力をかけるようにした。
1 2 3 4 5 6 7 8 9 10 |
//タッチ終了時の呼び出しメソッド override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) { //アクションを停止する。 birdBrown.removeAllActions() //物理ボディを設定して重力をかける。 birdBrown.physicsBody = SKPhysicsBody(texture: birdBrown.texture!, size: birdBrown.size) } |
以下は実際のプレイ動画