(Swift SpriteKit) Rotate sprite in the direction of touch

自作多情 提交于 2020-01-12 05:38:06

问题


On the screenshot provided, the red arrow and cross are just for demonstration purposes and are not in the game. I would like the sprite of the spaceship to face the direction of the ball it shoots.

Link to image

Here is my current code for touch location

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
   /* Called when a touch begins */

    for touch in touches {
        let location = touch.locationInNode(self)

        var bullet = SKSpriteNode(imageNamed: "bullet")
        bullet.position = cannon.position
        bullet.size = CGSize(width: 35, height: 35)

        //physics
        bullet.physicsBody = SKPhysicsBody(circleOfRadius: bullet.size.width/2)
        bullet.physicsBody?.categoryBitMask = PhysicsCategory.bullet
        bullet.physicsBody?.collisionBitMask = PhysicsCategory.enemy
        bullet.physicsBody?.contactTestBitMask = PhysicsCategory.enemy
        bullet.name = "bullet"
        bullet.physicsBody?.affectedByGravity = false

        self.addChild(bullet)

        var dx = CGFloat(location.x - cannon.position.x)
        var dy = CGFloat(location.y - cannon.position.y)

        let magnitude = sqrt(dx * dx + dy * dy)

        dx /= magnitude
        dy /= magnitude

        let vector = CGVector(dx: 120.0 * dx, dy: 120.0 * dy) //adjust constant to increase impluse.

        bullet.physicsBody?.applyImpulse(vector)

        // I found this code bellow this comment, but it just moves the cannon's y position

        let direction = SKAction.moveTo(
            CGPointMake(
                400 * -cos(bullet.zRotation - CGFloat(M_PI_2)) + bullet.position.x,
                400 * -sin(bullet.zRotation - CGFloat(M_PI_2)) + bullet.position.y
            ),
            duration: 0.8)

        cannon.runAction(direction)
    }
}

回答1:


Here is the code I found which works perfectly.

Rotate a sprite to sprite position not exact in SpriteKit with Swift

 let angle = atan2(location.y - cannon.position.y , location.x - cannon.position.x)
 cannon.zRotation = angle - CGFloat(M_PI_2)



回答2:


I had been working some time ago in something like what you want so, here is my results

first you need to use VectorMath.swift created by Nick Lockwood and this is my code to make my spider move towards user touch

import SpriteKit
import SceneKit

class GameScene: SKScene {
    let sprite = SKSpriteNode(imageNamed:"Aranna")
    var velocity = Vector2(x: 0, y: 0)
    var positionV2D = Vector2(x: 0, y: 0)
    var headingVector = Vector2(x: 0, y: 1)

    override func didMoveToView(view: SKView) {
        /* Setup your scene here */
        let myLabel = SKLabelNode(fontNamed:"Chalkduster")
        myLabel.text = "Hello, World!";
        myLabel.fontSize = 45;
        myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));

        sprite.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
        positionV2D = Vector2(point:sprite.position);

        let testVector = Vector2(x: 10, y: 14);
        velocity += testVector;
        print(velocity.toString());
        velocity += Vector2(x: 1, y: 1);
        //velocity = velocity + testVector;
        print(velocity.toString());
        velocity *= 0.5;
        velocity.printVector2D();

        velocity = Vector2(x: 2, y: 2);
        velocity.normalized();
        velocity.printVector2D();

        self.addChild(sprite)
    }


    func ToRad(grados:CGFloat) ->CGFloat
    {
        return ((CGFloat(M_PI) * grados) / 180.0)
    }

    func ToDeg(rad:CGFloat) ->CGFloat
    {
        return (180.0 * rad / CGFloat(M_PI))
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
       /* Called when a touch begins */

        for touch in touches {
            let location = touch.locationInNode(self)

            let toTarget = Vec2DNormalize(Vector2(point:location) - positionV2D);


            let angle2 = headingVector.angleWith(toTarget);

            print(ToDeg(CGFloat(angle2)));

            headingVector.printVector2D();

            self.sprite.runAction(SKAction.rotateToAngle(CGFloat(angle2), duration: 0.1))
            self.sprite.runAction(SKAction.moveTo(location, duration: 0.5))
            positionV2D = Vector2(point: location);

        }
    }

    override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
    }
}

I hope this helps you




回答3:


If you want to rotate only you shouldn't call the moveTo action. Calculate the angle between touch location and location of the cannon and call action rotateToAngel

here is the code

        let angle = atan2(dy, dx) - CGFloat(M_PI_2)
        let direction = SKAction.rotateToAngle(angle, duration: 0.4, shortestUnitArc: true)
        cannon.runAction(direction)



回答4:


I found that with the answer submitted by James that this caused it to rotate in the wrong way, fine if you have something like a canonball but as it was used on my game which had a mage and a fireball with a trail it caused an issue, this can be easily fixed with

 let angle = atan2(touchlocation.x - cannon.position.x , touchlocation.y - 
 cannon.position.y)
 cannon.zRotation = -(angle - CGFloat(Double.pi/2))

use Double.pi / 2 and M_PI_2 is depriciated now



来源:https://stackoverflow.com/questions/38016756/swift-spritekit-rotate-sprite-in-the-direction-of-touch

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