On SpriteKit on iOS, scaling a textured sprite creates the wrong frame?

I am exploring SpriteKit game development for fun, and I came across a seemingly simple problem that puzzled me.

Basically, after scaling the textured SKSpriteNode, the frame is NOT what I expect. I figured out a few hacks to get it to what I want, but I'm trying to figure out what is going on. Any ideas appreciated!

Here is my code WITHOUT ANYTHING:

func addSpaceship() { let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png") spaceship.name = "spaceship" // spaceship.setScale(0.50) let debugFrame = SKShapeNode.init(rect: spaceship.frame) debugFrame.strokeColor = SKColor.greenColor() spaceship.addChild(debugFrame) spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150) self.addChild(spaceship) } 

And my application looks like this: Unscaled ship with green debug frame

Now, if I comment in a line of code that scales it (spaceship.setScale (0.50)), I get the following:

Scaled ship with green debug frame

Note that the spaceship is reduced in the second image, but the frame is even smaller. Why?

If I move the zoom line after adding the spacecraft to the scene, it does what I expect, but it seems wrong:

Here the code with setScale is called after adding the spacecraft to the scene:

 func addSpaceship() { let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png") spaceship.name = "spaceship" let debugFrame = SKShapeNode.init(rect: spaceship.frame) debugFrame.strokeColor = SKColor.greenColor() spaceship.addChild(debugFrame) spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150) self.addChild(spaceship) spaceship.setScale(0.50) } 

And here is how my application works:

Scaling after adding to the scene

So what works, but why is it needed?

It was suggested below that this is a bug with SKShapeNode. But replacing SKShapeNode with SKLabelNode has the same problem:

 func addSpaceship() { let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png") spaceship.name = "spaceship" spaceship.setScale(0.50) let scoreNode = SKLabelNode(text: "100") scoreNode.position = CGPointMake(CGRectGetMidX(spaceship.frame), CGRectGetMaxY(spaceship.frame)) scoreNode.fontColor = SKColor.redColor() scoreNode.fontSize = 15.0 scoreNode.fontName = "Monaco" scoreNode.zPosition = 10.0 spaceship.addChild(scoreNode) spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150) self.addChild(spaceship) } 

which gives us:

Same problem with an SKLabelNode

The goal is for the score label (scoreNode) to be centered over the rocket, but as you can see, it is on top of the top porthole. There is something wrong with the spacecraft frame after I call spacehip.setScale.

I made one additional discovery: the setScale call should not be after adding a spaceship to the scene. It just has to be after I add debugFrame / scoreNode to the spaceship. If I set DOWNLOAD AFTER this point, everything will be fine:

 func addSpaceship() { let spaceship = SKSpriteNode.init(imageNamed: "rocketship.png") spaceship.name = "spaceship" let scoreNode = SKLabelNode(text: "100") scoreNode.position = CGPointMake(CGRectGetMidX(spaceship.frame), CGRectGetMaxY(spaceship.frame)) scoreNode.fontColor = SKColor.redColor() scoreNode.fontSize = 15.0 scoreNode.fontName = "Monaco" scoreNode.zPosition = 10.0 spaceship.addChild(scoreNode) spaceship.setScale(0.50) spaceship.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 150) self.addChild(spaceship) } 

that leads to:

This worked

+3
ios swift scaling sprite-kit
source share
2 answers

Your problem may be in the order of these two lines:

  spaceship.setScale(0.50) let debugFrame = SKShapeNode.init(rect: spaceship.frame) 

You reduced the spacecraft , and then calculated the size of the rectangle using a scaled spacecraft. Then, when rendering, the rectangle is reduced to half its size, which is a quarter of the original size of the spacecraft.

If you swap, this should work as expected.

In general, it’s better to make the layout in real size, and then scale everything before adding it to the scene.

+3
source share

First of all, let me preface with SKShapeNode - really funny (maybe a class with an error). At least that was in previous spritekit iterations. If your goal is to add a debug rectangle for physical purposes. You can include showsPhysics in your SKView class inside your GameViewController

Here is my experiment

  let redbox = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 100, height: 100)) redbox.position = CGPoint(x: self.size.width/2, y: self.size.height/2) redbox.setScale(0.5) let debugFrame = SKShapeNode(ellipseOfSize: redbox.size) debugFrame.strokeColor = SKColor.greenColor() self.addChild(redbox) redbox.addChild(debugFrame) 

enter image description here

looks just like yours. if I call setScale after adding nodes, then my circle will fill my red square.

Also, if I keep everything the same, but I just add my debugframe to the scene, it will scale correctly, strange, yes.

ok another test. note I set greenbox to 50% of the size of the red boxes so that we can see the red box below. If an error occurred here, and greenbox would finish filling 25% of the red box.

  let redbox = SKSpriteNode(color: SKColor.redColor(), size: CGSize(width: 100, height: 100)) redbox.position = CGPoint(x: self.size.width/2, y: self.size.height/2) redbox.setScale(0.5) let greenbox = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 50, height: 50)) self.addChild(redbox) redbox.addChild(greenbox) 

enter image description here

So, I did the same using another SKSpriteNode, and it behaves as we expected. For some reason, when you use SKShapeNode as a child . SetScale is called twice on it; unless you set the scale after adding nodes to the scene. But this does not happen with SKSpriteNode.

Answer: I do not think there is a good answer. This is probably a mistake. SKShapeNode has a bug history. SpriteKit has some errors = / Someone will correct me if I am wrong.

+1
source share

All Articles