Edited at

SpriteKitでのアニメーションまとめ

More than 3 years have passed since last update.

SpriteKitをつかってアニメーションをほいほいしたので、色々まとめ。

9.5割くらいSKActionのまとめです。

Swiftです。

SpriteKitではSKActionをつくって、それらをつなげたり同時につかったりすることでアニメーションをつくっていく感じでした。


ライブラリについて

SKActionはtimingModeというプロパティでEaseIn/Outなどが設定できるが、

細かいEasingは指定できないので、SpriteKitEasingSwiftというライブラリを使用した。

Objective-Cのこちらのライブラリが元になっているのでObjective-Cのかたはそちらをどうぞ


アニメーションつなげる

//SpriteKitEasingSwiftを使用したフェードイン

let fadeIn = SKEase.fade(easeFunction: .CurveTypeCubic, easeType: .EaseTypeIn, time: 1, fromValue: 0, toValue: 1)
//0.5s待つ
let delay = SKAction.waitForDuration(NSTimeInterval(0.5))
//最終的なアクション
let action = SKAction.sequence([delay, fadeIn])

node.runAction(action)

アクションをつなげる時は

SKAction.sequence([SKAction, SKAction, ...])

を使う。上のケースは0.5秒待った後に、1秒掛けてSKNodeのalphaを0から1に変える。


同時にアニメーションする

let expand  = SKEase.scale(easeFunction: .CurveTypeCubic, easeType: .EaseTypeIn, time: 0.5, fromValue:0, toValue: 1)

let fadeIn = SKEase.fade(easeFunction: .CurveTypeCubic, easeType: .EaseTypeIn, time: 0.5, fromValue: 0, toValue: 1)
let action = SKAction.group([fadeIn, expand])

trg.runAction(action)

アニメーションを同時にする時は

SKAction.group([SKAction, SKAction, ...])

を使う。上のケースはスケールとフェードインを0.5秒間に同時に行っている。


どっちも

let expand  = SKEase.scale(easeFunction: .CurveTypeCubic, easeType: .EaseTypeIn, time: 0.5, fromValue: 0, toValue: 1)

let fadeIn = SKEase.fade(easeFunction: .CurveTypeCubic, easeType: .EaseTypeIn, time: 0.5, fromValue: 0, toValue: 1)
let delay = SKAction.waitForDuration(NSTimeInterval(delayTime))
let action = SKAction.sequence([delay, SKAction.group([fadeIn, expand])])

trg.runAction(action)

もちろん

SKAction.sequence([SKAction, SKAction.group([SKAction, SKAction])])

みたいなこともできる


関数化してみる

func moveAction(from:CGPoint, to:CGPoint, delayTime:NSTimeInterval) -> SKAction{

let move = SKEase.move(easeFunction: .CurveTypeLinear, easeType: .EaseTypeIn, time: 0.2, fromPoint: from, toPoint: to)
let delay = SKAction.waitForDuration(NSTimeInterval(delayTime))
let action = SKAction.sequence([delay, move])

return action
}

最終的に、よく使うものは関数化して使っていたけど、どうなんだろう。

もっといいやりかたあるかもしれない。

アニメーションをつくったりしていくとコードはどんどん冗長になっていく印象があったので

頑張って整えるようには心がけた(つもり)。


Action終わった後に〇〇する

let action = SKAction.sequence([delay, fadeIn, SKAction.runBlock({ [weak self] in

//hogehoge
self?.addChild(hogehoge)
}) ])

SKAction.runBlockを使った。


マスクアニメーション

SKSpriteの一部分をマスクして、徐々に見える。みたいなことがしたく、少し困ったのでtipsとして紹介します。

画像の一部分をマスクするには、SKCropNodeを使います。

SKCropNodeはmaskNodeにしていしたspriteが 描画されている部分だけ見える ようになる機能があります。

イラレで画像の上に、平面置いてクリッピングマスクするような感覚です。

コードに書くと以下の感じです。

//マスクする方

var mask = SKSpriteNode()
//マスクされる方
var line = SKSpriteNode(imageNamed: "line")

//黒い平面のマスクしたいスプライトと同じ大きさのスプライトをつくる
mask.color = UIColor(red: 0, green: 0, blue: 0, alpha: 1)
mask.size = CGSizeMake(line.size.width/2, line.size.height/2)
mask.xScale = 0
mask.position = CGPoint(x: 0, y: 0)

//cropNode
let node = SKCropNode()
//masknodeにマスクする側のspriteを指定して、マスクされる側をaddChildする
node.maskNode = mask
node.addChild(line)
self.addChild(node)

//マスクアニメーション
let expandX = SKEase.scaleX(easeFunction: .CurveTypeCubic, easeType: .EaseTypeIn, time: 0.5, fromValue: 0, toValue: 1)
mask.runAction(expandX)


pngアニメーション

最終手段はpngの連番画像にしてaltasつくってアニメーションにするという手段

SKTextureAtlasを使う準備のようなものは省略

var list : [SKTexture] = []

let loading:SKTextureAtlas = SKTextureAtlas(named: "atlas")
//90 = 画像の枚数
//hoge_01.png, hoge_02.png, ..., hoge_89.pngという画像がある想定
for var i = 0; i < 90; ++i {
//0埋め
let num = String(format: "%02d", i)
list.append(loading.textureNamed("hoge_"+num))
}

spriteAnim = SKSpriteNode(texture: list[0])
spriteAnim.position = CGPoint(x: 0, y: 0)
spriteAnim.zPosition = 1.0
addChild(spriteAnim)

//アニメーション
let loadAction:SKAction = SKAction.animateWithTextures(loadingList, timePerFrame: 0.03, resize: false, restore: false)
spriteAnim.runAction(loadingAction)