Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
880 views
in Technique[技术] by (71.8m points)

swift - Rotate an object in its direction of motion

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 ^^

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...