ios – How can I correctly rotate SKSpriteNodes a couple of level aside from the origin?


The Drawback

I’ve a set of SKSpriteNodes inside a GameScene which are positioned in an orderly method i.e. their positions are consistently spaced e.g. (0, 0), (0, 150), (0, 300). I need to have the ability to rotate the entire ships concerning the centroid of their positions and have their heading level to the route during which they’re being rotated to. Please check out the diagram beneath to grasp what I imply:

enter image description here

What I’ve Tried

I’ve tried placing the entire sprite nodes inside a container SKNode and rotating the SKNode. This causes the youngsters to rotate as desired since they’re all positioned relative to the father or mother node. Nevertheless, I need to keep away from doing this as I need to have management over every of the person sprite node’s zRotation and place as an alternative of ‘dishonest’ and having a container node do it for me.

To repair this, I’ve tried making use of the usual 2D rotation matrix to the positions of the SKSpriteNodes. The code beneath isn’t an actual duplicate, nevertheless it roughly describes what I’ve tried to do:

@objc func sliderValueDidChange(_ sender: UISlider) { 

    // simply assume I've entry to the GameScene from the GameViewController
    guard let scene = view.scene as? GameScene else { return } 
    let nodes = scene.nodes 

    // prevSliderValue is the worth of the slider from the earlier name to 
    // this perform. the slider has a variety of values from 0 to 359
    let angleChange = (prevSliderValue - CGFloat(sender.worth)) / 180 * .pi

    // calculating the centroid
    var cenX = CGFloat.zero
    var cenY = CGFloat.zero
    // nodes is a listing of [SKSpriteNodes]
    for node in nodes {    
        cenX += node.place.x
        cenY += node.place.y
    }
    cenX = cenX / CGFloat(nodes.rely)
    cenY = cenY / CGFloat(nodes.rely)
    
    // making use of the rotation matrix to every node's place
    for node in nodes { 
        // calculating the brand new place
        let newX = node.place.x * cos(angleChange) - node.place.y * sin(angleChange) 
        let newY = node.place.x * sin(angleChange) + node.place.y * cos(angleChange) 
        node.place = CGPoint(x: newX, y: newY)

        // calculating the brand new angle to level at 
        // let a = -atan2(node.place.y - cenY, node.place.x - cenX) + .pi/2
        // node.zRotation = a
        /*
         atan2 offers the angle relative to the X axis, however SKSpriteNodes  
         zRotation are relative to the Y axis, therefore I am including pi/2 
         moreover, I need a constructive angle of rotation to be clockwise,
         so I am negating the return worth of the atan2 perform
        */ 
    }
}

The results of this code has to date been unsuccessful. The nodes are roughly capable of rotate clockwise to about 180º alongside an arc relative to the centroid. However for any worth previous 180º, the nodes mainly cease rotating/transferring and simply spasm on the spot. Making an attempt to reverse the rotation (i.e. going from 180º again to 0º) does trigger the nodes to rotate counterclockwise, however they do not attain to their authentic spot (i.e. their ending place is usually a few levels off from completely vertical). Moreover, if I drag the slider up and down a couple of instances, for no matter purpose which eludes me, the nodes find yourself transferring nearer and nearer till they converge on the centroid.

Is there one thing fallacious with how I am calculating the ultimate positions? I’ve realized that my calculation of newX and newY aren’t relative to the centroid however as an alternative are relative to the origin, which messes up my mind much more. I have been caught on this for a couple of days and I can already really feel myself beginning to burn out. Any assist or pointers could be enormously appreciated.

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles