Как я могу анимировать текстуру SKPhysicsBody из SKTextureAtlas - PullRequest
0 голосов
/ 07 января 2019

У меня есть SKTextureAtlas с 7 кадрами анимированного спрайта с прозрачным фоном.

Мне удалось использовать один кадр из атласа в качестве границ физического тела, но я хотел бы знать, как, если это возможно, заставить физическое тело обновлять свой контур для каждого кадра в атласе .

Здесь у меня есть физическое тело, использующее фрейм под названием «Run0», и оно применяется правильно. Я просто хотел посмотреть, возможно ли это, или было бы совершенно нецелесообразно, чтобы физическое тело использовало каждый кадр от «Run0» до «Run7» в атласе.

Изображение физического тела с контуром "Run0"

Это код, над которым я работаю:

import SpriteKit

класс GameScene: 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))

}

}

1 Ответ

0 голосов
/ 08 января 2019

Один из способов добиться этого - пользовательский 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 ($0, timePerFrame)
}

dogSpriteNode = SKSpriteNode(texture: dogFrames.first)
let dogAnimationAction = SKAction.animateTexturesWithPhysics(dogFrames)
dogSpriteNode.run(dogAnimationAction)
...