Swift/SpriteKit - Collisions and Objects - swift

I have a class called Item, and inside there is an instance variable called itemNode which is of type SKSpriteNode. In my GameScene class, when I create an instance of Item I create a physics body that is given to the Item's itemNode. In my collision detection system, when my character's physics body collides with the itemNode's physics body, I want to preform a function on the Item object whose node's physics body just collided. However, the collision system only returns to physics body. How do I access the Item object given only the physics body of the node?

The SKPhyicsBody class has a node property which points to the SKNode instance it is attached to.
Your collision detection code can look something like this:
func didBeginContact(contact: SKPhysicsContact) {
var item: SKSpriteNode
var character: SKSpriteNode
//Change this on the basis of the order of your categoryBitMask values
if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
item = contact.bodyA.node as SKSpriteNode
character = contact.bodyB.node as SKSpriteNode
}
else
{
item = contact.bodyB.node as SKSpriteNode
character = contact.bodyA.node as SKSpriteNode
}
//Perform necessary operations on item and character
}
EDIT:
In order to get access to the Item instance that declares the node, you will have to store a variable within the node which points to the Item instance. For this, you can either subclass SKSpriteNode and include a property, or use the userData
property of SKNode
Subclassing:
//New Class
class ItemNode: SKSpriteNode {
static var itemInstance
}
//In the Item class declare the itemNode using this class
let itemNode = ItemNode()
itemNode.itemInstance = self
UserData property:
item.userData = NSMutableDictionary(object: self, forKey: "ItemInstance"))

Related

How can I remove a subclass of SKSpriteNode from parent correctly in Swift (to be removed from array, space on screen...)?

I've created a subclass:
class EnemySprite: SKSpriteNode
and added an enemy in my game scene using this code:
let enemy = EnemySprite(imageNamed:"enemy.png")
self.addChild(enemy)
Now when I shoot on the enemy I have the code:
enemy.removeFromParent()
The enemy is not seen on the screen, but the _enemiesSpritesArray.count remains the same. Also, when I shoot to the area where the enemy was, bullets stop there as if the sprite is still in the same spot.
I've tried to add:
override func removeFromParent() {
super.removeFromParent()
}
but still the same.
How can I remove the sprite completely?
You should remove the instance from the array as well.
if let index = enemiesSpritesArray.index(of: enemy) {
enemiesSpritesArray.remove(at: index)
}

Init subclass of SKSpriteNode using .sks file Xcode 8

In my GameScene.sks I have a SKSpriteNode which represents a "ball".
I need to subclass SKSpriteNode as Ball:
class Ball:SKSpriteNode {
//custom init
}
In my scene, I would like init my Ball using the SKSpriteNode in the .sks.
As I'm using Xcode 8, I tried to use the custom class in my SKSpriteNode:
self.ball = self.childNode(withName: "ball") as! Ball
But my app crashes at this line...
Also I'm not sure how to create a custom initializer for my subclass.
FYI I would prefer to avoid having something like:
class Ball:SKNode {
var sprite:SKSpriteNode!
}
let ball = Ball()
ball.sprite = self.childNode(withName: "ball") as? SKSpriteNode
I think the problem here is that you are not assigning a name to the sprite you add in the scene editor.
You could retrieve your sprite searching for type instead that searching for name
Try this
self.ball = self.children.flatMap { $0 as? Ball }.first!

Change texture of SKNode that is an SKSpriteNode

In a game I'm making I can get the node the user is touching with
var node = self.nodeAtPoint(positionInScene)
However, this gets me an SKNode (even if the node the user touches is an SKSpriteNode) and I cannot use node.texture to change its texture. How can I change that SKNode to an SKSpriteNode or change its texture? (Actions won't work here because I need to pause the scene and they won't work when the scene is paused).
Casting is what you are looking for.
For instance:
If you are sure that the casting will be successful and your SKNode() is actually a SKSpriteNode, you can do the following:
let s = SKNode()
let ss: SKSpriteNode = (s as? SKSpriteNode)!
However, it is always better to use the optional specially in casting:
let ss2: SKSpriteNode? = s as? SKSpriteNode

Get position of private object in update method

Is there a way I can access a property of an SKSpriteNode (Its position) in the update() method if it is declared and initiated within a specific method? I have a method called shootLaser() that creates an SKSpriteNode like so:
var laser = SKSpriteNode(imageNamed: "LaserDot.png")
And I need to perform an action using the position of "laser" every time a frame is rendered, and I only know of doing that by using the update() method.
You can access the certain node by its name property:
laserNode.name = "laserNode"
After that , you can use childNodeWithName to access certain node by its name:
let laserNode: SKSpriteNode = parentNode.childNodeWithName("laserNode") as SKSpriteNode
or if laser is added directly to the scene:
let laserNode: SKSpriteNode = childNodeWithName("laserNode") as SKSpriteNode

How to set velocity in Swift

Below is an Enemy node in Sprite Kit, in Swift. I have set the velocity for the node, but when it spawns there is no movement. Xcode is giving me no errors, is there something I'm doing wrong here?
class Enemy: SKSpriteNode {
init(imageNamed: String) {
let imageTexture = SKTexture(imageNamed: imageNamed)
super.init(texture: imageTexture, color: nil, size: imageTexture.size())
self.name = "Enemy"
self.physicsBody = SKPhysicsBody(rectangleOfSize: imageTexture.size())
self.physicsBody?.dynamic = false
self.physicsBody?.velocity = CGVectorMake(10.0,10.0)
}
}
From Apple's SpriteKit documentation:
A Boolean value that indicates whether the physics body is moved by the physics simulation.
Declaration
Swift
var dynamic: Bool
Objective-C
#property(nonatomic, getter=isDynamic) BOOL dynamic
Discussion
If the value is NO, the physics body ignores all forces and impulses applied to it. This property is ignored on edge-based bodies; they are automatically static.
As 0x141E says, you have to make your SKPhysicsBody dynamic, or it won't move.