Search code examples
swiftsprite-kitsknode

How to rotate a SKNode without changing its position?


I have a SKNode which consists of 4 SKSpriteNodesthat make up a square shape (I hope I'm wording it right). Each side of the square has a different color, and I'm trying to rotate the whole square wihout chaning its position. The way I'm trying is always leading it to change its position when it begins the rotation. This is how I have approached it:

import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {

    var shape = SKNode()

    override func didMoveToView(view: SKView) {

    self.addChild(shape)
    self.physicsWorld.gravity = CGVectorMake(0.0, 0.0)
    self.physicsWorld.contactDelegate = self

    let greenLine = SKSpriteNode(imageNamed: "Green")
    greenLine.position = CGPoint(x: size.width / 2, y: size.height / 2.5)

    let yellowLine = SKSpriteNode(imageNamed: "Yellow")
    yellowLine.position = CGPoint(x: greenLine.position.x - greenLine.frame.width / 2, y: frame.size.height / 2)

    let redLine = SKSpriteNode(imageNamed: "Red")
    redLine.position = CGPoint(x: greenLine.position.x + greenLine.frame.width / 2, y: frame.size.height / 2)
    let blueLine = SKSpriteNode(imageNamed: "Blue")
    blueLine.position = CGPoint(x: frame.size.width / 2, y: redLine.position.y + redLine.frame.height / 2.3)

    shape.addChild(greenLine)
    shape.addChild(yellowLine)
    shape.addChild(redLine)
    shape.addChild(blueLine)

    let rotateAction = SKAction.rotateByAngle(CGFloat(M_PI_4) * 2, duration: 5)
    shape.runAction(rotateAction)
}

I tried zRotation as well, but that didn't work at all. When rotation happens with an SKAction, it takes the whole shape to the left while rotating, instead of staying at the same place.

Edit

Code:

 var shape = SKNode()

override func didMoveToView(view: SKView) {

    self.addChild(shape)
    self.physicsWorld.gravity = CGVectorMake(0.0, 0.0)
    self.physicsWorld.contactDelegate = self

    backgroundColor = UIColor.whiteColor()

    let greenLine = SKSpriteNode(imageNamed: "Green")
    greenLine.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2.5)

    let yellowLine = SKSpriteNode(imageNamed: "Yellow")
    yellowLine.position = CGPoint(x: greenLine.position.x - greenLine.frame.width / 2, y: frame.size.height / 2)

    let redLine = SKSpriteNode(imageNamed: "Red")
    redLine.position = CGPoint(x: greenLine.position.x + greenLine.frame.width / 2, y: frame.size.height / 2)

    let blueLine = SKSpriteNode(imageNamed: "Blue")
    blueLine.position = CGPoint(x: frame.size.width / 2, y: redLine.position.y + redLine.frame.height / 2.3)

    shape.position = CGPoint(x: 0, y: 0)
    shape.addChild(greenLine)
    shape.addChild(yellowLine)
    shape.addChild(redLine)
    shape.addChild(blueLine)

    let center = SKSpriteNode(color: .redColor(), size: CGSize(width: 50, height: 50))
    center.position = CGPoint(x: frame.midX, y: frame.midY)
    shape.addChild(center)

    let rotateAction = SKAction.rotateByAngle(CGFloat(M_PI_4) * 2, duration: 30)
    shape.runAction(rotateAction)


}

Solution

  • You probably don't understand the difference between different coordinate systems. You are adding a shape node to the scene. So when you set the position of the shape you have to work in scene's coordinate system. Same logic applies to the other nodes (lines). Here, you are adding them to the shape, which means you have to "think" in shape's coordinate system. Take a look a this example:

    import SpriteKit
    
    class GameScene: SKScene, SKPhysicsContactDelegate {
    
        var shape = SKNode()
    
        override func didMoveToView(view: SKView) {
    
            self.addChild(shape)
            self.physicsWorld.gravity = CGVectorMake(0.0, 0.0)
            self.physicsWorld.contactDelegate = self
    
            let greenLine = SKSpriteNode(color: .greenColor(), size: CGSize(width: 50, height: 50))
            greenLine.position = CGPoint(x: -30, y: 30)
    
            let yellowLine =  SKSpriteNode(color: .yellowColor(), size: CGSize(width: 50, height: 50))
            yellowLine.position = CGPoint(x: 30, y: 30)
    
            let redLine = SKSpriteNode(color: .redColor(), size: CGSize(width: 50, height: 50))
            redLine.position = CGPoint(x: 30, y: -30 )
            let blueLine =  SKSpriteNode(color: .blueColor(), size: CGSize(width: 50, height: 50))
            blueLine.position = CGPoint(x:-30, y:-30)
    
            shape.position = CGPoint(x: frame.midX, y: frame.midY)
            shape.addChild(greenLine)
            shape.addChild(yellowLine)
            shape.addChild(redLine)
            shape.addChild(blueLine)
    
            let center = SKSpriteNode(color: .redColor(), size: CGSize(width: 5, height: 5))
    
            shape.addChild(center)
    
            let rotateAction = SKAction.rotateByAngle(CGFloat(2 * M_PI), duration: 5)
            shape.runAction(rotateAction)
    
        }
    }
    

    The result:

    rotating

    Note the center node. That is the actual position of the shape node. And that is the point around other nodes are being rotated.