SpriteKit applyImpulse不影响Sprite

时间:2019-02-20 06:47:08

标签: ios swift sprite-kit skphysicsbody

我有一个类型为Skier的播放器节点,我想通过触摸和拖动类似于this tutorial在x轴上移动。我将播放器节点添加到场景中,并且它的物理主体将isDynamic设置为true,但是由于某些原因,当我触摸并拖动播放器时,它不会移动。我究竟做错了什么?这是我的GameScene和我的Skier课程:

滑雪者:

class Skier: SKSpriteNode {
    let playerTexture = SKTexture(imageNamed: "snowmanFancy_NE")
    let playerSize = CGSize(width: 24, height: 40)

    init () {
        super.init(texture: playerTexture, color: UIColor.clear, size: playerSize)
        self.name = "player"
        setPhysics()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setPhysics(){
        self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        self.physicsBody? = SKPhysicsBody(rectangleOf: size)
        self.physicsBody?.categoryBitMask = PhysicsCategory.player
        self.physicsBody?.contactTestBitMask = PhysicsCategory.tree | 
        PhysicsCategory.rock | PhysicsCategory.cabin | PhysicsCategory.snowman | 
        PhysicsCategory.marker
        self.physicsBody?.collisionBitMask = 0
        self.physicsBody?.allowsRotation = false
        self.physicsBody?.angularDamping = 0
        self.physicsBody?.isDynamic = true
    }
}

GameScene:

class GameScene: SKScene, SKPhysicsContactDelegate {
    var lastTouch: CGPoint? = nil

    var world = SKNode()
    var cam = SKCameraNode()

    var player = Skier()
    let playerDefaultYInset : CGFloat = 350

    var sceneVelocity = CGVector(dx: 0, dy: -170)
    var zPositionCounter: CGFloat = 0

    override func didMove(to view: SKView) {
        //Set up the scene
        self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
        backgroundColor = SKColor.white

        //Add top-level world node to the scene
        self.addChild(world)

        self.physicsWorld.contactDelegate = self

        //Add player to scene
        spawnPlayer()
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        if let location = touch?.location(in: self) {
            lastTouch = location
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        let touch = touches.first
        if let location = touch?.location(in: self) {
            lastTouch = location
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        lastTouch = nil
    }

    override func update(_ currentTime: TimeInterval) {
        // Only add an impulse if there's a lastTouch stored
        if let touch = lastTouch {
            let impulseVector = CGVector(dx: touch.x - player.position.x, dy: 0)
            // If myShip starts moving too fast or too slow, you can multiply impulseVector by a constant or clamp its range
            player.physicsBody?.applyImpulse(impulseVector)
        }
    }

    func spawnPlayer() {
        player.position = CGPoint(x: 0, y: (-self.frame.height / 2) + playerDefaultYInset)
        player.zPosition = CGFloat(Int.min)
        world.addChild(player)
    }
}

1 个答案:

答案 0 :(得分:0)

我弄清楚我做错了什么。当我为Skier课程设置物理身体时,我为该物理身体分配了一个可选的内容:

self.physicsBody? = SKPhysicsBody(rectangleOf: size)

因此,实际上未将物理主体分配给该精灵。我将其更改为:

self.physicsBody = SKPhysicsBody(rectangleOf: playerSize)

,现在可以正常使用了。话虽这么说,对于任何其他尝试通过手指拖动精灵在场景中移动来达到类似效果的人,我最终都提出了一个简单得多的解决方案。我在touchesMoved方法中有此方法:

let touch = touches.first
    if let location = touch?.location(in: self) {
        let prev = touch?.previousLocation(in: self)
        let impulse = CGVector(dx: 0.02 * (location.x - (prev?.x)!), dy: 0)
        player.physicsBody?.applyImpulse(impulse)
}

它的工作原理完全不必担心更新,touchesBegan或touchesEnded方法。简单多了。