昨天一天把SKAction常見的用法都實操過了一遍,基本都實現(xiàn)了sample code中要實現(xiàn)的需求产喉。先總結(jié)如下:
- 最基本的SKAction.move(to:)和 SKAction.move(by:)用法
學過英語的都從字面上能理解到move to和move by的區(qū)別矫限,
move to代表具體移動到哪個位置CGPoint彭雾,
而move by的話是指sprite移動的矢量offset(大概可以這樣理解)沪铭。
這個太簡單了,就不舉例了峦朗。
- Sequence action
其實sequence action就是將一個SKAction數(shù)組里面的action依次執(zhí)行。首先依次定義好單獨的SKAction排龄,然后通過以下方法將之前定義好單獨的SKAction append進來
let actionSequence:[SKAction] = []
actionSequence.append(action)
然后通過以下方法依次執(zhí)行各個action:
run.SKAction(SKAction.sequence(actionAction))
- Wait-for-duration action
在執(zhí)行sequence的SKAction時波势,有時需要在兩個動作之間有一些間歇時間,我們可以通過以下方法實現(xiàn):
let action1 = SKAction()
let action2 = SKAction()
let actionWait = SKAction.wait(forDuration: 2.0)
zombie.run(SKAction.sequence([action1,actionWait,action2]))
然后action1和action2在執(zhí)行時橄维,中間就會停頓2秒
- Run-block action
如果想在sequence里面加一些打log的動作尺铣,可通過以下方法實現(xiàn):
let logMessage = SKAction.run() {
print("Reached bottom!")
}
-
Reversing actions
所謂的reverse,就是把可逆的action進行反向操作争舞,比如move(by:)凛忿,如下圖所示
image.png
用法如下:
let reverseMid = actionMidMove.reversed()
- Repeat & RepeatForever actions
前者是指定重復(fù)動作的次數(shù),用法如下:
let repeatAction = SKAction.repeat(SKAction, count: Int)
后者是永遠重復(fù)竞川,用法如下:
let repeatAction = SKAction.repeatForever(SKAction)
- 在教程中間店溢,插了一個取最小值與最大值之間隨機數(shù)的算法,如下:
extension CGFloat {
static func random() -> CGFloat {
//arc4random()是返回UInt32以內(nèi)的一個隨機數(shù)流译,UInt32.max是UInt32內(nèi)的最大值逞怨,前者除以后者得到了一個0-1之間的隨機數(shù)。
return CGFloat(Float(arc4random()) / Float(UInt32.max))
}
static func random(min: CGFloat, max: CGFloat) -> CGFloat {
//首先斷言最小值應(yīng)該小于最大值福澡,然后下面這個公式應(yīng)該就不用贅述了
assert(min < max)
return CGFloat.random() * (max - min) + min
}
}
- 在該section中叠赦,sample創(chuàng)建了很多元素,比如僵尸啊,敵人啊除秀,貓貓狗狗之類的糯累,他們都是用了一個spawnXXX()的方法將sprite素材加載出來、初始化位置(可能是固定的册踩,也可能位置是隨機的)泳姐、然后匹配一些初始化的動作。如果場景初始化的時候需要他們出現(xiàn)暂吉,則直接將spawnXXX()的方法在didMove()中進行調(diào)用即可胖秒,比如如下所示的方法:
func spawnEnemy() {
let enemy = SKSpriteNode(imageNamed: "enemy")
enemy.position = CGPoint(
x: size.width + enemy.size.width/2,
y: CGFloat.random(
min: playableRect.minY + enemy.size.height/2,
max: playableRect.maxY - enemy.size.height/2))
addChild(enemy)
let actionMove =
SKAction.moveTo(x: -enemy.size.width/2, duration: 2.0)
enemy.run(actionMove)
}
9.在創(chuàng)建敵人的時候使用了弱引用weak reference,原文的解釋如下:
Note: You are using a weak reference to self here. Otherwise the closure passed to run(_ block:) will create a strong reference cycle and result in a memory leak.
暫時對內(nèi)存泄漏的了解不是太多慕的,先暫時知其然吧阎肝,后面再來看weak/strong reference的專題文章。
run(SKAction.repeatForever(
SKAction.sequence([SKAction.run() { [weak self] in
self?.spawnEnemy()
},
SKAction.wait(forDuration: 2.0)])))
10.Remove-from-parent action
這個方法就是不用sprite的時候無情干掉肮街,免得占用內(nèi)存风题,浪費資源,用法如下:
let actionRemove = SKAction.removeFromParent()
enemy.run(SKAction.sequence([actionMove, actionRemove]))
這個方法removeFromParent()顧名思義就是從他的父節(jié)點中移除他嫉父,不僅適用于SKAction也適用于node節(jié)點的移除
- Animation action
這個就是序列幀素材的動畫action沛硅,用法如下:
// 1
var textures:[SKTexture] = []
// 2
for i in 1...4 {
textures.append(SKTexture(imageNamed: "zombie\(i)"))
}
// 3
textures.append(textures[2])
textures.append(textures[1])
// 4
zombieAnimation = SKAction.animate(with: textures,
timePerFrame: 0.1)
//創(chuàng)建好動畫后,就直接在sprite節(jié)點run這個動畫即可
zombie.run(SKAction.repeatForever(zombieAnimation))
- Stop animation
用過一個key介質(zhì)來控制動畫的開始和停止
func startZombieAnimation() {
if zombie.action(forKey: "animation") == nil {
zombie.run(
SKAction.repeatForever(zombieAnimation),
withKey: "animation")
} }
func stopZombieAnimation() {
zombie.removeAction(forKey: "animation")
}
Scale actions
初始化scale
cat.setScale(0)
然后就是scale(to:) scale(by:)Rotate actions
rotate(byAngle: )
rotate(toAngle: )
注:swift中π的用法為Double.piGroup actions
之前學到的actions都是串行的绕辖,如果我們想讓多個動作并行摇肌,應(yīng)該怎么做呢?比如sample項目中的小貓引镊,我們要他在rotate的同時朦蕴,也要scale,那么group action的用法就派上用場了弟头,方法如下:
//fullScale為scale的action吩抓, fullWiggle為rotate的action
let group = SKAction.group([fullScale, fullWiggle])
15.Collision detection
因為SK中有強大的物理引擎碰撞檢測,所以我就打算跳過這個不學赴恨,所以此處略(不過還是把sample code貼進來做note),看了一下下面的sample code疹娶,大概的意思就是通過frame.intersects看不同sprite之間的交集,如果交集上了伦连,就算是碰撞了
func zombieHit(cat: SKSpriteNode) {
cat.removeFromParent()
}
func zombieHit(enemy: SKSpriteNode) {
enemy.removeFromParent()
}
func checkCollisions() {
var hitCats: [SKSpriteNode] = []
enumerateChildNodes(withName: "cat") { node, _ in
let cat = node as! SKSpriteNode
if cat.frame.intersects(self.zombie.frame) {
hitCats.append(cat)
}
}
for cat in hitCats {
zombieHit(cat: cat)
}
var hitEnemies: [SKSpriteNode] = []
enumerateChildNodes(withName: "enemy") { node, _ in
let enemy = node as! SKSpriteNode
if node.frame.insetBy(dx: 20, dy: 20).intersects(
self.zombie.frame) {
hitEnemies.append(enemy)
}
}
for enemy in hitEnemies {
zombieHit(enemy: enemy)
}
16.Sound actions
播放聲音雨饺,用法如下:
run(SKAction.playSoundFileNamed("hitCat.wav",
waitForCompletion: false))
好了,SKAction的筆記大概就記到這了惑淳,本Section后還有三個challenges额港,現(xiàn)在就去完成它們。
PS:中英文夾雜做筆記切換好累啊歧焦,從下一篇起移斩,嘗試使用英文來記了,順便也可以練習丟了很久的英文寫作。