我使用“Hello World”Sprite-kit 模板做了一个小测试项目,其中有一个由这些帧组成的图集动画:
-
我想展示这个骑士和它的动画。
我想设置一个 DYNAMIC 物理体。
所以我使用了一个工具来分离单帧,我做了一个atlasc
文件夹,所以代码应该是:
import SpriteKit
class GameScene: SKScene {
var knight: SKSpriteNode!
var textures : [SKTexture] = [SKTexture]()
override func didMove(to view: SKView) {
self.physicsWorld.gravity = CGVector(dx:0, dy:-2)
let plist = "knight.plist"
let genericAtlas = SKTextureAtlas(named:plist)
let filename : String! = NSURL(fileURLWithPath: plist).deletingPathExtension!.lastPathComponent
for i in 0 ..< genericAtlas.textureNames.count
{
let textureName = (String(format:"%@%02d",filename,i))
textures.append(genericAtlas.textureNamed(textureName))
}
if textures.count>0 {
knight = SKSpriteNode(texture:textures.first)
knight.zPosition = 2
addChild(knight)
knight.position = CGPoint(x:self.frame.midX,y:self.frame.midY)
}
//
self.setPhysics()
let animation = SKAction.animate(with: textures, timePerFrame: 0.15, resize: true, restore: false)
knight.run(animation, withKey:"knight")
}
func setPhysics() {
knight.physicsBody = SKPhysicsBody.init(rectangleOf: knight.size)
knight.physicsBody?.isDynamic = false
}
}
输出是:
如您所见,这physicsBody
是静态的,不要尊重动画:这是正常的,因为在动画期间纹理会更改尺寸/大小,而我们不会更改physicsBody
在动作期间保持不变的。
遵循源代码,在 期间没有SKAction.animate
允许更改physicsBody
.
虽然我们使用:
/**
Creates an compound body that is the union of the bodies used to create it.
*/
public /*not inherited*/ init(bodies: [SKPhysicsBody])
为了为我们动画的每一帧创建身体,这些身体在场景中保持在一起,创造了一个丑陋的奇怪情况,如下图:
因此,正确的做法应该是在动画期间截取帧并动态更改physicsBody
。我们也可以使用update()
from 的方法SKScene
,但我正在考虑扩展。
我的想法是将animation
动作与 a结合起来SKAction.group
,制作另一个自定义动作来检查第一个动作的执行,拦截与当前数组匹配的帧knight.texture
并textures
更改physicsBody
启动外部方法,在这种情况下setPhysicsBody
。
然后,我写了这个:
extension SKAction {
class func animateWithDynamicPhysicsBody(animate:SKAction, key:String, textures:[SKTexture], duration: TimeInterval, launchMethod: @escaping ()->()) ->SKAction {
let interceptor = SKAction.customAction(withDuration: duration) { node, _ in
if node is SKSpriteNode {
let n = node as! SKSpriteNode
guard n.action(forKey: key) != nil else { return }
if textures.contains(n.texture!) {
let frameNum = textures.index(of: n.texture!)
print("frame number: \(frameNum)")
// Launch a method to change physicBody or do other things with frameNum
launchMethod()
}
}
}
return SKAction.group([animate,interceptor])
}
}
添加此扩展后,我们将代码的动画部分更改为:
//
self.setPhysics()
let animation = SKAction.animate(with: textures, timePerFrame: 0.15, resize: true, restore: false)
let interceptor = SKAction.animateWithDynamicPhysicsBody(animate: animation, key: "knight", textures: textures, duration: 60.0, launchMethod: self.setPhysics)
knight.run(interceptor,withKey:"knight")
}
func setPhysics() {
knight.physicsBody = SKPhysicsBody.init(rectangleOf: knight.size)
knight.physicsBody?.isDynamic = false
}
这终于奏效了,输出是:
您知道获得此结果的更好方法或更优雅的方法吗?