Scenekit / Spritekit remove node causing crash - swift

What I'm try to do, is replicate some digital instrument gauge ...using Spritekit..
On my project I have to use a SpriteKit Scene as material for Scenekit SCNnode.
In order to do that I create a sub class of SKscene and and apply it as "material.diffuse.contents" of the SCNNode.
all working fine, I can see my SKscene as material of the SCNNode.
Here the issue:
I try to animate/replicate the correct indication of the instrument based of some value my app received from other source.
To do so, i decide to use the SKsceneDelegate and use the method "update(_ currentTime: TimeInterval)"
simply the update method look for the sknode of the green needle "fulcro" remove it , and make a new line calculating the angle and new coordinate for the new line.
override func update(_ currentTime: TimeInterval) {
guard let fulcroToRemove = self.childNode(withName: "fulcro") else {return}
fulcroToRemove.removeFromParent() // issue here...
let fulcro = SKNode()
fulcro.name = "fulcro"
fulcro.position = CGPoint(x: 300, y: 260)
let line = makeLine(startPos: CGPoint(x: 0, y: 0),
endPos: getCoordinate(angleDeg: getCurrentEGT()),
name: "EGT_LINE")
fulcro.addChild(line)
self.addChild(fulcro)
}
... if I try this SKscene itself in a project only with Spritekit all working fine.. I can see my needle increase the value correctly when the data source increase.
But if use the same SKscene as material of SceneKit getting the following error:
look like I'm removing something not correctly .. and I can see fulcroToRemove.removeFromParent() is the line trigger the error.
But why ??How I can remove the line to avoid the crash?

Related

How do I draw a line in SpriteKit with Swift 3?

For one of my classes I made a javascript game that involve characters that jump to random parts of the screen. I am trying to convert this game to Swift (I am very bad at coding and this is my third day working with Swift).
I got the part where the characters (SKSpriteNode) bounce around the screen. But for some reason I have really struggled with drawing the lines. I tried using UIBezierPath() & CAShapeLayer(). I also tried an SKSpriteNode.
But I haven't been able to draw a line at the proper angle between the original point and the ending point of the characters. Because the characters move to random spots the angle changes all the time and the size of the line also needs to change.
Here's a picture of the Javascript game:
You can use something like this:
var line = SKShapeNode()
func drawLine(from: CGPoint, to: CGPoint){
line.removeFromParent()
let path = CGMutablePath()
path.move(to: from)
path.addLine(to: to)
line = SKShapeNode(path: path)
self.addChild(line)
}
override func update(_ currentTime: TimeInterval) {
drawLine(from: player.position, to: enemy.position)
}
Here you create a path and add a startpoint to it via path.move(to:). Then you add a line to your other point with path.addLine(to:). Then use the SKShapeNode(path: CGPath) initializer to create a SKShapeNode from the path. The SKShapeNode will present your line in the scene. At the end just add your node to the scene via addChild() and call this function in your update() function to recreate the line when the player or the enemy is moving.

Sprite Kit Animations and Texture Atlases in Swift 4

Currently working on an application that requires a little bit of animations through an array of images. I've done tons of research online on how to resolve my issue but couldn't run into anything for Swift 4. Below is my code, it shows the first picture in the loop when I run the app but no animation at all. Everything looks fine, I don't see a problem with my code but maybe you guys can help. Appreciate it in advanced!
let atlas = SKTextureAtlas(named: “mypic”)
var TextureArray = [SKTexture]()
var person = SKSpriteNode()
override func didMove(to view: SKView) {
person = SKSpriteNode(imageNamed: "red_1.png")
person.size = CGSize(width: 150, height: 129)
person.position = CGPoint(x: 0, y: 0)
person = SKSpriteNode(imageNamed: atlas.textureNames[0])
for i in 1...atlas.textureNames.count {
let Name = "red_\(i).png"
TextureArray.append(SKTexture(imageNamed: Name))
}
self.addChild(person)
}
override func update(_ currentTime: TimeInterval) {
let myAnimation = SKAction.animate(with: TextureArray, timePerFrame: 0.1)
person.run(SKAction.repeatForever(myAnimation))
}
The animation action is placed in update, which is executed once every frame. So if the game runs at 60 FPS, update gets called 60 times in one second. This means that every second person gets 60 new myAnimation actions that it needs to run.
To fix this, consider placing the animation action somewhere else in your code, e.g. right after adding the person to the scene. Since this is a repeatForever action, the animation will run as you intended until either the action is removed from the node, or the node is removed from the scene.
Hope this helps!

