Performance difference between SKShapeNode and SKSpriteNode - ios

If I wanted to draw a simple red rectangle, should I use an SKShapeNode or an SKSpriteNode? What is the performance (speed to render) difference?
Are there any exceptions (like applying transparency, or maybe creating a physicsBody)?
I know what the primary purpose of both are, but I'm not sure which is better on performance for drawing a simple red square.
Code:
// Shape
let myShape = SKShapeNode(rectOf: CGSize(width: 100, height: 100))
myShape.fillColor = .red
myShape.strokeColor = .clear
// Sprite
let mySprite = SKSpriteNode(color: .red, size: CGSize(width: 100, height: 100))

SKSpriteNode offers higher performance than SKShapeNode class. See documentation here
If you want to add physicsbody to SKShapeNode, you should be aligned with shapenode points. For more sophisticated performance use SKSpriteNode. SKShapeNodes are useful when it is difficult to use a texture(may be a custom shape) and for building or displaying debugging information.
Furthermore, drawing/displaying a red rectangle is OK with SKShapeNode.

Related

SpriteKit SKCropNode cropping wrong area

I am using SpriteKit to draw a graph (with the ability to zoom in and pan around).
When I use an SKCropNode to crop the grid of my graph it doesn't crop the desired area. It crops less, no matter if I use a rectangular SKShapeNode or a SKSpriteNode (with image) as .maskNode.
Here is my code:
//GRID
let grid = SKCropNode()
graphViewModel.graphScene.addChild(grid)
let ratio:CGFloat = 1000 / 500
let width = (graphViewModel.sceneSize.width*0.95)
let newSize = CGSize(width: width, height: width/ratio)
let origin = CGPoint(x: -newSize.width/2.0, y: 0.0)
let rectangularMask = SKShapeNode(rect: CGRect(origin: origin, size: newSize))
rectangularMask.fillColor = UIColor.lightGray
rectangularMask.zPosition = -10.0 //So it appears behind the grid, doesn't affect the cropping
grid.maskNode = rectangularMask
graphViewModel.graphScene.addChild(rectangularMask)
Here are two screenshots to illustrate what I mean:
This is the graph with its grid not being cropped.
This is the graph with the maskNode set.
The lightGray Area is the actual rectangularNode and the grid is being cut off a lot less than it ought to be.
My scene is scaled so I can zoom in without pixelating.
When I disable zooming (setting the scene's size to the view's size) then the bug disappears. Unfortunately I need zooming without any pixel artefacts.
Maybe someone has an idea how to fix this issue. It might also be a SpriteKit Bug.

didBeginContact() called before contact occurred

I have two sprite nodes where I have made sure both self.size and the size of their respective physics bodies is the same, but I still get a very odd behavior like this:
The photo is taken as the collision has been detected and i paused the scene. Why does this happen?
Here is the code for setting the different sizes:
Inside init() of my Player class (circular node):
super.init(texture: texture, color: color, size: CGSize(width: 100, height: 100))
then:
self.physicsBody = SKPhysicsBody(circleOfRadius: self.size.width/2, center: self.position)
Turn on physics visual representation in you GameViewController.swift, like this:
skView.showsPhysics = true
self.size in your case probably referring to the scene. What you need is to set physics body's size like this:
yourNode.physicsBody = SKPhysicsBody(rectangleOfSize: yourNode.size)
Also keep in mind that if you are altering node's anchor point,you may end up with unexpected results. Anchor point defines how texture is drawn relative to the node. It has no effect on node's physics body.

How to create a ring with 3D effect using Sprite Kit?

