我怎样才能从 SKTextureAtlas 动画 SKPhysicsBody 纹理
How can I animate a SKPhysicsBody texture from an SKTextureAtlas
我有一个 SKTextureAtlas,带有 7 帧透明背景的动画精灵。
我已经能够使用图集中的单个帧作为物理体的边界,但我想知道,如果可能的话,如何让物理体更新其每一帧的轮廓地图集。
这里我的物理体使用了名为 "Run0" 的框架,并且应用正确。我只是想看看是否有可能,或者让物理体使用图集中从 "Run0" 到 "Run7" 的每一帧是否完全不切实际。
Image of physics body with the outline of "Run0"
这是我正在处理的代码:
import SpriteKit
class 游戏场景:SKScene {
let dogSpriteNode = SKSpriteNode(imageNamed: "Run0")
var dogFrames = [SKTexture]()
override func didMove(to view: SKView) {
physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
dogSpriteNode.setScale(0.1)
dogSpriteNode.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(dogSpriteNode)
let textureAtlas = SKTextureAtlas(named: "Dog Frames")
for index in 0..<textureAtlas.textureNames.count {
let textureName = "Run" + String(index)
dogFrames.append(textureAtlas.textureNamed(textureName))
}
dogSpriteNode.physicsBody = SKPhysicsBody(
texture: textureAtlas.textureNamed("Run0"),
alphaThreshold: 0.5,
size: dogSpriteNode.frame.size)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
dogSpriteNode.run(SKAction.group([SKAction.repeatForever(SKAction.animate(with: dogFrames, timePerFrame: 0.1))]))
dogSpriteNode.run(SKAction.applyImpulse(CGVector(dx: 0, dy: 1000), duration: 0.1))
}
}
实现此目的的一种方法是使用自定义 SKAction
:
extension SKAction {
public class func animateTexturesWithPhysics(_ frames: [(texture: SKTexture, duration: TimeInterval)], repeatForever: Bool=true) -> SKAction {
var actions: [SKAction] = []
for frame in frames {
// define a custom action for each frame
let customAction = SKAction.customAction(withDuration: frame.duration) { node, _ in
// if the action target is a sprite node, apply the texture & physics
if node is SKSpriteNode {
let setTextureGroup = SKAction.group([
SKAction.setTexture(frame.texture, resize: false),
SKAction.wait(forDuration: frame.duration),
SKAction.run {
node.physicsBody = SKPhysicsBody(texture: frame.texture, alphaThreshold: 0.5, size: frame.texture.size())
// add physics attributes here
}
])
node.run(setTextureGroup)
}
}
actions.append(customAction)
}
// add the repeating action
if (repeatForever == true) {
return SKAction.repeatForever(SKAction.sequence(actions))
}
return SKAction.sequence(actions)
}
}
要实现它,您需要创建一个帧 + 持续时间数组并将动作应用于精灵:
typealias Frame = (texture: SKTexture, duration: TimeInterval)
let timePerFrame: TimeInterval = 0.1
let dogFrames: [Frame] = dogTextures.map {
return ([=11=], timePerFrame)
}
dogSpriteNode = SKSpriteNode(texture: dogFrames.first)
let dogAnimationAction = SKAction.animateTexturesWithPhysics(dogFrames)
dogSpriteNode.run(dogAnimationAction)
我有一个 SKTextureAtlas,带有 7 帧透明背景的动画精灵。
我已经能够使用图集中的单个帧作为物理体的边界,但我想知道,如果可能的话,如何让物理体更新其每一帧的轮廓地图集。
这里我的物理体使用了名为 "Run0" 的框架,并且应用正确。我只是想看看是否有可能,或者让物理体使用图集中从 "Run0" 到 "Run7" 的每一帧是否完全不切实际。
Image of physics body with the outline of "Run0"
这是我正在处理的代码:
import SpriteKit
class 游戏场景:SKScene {
let dogSpriteNode = SKSpriteNode(imageNamed: "Run0")
var dogFrames = [SKTexture]()
override func didMove(to view: SKView) {
physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
dogSpriteNode.setScale(0.1)
dogSpriteNode.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(dogSpriteNode)
let textureAtlas = SKTextureAtlas(named: "Dog Frames")
for index in 0..<textureAtlas.textureNames.count {
let textureName = "Run" + String(index)
dogFrames.append(textureAtlas.textureNamed(textureName))
}
dogSpriteNode.physicsBody = SKPhysicsBody(
texture: textureAtlas.textureNamed("Run0"),
alphaThreshold: 0.5,
size: dogSpriteNode.frame.size)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
dogSpriteNode.run(SKAction.group([SKAction.repeatForever(SKAction.animate(with: dogFrames, timePerFrame: 0.1))]))
dogSpriteNode.run(SKAction.applyImpulse(CGVector(dx: 0, dy: 1000), duration: 0.1))
}
}
实现此目的的一种方法是使用自定义 SKAction
:
extension SKAction {
public class func animateTexturesWithPhysics(_ frames: [(texture: SKTexture, duration: TimeInterval)], repeatForever: Bool=true) -> SKAction {
var actions: [SKAction] = []
for frame in frames {
// define a custom action for each frame
let customAction = SKAction.customAction(withDuration: frame.duration) { node, _ in
// if the action target is a sprite node, apply the texture & physics
if node is SKSpriteNode {
let setTextureGroup = SKAction.group([
SKAction.setTexture(frame.texture, resize: false),
SKAction.wait(forDuration: frame.duration),
SKAction.run {
node.physicsBody = SKPhysicsBody(texture: frame.texture, alphaThreshold: 0.5, size: frame.texture.size())
// add physics attributes here
}
])
node.run(setTextureGroup)
}
}
actions.append(customAction)
}
// add the repeating action
if (repeatForever == true) {
return SKAction.repeatForever(SKAction.sequence(actions))
}
return SKAction.sequence(actions)
}
}
要实现它,您需要创建一个帧 + 持续时间数组并将动作应用于精灵:
typealias Frame = (texture: SKTexture, duration: TimeInterval)
let timePerFrame: TimeInterval = 0.1
let dogFrames: [Frame] = dogTextures.map {
return ([=11=], timePerFrame)
}
dogSpriteNode = SKSpriteNode(texture: dogFrames.first)
let dogAnimationAction = SKAction.animateTexturesWithPhysics(dogFrames)
dogSpriteNode.run(dogAnimationAction)