Hi,
Re: Chap 9.
I am having trouble referencing a childnode from a custom class (JoeSprite) with code. Chap 9 Shows how to refer to the sks scene. How can I do this in code? I created a protocol in the GameScene (JoeScene) and call it in the enumeration but the simulator crashes when I build it. It finds nil when force unwrapping. Xcode suggests to make it optional instead but then the sprite (“Joe”) doesn’t appear. I tried giving the sprite a name (joe.name = “Joe”) but it didn’t work. Where have I gone wrong? I can make it work when all the codes are in one class but not when I move the sprite to its own class. Here are my codes:
import SpriteKit
protocol PlayAlong {
func allSweet()
}
class JoeScene: SKScene {
var joeSprite: JoeSprite!
override func didMove(to view: SKView) {
joeSprite = childNode(withName: "joe") as! JoeSprite
enumerateChildNodes(withName: "//*", using: { node, _ in if let eventListenerNode = node as! PlayAlong {
eventListenerNode.allSweet()
}})
}
}
import SpriteKit
class JoeSprite: JoeScene, PlayAlong {
let textureAtlas: SKTextureAtlas = SKTextureAtlas(named: "Joe")
var joe = SKSpriteNode(imageNamed: "J1.png")
var joeWalkingFrames: [SKTexture] = []
var joeBlushingAnimation = SKAction()
override init(size: CGSize) {
super.init(size: size)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func allSweet() {
buildJoe()
animateJoe()
}
func buildJoe() {
let joeAnimatedAtlas = SKTextureAtlas(named: "Joe")
var walkFrames: [SKTexture] = []
let numImages = joeAnimatedAtlas.textureNames.count
for i in 1...numImages {
let joeTextureName = "J\(i)"
walkFrames.append(joeAnimatedAtlas.textureNamed(joeTextureName))
}
joeWalkingFrames = walkFrames
let firstFrameTexture = joeWalkingFrames[0]
joe = SKSpriteNode(texture: firstFrameTexture)
joe.position = CGPoint(x: frame.midX, y: frame.midY)
joe.size = CGSize(width: 90, height: 145)
joe.name = "joe"
joe.zPosition = 5
self.addChild(joe)
}
func animateJoe() {
let joeBlushes = SKAction.colorize(with: SKColor.red, colorBlendFactor: 0.3, duration: 1.0)
let joeBlushes2 = SKAction.colorize(withColorBlendFactor: 0.0, duration: 1.0)
let joeBlushing = SKAction.sequence([joeBlushes, joeBlushes2])
joeBlushingAnimation = SKAction.group([SKAction.repeatForever(joeBlushing)])
joe.run(joeBlushingAnimation)
joe.run(SKAction.repeatForever(
SKAction.animate(with: joeWalkingFrames,
timePerFrame: 0.1,
resize: false,
restore: true)),
withKey:"walkingInPlaceJoe")
}
func moveJoe(location: CGPoint) {
var multiplierForDirection: CGFloat
let joeSpeed = frame.size.width / 3.0
let moveDifference = CGPoint(x: location.x - joe.position.x, y: location.y - joe.position.y)
let distanceToMove = sqrt(moveDifference.x * moveDifference.x + moveDifference.y * moveDifference.y)
let moveDuration = distanceToMove / joeSpeed
if moveDifference.x < 0 {
multiplierForDirection = -1.0
} else {
multiplierForDirection = 1.0
}
joe.xScale = abs(joe.xScale) * multiplierForDirection
if joe.action(forKey: "walkingInPlaceJoe") == nil {
animateJoe()
}
let moveAction = SKAction.move(to: location, duration:(TimeInterval(moveDuration)))
let doneAction = SKAction.run({ [weak self] in
self?.joeMoveEnded()
})
let moveActionWithDone = SKAction.sequence([moveAction, doneAction])
joe.run(moveActionWithDone, withKey:"joeMoving")
}
func joeMoveEnded() {
joe.removeAllActions()
}
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return random() * (max - min) + min
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// 1 - Choose one of the touches to work with
guard let touch = touches.first else {
return
}
let location = touch.location(in: self)
moveJoe(location: location)
}
}
Note: I did not include the math utilities here.
Thanks in advance
z