I want to create a ring with a 3D effect using Sprite Kit. (SEE IMAGES)
I tried subclassing a SKNode and adding two nodes as children. (SEE CODE)
One node was a complete SKShapeNode ellipse, and the other was half ellipse using SKCropNode with a higher zPosition.
It looks good, but the SKCropNode increases the app CPU usage from 40% to 99%.
Any ideas on how to reduce the SKCropNode performance cost, or any alternative to create the same ring 3D effect?
class RingNode: SKNode {
let size: CGSize
init(size: CGSize, color: SKColor)
{
self.size = size
self.color = color
super.init()
ringPartsSetup()
}
private func ringPartsSetup() {
// LEFT PART (half ellipse)
let ellipseNodeLeft = getEllipseNode()
let leftMask = SKSpriteNode(texture: nil, color: SKColor.blackColor(), size: CGSize(
width: ellipseNodeLeft.frame.size.width/2,
height: ellipseNodeLeft.frame.size.height))
leftMask.anchorPoint = CGPoint(x: 0, y: 0.5)
leftMask.position = CGPoint(x: -ellipseNodeLeft.frame.size.width/2, y: 0)
let leftNode = SKCropNode()
leftNode.addChild(ellipseNodeLeft)
leftNode.maskNode = leftMask
leftNode.zPosition = 10 // Higher zPosition for 3D effect
leftNode.position = CGPoint(x: -leftNode.frame.size.width/4, y: 0)
addChild(leftNode)
// RIGHT PART (complete ellipse)
let rightNode = getEllipseNode()
rightNode.position = CGPoint(x: 0, y: 0)
rightNode.zPosition = 5
addChild(rightNode)
}
private func getEllipseNode() -> SKShapeNode {
let ellipseNode = SKShapeNode(ellipseOfSize: CGSize(
width: size.width,
height: size.height))
ellipseNode.strokeColor = SKColor.blackColor()
ellipseNode.lineWidth = 5
return ellipseNode
}
}
You've got the right idea with your two-layer approach and the half-slips on top. But instead of using a shape node inside a crop node, why not just use a shape node whose path is a half-ellipse? Create one using either CGPath or UIBezierPath API — use a circular arc with a transform to make it elliptical — then create your SKShapeNode from that path.
You may try converting your SKShapeNode to an SKSpriteNode. You can use SKView textureFromNode: (but we aware of issues with scale that require you to use it only after the node has been added to the view and at least one update cycle has run), or from scratch using an image (created programatically with a CGBitmapContext, of course).

SpriteKit simple shapes not drawing

I'm doing some experimentation with SpriteKit and am roadblocked on a concept that to me seems very simple. I'm trying to draw simple shape (ie: square, circle) to the screen.
var testNode = SKSpriteNode()
testNode = SKSpriteNode(color: UIColor.orangeColor(), size: CGSizeMake(20, 20))
testNode.position = goalPoint
testNode.color = UIColor.orangeColor()
self.addChild(testNode)
According to the developer documentation for SKSpriteNode
An SKSpriteNode is a node that draws a textured image, a colored square, or a textured image blended with a color. You can also provide a custom shader to create your own rendering effects.
Apparently I'm missing how to do the colored square. I was able to create an SKTexture and get a sprite to appear, but without one I've been unable to get geometric shapes to appear.
I also attempted to use the SKShapeNode class but was unable to get that to appear either. I assume I'm missing something simple. Any suggestions?
The code in itself is correct, the only two things I can think of to be the problem is:
goalPoint - Is somewhere out of the screen bounds.
The location of the code. Where is your code located in your project?
In my didMoveToView I have the following :
var testNode = SKSpriteNode()
testNode = SKSpriteNode(color: UIColor.orangeColor(), size: CGSizeMake(20, 20))
testNode.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
testNode.color = UIColor.orangeColor()
self.addChild(testNode)
And it works like a charm.
So relocate your code to somewhere you are sure it's executed. And make sure goalPoint is within the screen.
Good luck :)

How to fix a node in a position using SpriteKit

I have created a world using SpriteKit, containing a SKShapeNode. I'd like to tie it into the ceiling. The gravity and other stuff still have their effect on this shape, but it should hang from the ceiling. Like a lamp, or a rope.
My shape:
let shape = SKShapeNode(rectOfSize: CGSize(width: self.tamanhoQuadrado, height: self.tamanhoQuadrado))
When I add this:
shape.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: self.tamanhoQuadrado, height: self.tamanhoQuadrado))
It falls to the ground. I haven't found a property that can ignore gravity.
Found it!
//no gravity
shape.physicsBody!.affectedByGravity=false
//make it stay on it's place
shape.physicsBody!.dynamic=false

Resources