SpriteKit: Add a node to view?

I'm new to Xcode 7, how do I add a black node in SpriteKit?
Can anyone point me in the right direction or link me up with any tutorials please? Thank you
You want to create a new SKSpriteNode object, and add it to the view
class GameScene: SKScene {
var node: SKSpriteNode?
override func didMoveToView(view: SKView) {
let node = SKSpriteNode(imageNamed: "BlackNode.png")
node.position.x = self.size.width / 2
node.position.y = self.size.height / 2
addChild(node)
}
}
So in your GameScene class (or whatever SKScene class you are using), this creates a SKSpriteNode that is the image of whatever "BlackNode.png" is, and sets its position to the center of the screen, and adds it to scene
Assuming your question is asking how to add an all black node to the scene, try this:
override func didMoveTo(view: SKView) {
let node = SKSpriteNode(color: UIColor.black, size: CGSize(width: 100, height: 100)) // Declare and initialize node
addChild(node) // Function that adds node to scene
}
This uses the SKSpriteNode initializer init(color: UIColor, size: CGSize), which you would pass a color for the node and size. This is then used to create a rectangle, while the nodes texture property remains nil.
Note that in this example, no position is explicitly chosen, so the default (0,0) is chosen (centre of scene if scene anchorPoint is 0.5,0.5)
To get a further understanding of scenes vs views and SpriteKit vs UIKit (which I think is where you're having trouble) check out this answer: SpriteKit vs UIKit

How to add sub-child to a child of self in swift

I am trying to add two SKSpriteNodes with their respective textures in swift, however the "Blade" does not show up on screen during the simulation. I am having no trouble getting the "Handle" to appear though. So my question is, what is the proper way to add a child of a child of self in swift so that everything works as intended?
var Handle = SKSpriteNode(imageNamed: "Handle.png")
var Blade = SKSpriteNode(imageNamed: "Blade.png")
override func didMoveToView(view: SKView) {
Handle.position = CGPointMake(self.size.width / 2, self.size.height / 14)
Blade.position = CGPointMake(Handle.position.x, Handle.position.y + 124)
self.addChild(Handle)
Handle.addChild(Blade)
}
This should get you close to where you expected it.
Blade.position = CGPointMake(0, 124)
Keep in mind when you add a sprite to another sprite the position is the position "within" that sprite. If you don't change the anchor that starts at the center of its parent. So you were starting in the center of Handle and adding half the width of the scene. Because Handle was already centered in the scene blade was off the scene.
Hopefully that makes sense and is helpful.
Also as lchamp mentioned you should lowerCamelCase
var Blade = SKSpriteNode(imageNamed: "Blade.png")
This will help you in the future identifying Classes vs Variables.

Sprite Kit Remove SKNode From Parent When Off Screen

I would like to know how to remove my SKNodes when they are off screen to help my game run more smoothly.
How To Do This On Sprite Kit
Thanks So Much
Here is an easy solution in Swift 4:
class GameScene: SKScene {
let s = SKLabelNode(fontNamed: "Chalkduster")
override func didMove(to view: SKView) {
s.text = "test"
s.fontSize = 50
addChild(s)
let moveRight = SKAction.moveBy(x: 40, y: 0, duration: 0.5)
s.run(SKAction.repeatForever(moveRight))
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
if ((s.parent != nil) && !intersects(s)) {
s.removeFromParent()
print("Sprite removed.")
}
}
}
You have a sprite (in this case a SKLabelNode but any sprite node will do) that is moving horizontally and you want to delete this sprite once is out of the frame bounds.
You can use the intersects function to check this and then remove that sprite from its parent. I have also checked that the sprite has a parent before removing it (by checking if s.parent is not nil) as we wish to remove the sprite only once.
https://stackoverflow.com/a/24195006/2494064
Here is a link to an answer that removes nodes that go off the top of the screen. You would just have to replicate this to cover the entire border and set all of the walls to have the same contactBitMask values.
Basically the logic is to remove the SKSpriteNodes when they contact physicsbodies that you have resting just outside the visible screen.