Rotate an object in its direction of motion

﹥>﹥吖頭↗ 提交于 2019-12-18 04:27:28

问题


Is there a relatively simple way to rotate SKSpriteNode so that it is always facing the direction it is moving? My class Gamescene has a system of objects with their relative physicsbodies that apply impulses on each other when they collide. This makes it relatively difficult to keep track of exactly what direction an object is moving in. Some of the objects are also not regularly shaped, which makes things a bit more chaotic. I have tried using trigonometry (e.g. arctangent), but it only works as intended in very special circumstances. Might there be a way to find out the angle of an SKSpriteNode's trajectory, so that I can rotate the object to that angle? Thanks for any help you can provide!

EDIT:

I created an extension for CGVector and tried to rotate the SKSpriteNode in the direction of its velocity (Thanks to 0x141E for the idea) once two objects collided, but it doesn't seem to be working properly

func didBeginContact(contact: SKPhysicsContact) {
    var firstBody : SKPhysicsBody = contact.bodyA
    var secondBody : SKPhysicsBody = contact.bodyB
    if ((firstBody.categoryBitMask == PhysicsCatagory.Blade) && (secondBody.categoryBitMask == PhysicsCatagory.Laser))
    {
        if (secondBody.node != nil)
        {
            if (saberAngle <= 0 && LCR == 1) // Blade pointing right
            {
                let rebound = CGVectorMake(-reboundStrength*sin(1.5707 + saberAngle), reboundStrength*cos(1.5707 + saberAngle))
                secondBody.applyImpulse(rebound)
            }
            else if (saberAngle > 0 && LCR == -1) // Blade pointing left
            {
                let rebound = CGVectorMake(reboundStrength*sin(1.5707 - saberAngle), reboundStrength*cos(1.5707 - saberAngle))
                secondBody.applyImpulse(rebound)
            }
            if (secondBody.velocity.speed() > 0.01){
                (secondBody.node as! SKSpriteNode).zRotation = secondBody.velocity.angle() - offset
            }
        }
    }
}

I didn't do it in the didSimulatePhysics() method because there would be times when the node I was trying to rotate would not exist, and I would get errors like "Use of unresolved identifier 'sprite'"

EDIT:

I got it to work by simply creating and running an action called rotate that rotates the sprite to secondBody.velocity.angle() - offset, but I'm still curious as to why my code wasn't working before ^^


回答1:


It's fairly straightforward to rotate a sprite in the direction of its motion. You can do this by converting the x and y components of the sprite's velocity into an angle with the atan2 function. You should rotate the sprite only when its speed is greater than some nominal value to prevent the sprite from resetting to zero degrees when the sprite's speed is (nearly) zero.

If we extend CGVector to compute speed and angle from the velocity's components by

extension CGVector {
    func speed() -> CGFloat {
        return sqrt(dx*dx+dy*dy)
    }
    func angle() -> CGFloat {
        return atan2(dy, dx)
    }
}

we can rotate a sprite to face in the direction of its motion with

override func didSimulatePhysics() {
    if let body = sprite.physicsBody {
        if (body.velocity.speed() > 0.01) {
            sprite.zRotation = body.velocity.angle() - offset
        }
    }
}

where offset = CGFloat(M_PI_2) if your sprite faces up when zRotation is zero, and offset = 0 if your sprite faces to the right when zRotation is zero.



来源:https://stackoverflow.com/questions/31421912/rotate-an-object-in-its-direction-of-motion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!