init skshape node inside a specific class - swift

I create a class of kind SKShapeNode. in the class I create a ball var that implements some properties. one of the properties that I need is 'circleOfRadius' so the ball will get a specific size. I look at the question and the answer here: here but I don't really get it. here is my code:
class BallNode: SKShapeNode{
var lastPosition: CGPoint?
init(circleOfRadius: CGFloat){
super.init()
let radius = 25
self.init(circleOfRadius: radius)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
no matter what I try I get an error. how can I init the ball size inside the class?
thanks!

Related

Initialize a Custom SKSpriteNode with its properties from the editor

I made my own simple custom class called SKGlowNode as a subclass of SKSpriteNode. I originally wanted to be able to create a custom class and input all the init parameters in the editor like you can with a SKSpriteNode. However, I found out that this is not possible yet and I had to try to do it with user data. I set up my node in the editor like this:
And simply did the custom class like this:
Here is my class for SKGlowNode
import Foundation
import SpriteKit
class SKGlowNode: SKSpriteNode{
let colors = [UIColor.blue,UIColor.green,UIColor.red,UIColor.orange,UIColor.purple,UIColor.yellow,UIColor.white,UIColor.magenta]
required init?(coder aDecoder: NSCoder) {
super.init(texture: texture, color: .black, size: size)//error here
let glowIndex = self.userData?.value(forKey: "glowColorIndex") as? Int ?? 0
let glowTexture = self.userData?.value(forKey: "glowTexture") as? String ?? "squareBg"
addGlow(radius: 75, texture: SKTexture(imageNamed: glowTexture), color: colors[glowIndex])
//This glow function works and is an extension from a SKSpriteNode where it creates a glow from a texture with certain color
}
}
Obviously I get an error on the line specified because I cant initialize the superclass using those variables, but I have no idea what to put in order to get it to initialize with the values already defined in the editor as it would work if there was no custom class. Thanks
You need to have the appropriate Super.init for your class init.
If you are instantiating the subclassed SKSpriteNode in an init() whether it be the default or a custom init with custom parameters you use
super.init(texture: SKTexture, color: SKColor, size: CGSize)
if you are instantiating it from an sks scene file then required init?(coder aDecoder: NSCoder) gets called and you need to have
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

Editing properties of an SKSpriteNode custom class?

In my custom SKSpriteNode class, I want to be able to change properties such as anchorPoint, posistion, etc. within the custom class so I don't need to elsewhere.
import Foundation
import SpriteKit
open class Crank:SKSpriteNode {
init() {
super.init(texture: SKTexture(imageNamed: "crank"), color:
NSColor.white, size: CGSize(width: 155.0, height: 188.0))
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
How would I edit other properties?
import Foundation
import SpriteKit
class Crank: SKSpriteNode {
init(imageNamed image: String, position at: CGPoint, withAnchor anchor: CGPoint) {
super.init(imageNamed: image)
self.position = position
self.anchorPoint = anchor
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
(Written from memory, so may contain small errors, but is broadly correct).
and then in your main code:
let myCrank = Crank(imageNamed: "Crank.png", at: CGPoint(300, 500), withAnchor: CGpointZero)
My answer notwithstanding, Alessandro has a point. I think that it's better to set 'standard' properties in the normal place.
If you are going to set any of the standard SKSpriteNode properties inside the actual class, then I think specifying them in an initialiser is good practice as it makes the m more visible,. Debugging a program where you don't appears to set a node's position, or texture etc. would be problematic.
Another way to do it would be to create a protocol and apply it to the standard SpriteKit classes that you are subclassing (or their ancestor).
For example:
protocol CustomSKNode
{
var position:CGFloat { get set }
var zRotation:CGFloat { get set }
// ...
}
extension SKNode: CustomSKNode {}
Once you've done this somewhere in your project, you'll be able to access these properties of on any of your custom SKNode or SKSpriteNode without having to import SpriteKit.

Using a class (or instance) property inside of another classes initilizer in swift

I'm relatively new to Swift, and I wanted to know if there was a way to reference a class's property inside of a separate class initializer? For example: if I have a class Person with the property position, is there a way to initialize a Pants class such that its position is the same as Person's? Here's my code:
class Pants:SKSpriteNode{
init(){
let pants = SKTexture(imageNamed: "Sprites/pants.jpg")
pants.setScale(0.5)
super.init(texture: pants, color: UIColor.clearColor(), size: pants.size())
//self.position.x = aPerson.position.x + (aPerson.size.width / 2)
//self.position.y = aPerson.position.y - (aPerson.size.height * 0.04)
self.position = Person.getPos()//CGPoint(x: 200,y: 200)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
}
At first I tried referencing aPerson which is an instance of Person but I received the error: Instance member aPerson cannot be used on type GameScene. I think understand why it doesn't make much sense to reference an instance in this case- as the instance may not exist by the time of reference? But I don't really know what this error message means- any clarification would be great. I then thought to use a static getter method within the Person class that just returned it's position property. This also doesn't seem to work. Any suggestions would be awesome!
One solution is to add a parameter to your initializer (as suggested by Paul Griffiths in a comment above):
class Pants: SKSpriteNode {
init(aPerson: Person) {
let pants = SKTexture(imageNamed: "Sprites/pants.jpg")
pants.setScale(0.5)
super.init(texture: pants, color: UIColor.clearColor(), size: pants.size())
self.position.x = aPerson.position.x + (aPerson.size.width / 2)
self.position.y = aPerson.position.y - (aPerson.size.height * 0.04)
self.position = aPerson.getPos()//CGPoint(x: 200,y: 200)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Then wherever you want to create a Pants instance, you must pass a person:
let somePerson = Person()
let pants = Pants(aPerson: somePerson)
I assume Pants are worn by Person? so instead, work relative, not absolute.
Make Pants a child node of person, then all you need to worry about is the distance from the center of Person, to the Pant line. If this will always be a constant number (Like 10 pixels below center) then hard code it. If the Pant line changes, then pass in the pant line like #Santa Claus suggests
====Assume some code here please======
person.pantline = -10;
person.addChild(Pants(pantline:person.pantline))
=====================================
class Pants: SKSpriteNode {
convenience init(pantline: Int) {
self.init(imageNamed: "Sprites/pants.jpg")
self.setScale(0.5) //Why?
self.anchorPoint = CGPointMake(0.5,1)
self.position.y = pantline
}
required init?(coder aDecoder: NSCoder) {
super.init(coder:aDecoder)
}
override init (texture: SKTexture, color: UIColor, size: CGSize)
{
super.init(texture: texture, color: color, size: size)
}
}

sknode can't see added children

Here i created a menu class which contains a few items. I want to display these sprites in the main class. I experimented with this by creating an object associating with the sknode class in the touches began method, but when i added the menu object in the main class using the addChild thing, nothing showed up.
class menu:SKNode {
let background = SKSpriteNode(imageNamed:"background")
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(){
super.init()
var fixedSize = self.frame.width/11
background.size = CGSizeMake(self.frame.width-fixedSize, self.frame.size.height-fixedSize)
background.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2)
self.addChild(background)
}
}
//In the main method i said let settings = menu() self.addChild(settings) nothing shows up
The frame property of an SKNode is equal to CGRectZero, so when you try to set the size of your background node it will also end up as CGRectZero.
An easy fix to your problem would be to add custom initializer and call that with the size of the scene.
class menu:SKNode {
let background = SKSpriteNode(imageNamed:"background")
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
init(size: CGSize) {
super.init()
var fixedSize = size.width/11
background.size = CGSizeMake(size.width-fixedSize, size.height-fixedSize)
background.position = CGPointMake(size.width/2, size.height/2)
self.addChild(background)
}
}

Is it possible for a subclass of SKShapeNode ot use one of its convenience initializers?

I have a class that inherits from SKShapeNode because I want to add additional properties. The problem I am having is that I want to be able to create a "circle" by using SKShapeNode's "convenience" initializer SKShapeNode.init(circleOfRadius:CGFloat), but since it is a convenience initializer the compiler complains with a message " Must call a designated initializer of the class SKShapeNode", because it only allows calling of a "designated initializer" of the parent class, but the only "designated" initializer of SKShapeNode is SKShapeNode.init(), which would not create the circle shape i want.
Below is my code with the compiler error.
So the question is, can I subclass SKShapeNode and still somehow have access to the "convenience" initializer to initialize it with a circle shape? Seems to me that it is not possible. And so are there any workarounds?
thanks
The designated initializer for SKShapeNode is just plain old init, so that's what we have to call in our custom init method. To create a circle shape then, we will have to create the path ourselves. Fortunately, CGPath has a convenience initializer we can use to create the circle. Here ya go:
import SpriteKit
class CustomSKShapeNode:SKShapeNode{
var groupName:String!
init(groupName:String,radius:CGFloat){
super.init()
self.groupName = groupName
let rect = CGRect(x:-radius,y:-radius,width:radius * 2,height:radius * 2)
self.path = CGPath(ellipseIn: rect, transform: nil)
self.fillColor = UIColor.yellow
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
var node = CustomSKShapeNode(groupName:"group1",radius:40)
node.position = CGPoint(x:40,y:40) // bottom left corner
addChild(node)