ios Swift - Group separated sprites with syncronized animation - ios

I am trying to make a synchronized animation (a large video decomposed by frames on separated and smaller puzzle jigsaw parts). This game is a video puzzle. Here is the code I use in three parts by way of example:
func Anim_Puzzle13 (Node13 : SKPuzzle) {
let puzzle13 = SKAction.animateWithTextures(sheet_puzzle13.Puzzle13_(), timePerFrame: 0.066)
NPuzzle13 = Node13
NPuzzle13.runAction(SKAction.repeatActionForever(puzzle13))
NPuzzle13.position = CGPoint(x: 500, y: 400)
NPuzzle13.zPosition = 1
}
func Anim_Puzzle19 (Node19 : SKPuzzle) {
let puzzle19 = SKAction.animateWithTextures(sheet_puzzle19.Puzzle19_(), timePerFrame: 0.066)
NPuzzle19 = Node19
NPuzzle19.runAction(SKAction.repeatActionForever(puzzle19))
NPuzzle19.position = CGPoint(x: 600, y: 500)
NPuzzle19.zPosition = 1
}
func Anim_Puzzle30 (Node30 : SKPuzzle) {
let puzzle30 = SKAction.animateWithTextures(sheet_puzzle30.Puzzle30_(), timePerFrame: 0.066)
NPuzzle30 = Node30
NPuzzle30.runAction(SKAction.repeatActionForever(puzzle30))
NPuzzle30.position = CGPoint(x: 700, y: 600)
NPuzzle30.zPosition = 1
}
It works well but it does not synchronize between the animations and the video has no integrity. I searched for a long time for a solution to make the animations synchronize; I see two possibilities: first is to create a unique SKNode() with all the jigsaw parts inside, but I want to be able to move each jigsaw part independently and have had no success getting a synchronized animation with this method.
The other way seem to be to create a group with all the animations together but this doesn't work, and causes the application to stop.
Here is all the code I use:
import SpriteKit
import UIKit
import AVFoundation
import AVKit
import CoreFoundation
private let kpuzzleNodeName = "puzzle"
private let kdancing = "dancing"
class SKPuzzle: SKSpriteNode {
var name2:String = "";
}
class GameScene: SKScene {
var background = SKVideoNode(videoFileNamed: "Video_Socle.mov")
var selectedNode = SKPuzzle()
var player:AVPlayer?
var videoNode:SKVideoNode?
var NPuzzle13 = SKPuzzle()
var NPuzzle19 = SKPuzzle()
var NPuzzle30 = SKPuzzle()
var NPuzzle11 = SKPuzzle()
var NPuzzle29 = SKPuzzle()
var NPuzzle35 = SKPuzzle()
var puzzle13 = SKAction()
var puzzle19 = SKAction()
var puzzle30 = SKAction()
var puzzle11 = SKAction()
var puzzle29 = SKAction()
var puzzle35 = SKAction()
let sheet_puzzle13 = Puzzle13()
let sheet_puzzle19 = Puzzle19()
let sheet_puzzle30 = Puzzle30()
let sheet_puzzle11 = Puzzle11()
let sheet_puzzle29 = Puzzle29()
let sheet_puzzle35 = Puzzle35()
override init(size: CGSize) {
super.init(size: size)
// 1
self.background.name = kdancing
self.background.anchorPoint = CGPointZero
background.zPosition = 0
self.addChild(background)
// 2
let sheet = Statiques()
let sprite_dancing1 = SKSpriteNode(texture: sheet.Dancing1())
let sprite_dancing2 = SKSpriteNode(texture: sheet.Dancing2())
sprite_dancing1.name = kdancing
sprite_dancing2.name = kdancing
sprite_dancing1.position = CGPoint(x: 837, y: 752)
sprite_dancing1.zPosition = 2
sprite_dancing2.position = CGPoint(x: 1241, y: 752)
sprite_dancing2.zPosition = 2
background.addChild(sprite_dancing1)
background.addChild(sprite_dancing2)
let imageNames = [sheet.Puzzle13() , sheet.Puzzle19(), sheet.Puzzle30(), sheet.Puzzle11(), sheet.Puzzle29(), sheet.Puzzle35() ]
for i in 0..<imageNames.count {
let imageName = imageNames[i]
let sprite = SKPuzzle(texture: imageName)
sprite.name = kpuzzleNodeName
sprite.name2 = "\(i)"
let offsetFraction = (CGFloat(i) + 1.0)/(CGFloat(imageNames.count) + 1.0)
sprite.position = CGPoint(x: size.width * offsetFraction, y: size.height / 2)
sprite.zPosition = 3
background.addChild(sprite)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let positionInScene = touch.locationInNode(self)
selectNodeForTouch(positionInScene)
}
}
override func didMoveToView(view: SKView) {
let urlStr = NSBundle.mainBundle().pathForResource("Video_Socle", ofType: "mov")
let url = NSURL(fileURLWithPath: urlStr!)
player = AVPlayer(URL: url)
NSNotificationCenter.defaultCenter().addObserverForName(AVPlayerItemDidPlayToEndTimeNotification, object: player!.currentItem, queue: nil)
{ notification in
let t1 = CMTimeMake(5, 100);
self.player!.seekToTime(t1)
self.player!.play()
}
videoNode = SKVideoNode(AVPlayer: player!)
videoNode!.position = CGPointMake(frame.size.width/2, frame.size.height/2)
videoNode!.size = CGSize(width: 2048, height: 1536)
videoNode!.zPosition = 0
background.addChild(videoNode!)
videoNode!.play()
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(GameScene.handlePanFrom(_:)))
self.view!.addGestureRecognizer(gestureRecognizer)
}
func handlePanFrom(recognizer : UIPanGestureRecognizer) {
if recognizer.state == .Began {
var touchLocation = recognizer.locationInView(recognizer.view)
touchLocation = self.convertPointFromView(touchLocation)
self.selectNodeForTouch(touchLocation)
} else if recognizer.state == .Changed {
var translation = recognizer.translationInView(recognizer.view!)
translation = CGPoint(x: translation.x, y: -translation.y)
self.panForTranslation(translation)
recognizer.setTranslation(CGPointZero, inView: recognizer.view)
} else if recognizer.state == .Ended {
}
}
func degToRad(degree: Double) -> CGFloat {
return CGFloat(degree / 180.0 * M_PI)
}
func selectNodeForTouch(touchLocation : CGPoint) {
// 1
let touchedNode = self.nodeAtPoint(touchLocation)
if touchedNode is SKPuzzle {
// 2
if !selectedNode.isEqual(touchedNode) {
selectedNode.runAction(SKAction.rotateToAngle(0.0, duration: 0.1))
selectedNode = touchedNode as! SKPuzzle
// 3
if touchedNode.name! == kpuzzleNodeName {
let sequence = SKAction.sequence([SKAction.rotateByAngle(degToRad(-4.0), duration: 0.1),
SKAction.rotateByAngle(0.0, duration: 0.1),
SKAction.rotateByAngle(degToRad(4.0), duration: 0.1)])
selectedNode.runAction(SKAction.repeatActionForever(sequence))
}
}
}
}
func panForTranslation(translation : CGPoint) {
let position = selectedNode.position
if selectedNode.name! == kpuzzleNodeName {
selectedNode.position = CGPoint(x: position.x + translation.x * 2, y: position.y + translation.y * 2)
print (selectedNode.name)
print (selectedNode.name2)
if selectedNode.name2 == "0" {
Anim_Puzzle13(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "1" {
Anim_Puzzle19(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "2" {
Anim_Puzzle30(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "3" {
Anim_Puzzle11(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "4" {
Anim_Puzzle29(selectedNode)
}
print (selectedNode.name2)
if selectedNode.name2 == "5" {
Anim_Puzzle35(selectedNode)
}
}
}
func Anim_Puzzle13 (Node13 : SKPuzzle) {
let puzzle13 = SKAction.animateWithTextures(sheet_puzzle13.Puzzle13_(), timePerFrame: 0.066)
NPuzzle13 = Node13
NPuzzle13.runAction(SKAction.repeatActionForever(puzzle13))
NPuzzle13.position = CGPoint(x: 500, y: 400)
NPuzzle13.zPosition = 1
}
func Anim_Puzzle19 (Node19 : SKPuzzle) {
let puzzle19 = SKAction.animateWithTextures(sheet_puzzle19.Puzzle19_(), timePerFrame: 0.066)
NPuzzle19 = Node19
NPuzzle19.runAction(SKAction.repeatActionForever(puzzle19))
NPuzzle19.position = CGPoint(x: 600, y: 500)
NPuzzle19.zPosition = 1
}
func Anim_Puzzle30 (Node30 : SKPuzzle) {
let puzzle30 = SKAction.animateWithTextures(sheet_puzzle30.Puzzle30_(), timePerFrame: 0.066)
NPuzzle30 = Node30
NPuzzle30.runAction(SKAction.repeatActionForever(puzzle30))
NPuzzle30.position = CGPoint(x: 700, y: 600)
NPuzzle30.zPosition = 1
}
func Anim_Puzzle11 (Node11 : SKPuzzle) {
let puzzle11 = SKAction.animateWithTextures(sheet_puzzle11.Puzzle11_(), timePerFrame: 0.066)
NPuzzle11 = Node11
NPuzzle11.runAction(SKAction.repeatActionForever(puzzle11))
NPuzzle11.position = CGPoint(x: 800, y: 700)
NPuzzle11.zPosition = 1
}
func Anim_Puzzle29 (Node29 : SKPuzzle) {
let puzzle29 = SKAction.animateWithTextures(sheet_puzzle29.Puzzle29_(), timePerFrame: 0.066)
NPuzzle29 = Node29
NPuzzle29.runAction(SKAction.repeatActionForever(puzzle29))
NPuzzle29.position = CGPoint(x: 900, y: 800)
NPuzzle29.zPosition = 1
}
func Anim_Puzzle35 (Node35 : SKPuzzle) {
let puzzle35 = SKAction.animateWithTextures(sheet_puzzle35.Puzzle35_(), timePerFrame: 0.066)
NPuzzle35 = Node35
NPuzzle35.runAction(SKAction.repeatActionForever(puzzle35))
NPuzzle35.position = CGPoint(x: 1000, y: 900)
NPuzzle35.zPosition = 1
}
}
I'm not sure if it's possible to synchronize animations like this: with SKAction() in several separated parts, because it's necessary to be able to select them individually.
UPDATE: I've tried to follow the action group way but I have the same animation playing on each sprite instead of a different animation synchronized for each sprite (6 different animations synchronized: 6 different sprites):
let sheet13 = Puzzle13()
let sheet19 = Puzzle19()
let sheet30 = Puzzle30()
let sheet11 = Puzzle11()
let sheet29 = Puzzle29()
let sheet35 = Puzzle35()
let imageAnims = [sheet13.Puzzle13_0000() , sheet19.Puzzle19_0000(), sheet30.Puzzle30_0000(), sheet11.Puzzle11_0000(), sheet29.Puzzle29_0000(), sheet35.Puzzle35_0000() ]
let puzzle13 = SKAction.animateWithTextures(sheet13.Puzzle13_(), timePerFrame: 0.066)
let puzzle19 = SKAction.animateWithTextures(sheet19.Puzzle19_(), timePerFrame: 0.066)
let puzzle30 = SKAction.animateWithTextures(sheet30.Puzzle30_(), timePerFrame: 0.066)
let puzzle11 = SKAction.animateWithTextures(sheet11.Puzzle11_(), timePerFrame: 0.066)
let puzzle29 = SKAction.animateWithTextures(sheet29.Puzzle29_(), timePerFrame: 0.066)
let puzzle35 = SKAction.animateWithTextures(sheet35.Puzzle35_(), timePerFrame: 0.066)
let group = SKAction.group([puzzle13,puzzle19,puzzle30,puzzle11,puzzle29,puzzle35])
for i in 0..<imageAnims.count {
let imageAnim = imageAnims[i]
let spriteAnim = SKPuzzle(texture: imageAnim)
spriteAnim.name = kanimNodeName
spriteAnim.name2 = "\(i)"
let offsetFraction = (CGFloat(i) + 1.0)/(CGFloat(imageAnims.count) + 1.0)
spriteAnim.position = CGPoint(x: ((size.width)*2) * offsetFraction, y: size.height * 1.5)
spriteAnim.zPosition = 3
spriteAnim.runAction(SKAction.repeatActionForever(group))
background.addChild(spriteAnim)
}

First of all I want to list two differents method to create your SKAction:
Starting with parallel actions by using SKAction.group:
let sprite = SKSpriteNode(imageNamed:"Spaceship")
let scale = SKAction.scaleTo(0.1, duration: 0.5)
let fade = SKAction.fadeOutWithDuration(0.5)
let group = SKAction.group([scale, fade])
sprite.runAction(group)
Another useful method can be the completion , so you can know when an SKAction was finished:
extension SKNode
{
func runAction( action: SKAction!, withKey: String!, optionalCompletion: dispatch_block_t? )
{
if let completion = optionalCompletion
{
let completionAction = SKAction.runBlock( completion )
let compositeAction = SKAction.sequence([ action, completionAction ])
runAction( compositeAction, withKey: withKey )
}
else
{
runAction( action, withKey: withKey )
}
}
}
Usage:
node.runAction(move,withKey:"swipeMove",optionalCompletion: {
// here the action is finished, do whatever you want
})
After that, about your project, I've seen many node.runAction.., you can also adopt this strategy to sinchronize your actions:
var myAction30 :SKAction!
var myAction31 :SKAction!
self.myAction30 = SKAction.repeatActionForever(puzzle30)
self.myAction31 = SKAction.repeatActionForever(puzzle31)
let group = SKAction.group([self.myAction30, self.myAction31])
self.runAction(group)
UPDATE: I've seen your update part, when you speak about "synchronize" probably you don't means the "running in parallel" actions.
So, if you want to run an action after another there is also:
self.myAction30 = SKAction.repeatActionForever(puzzle30)
self.myAction31 = SKAction.repeatActionForever(puzzle31)
let sequence = SKAction.sequence([self.myAction30, self.myAction31])
self.runAction(sequence)

Related

My animated SKSprite nodes atlas won't change during touchBegan

I created a sprite with an animated texture atlas. I then want that animation to change based on the direction the sprite is heading. I try to do so with "self.player!.texture = firstFrametexture(ofatlas)"
Here is where I build the player (put inside didMove but the animation starts without having to move?)
func buildPlayer() {
let playerAnimatedAtlas = SKTextureAtlas(named: "animation")
var walkFrames: [SKTexture] = []
let numImages = playerAnimatedAtlas.textureNames.count
for i in 1...numImages {
let playerTextureName = "player\(i)"
walkFrames.append(playerAnimatedAtlas.textureNamed(playerTextureName))
}
walkingPlayer = walkFrames
let firstFrameTexture = walkingPlayer[0]
player! = SKSpriteNode(texture: firstFrameTexture)
player!.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(player!)
}
Here is where I animate the player
func animatePlayer() {
player!.run(SKAction.repeatForever(
SKAction.animate(with: walkingPlayer,
timePerFrame: 0.5,
resize: false,
restore: true)),
withKey:"walkingInPlacePlayer")
}
Here is where I try to change the animation. Everything works, the if statement are correctly executed. Just nothing changes
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
if let location = touches.first?.location(in: self) {
let horizontalAction = SKAction.move(to: location, duration: 1.0)
horizontalAction.timingMode = SKActionTimingMode.easeOut
player?.run(horizontalAction)
let playerAnimatedAtlas = SKTextureAtlas(named: "animation")
let lplayerAnimatedAtlas = SKTextureAtlas(named: "animationleft")
var walkFrames: [SKTexture] = []
var lwalkFrames: [SKTexture] = []
let numImages = playerAnimatedAtlas.textureNames.count
for i in 1...numImages {
let playerTextureName = "player\(i)"
let playerLeftTextureName = "lplayer\(i)"
walkFrames.append(playerAnimatedAtlas.textureNamed(playerTextureName))
lwalkFrames.append(lplayerAnimatedAtlas.textureNamed(playerLeftTextureName))
}
walkingPlayer = walkFrames
lwalkingPlayer = lwalkFrames
let firstFrameTexture = walkingPlayer[0]
let leftFrameTexture = lwalkingPlayer[0]
if location.x > player!.position.x {
self.player!.texture = firstFrameTexture
print("rightsuccess")
} else if location.x < player!.position.x {
self.player!.texture = leftFrameTexture
print("leftsuccess")
}
}
}

Terminating app due to uncaught exception while running app

I am making a game in which if I press a button the player (circuloPrincipal) changes to the color to a color determinate by the button.
When I run my game sometimes crashes with the error below. I havent find the error, because I cont know how to interpretate
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attemped to add a SKNode which already has a parent: name:'button4' texture:[ 'circuloBoton' (100 x 100)] position:{407, 39} scale:{1.00, 1.00} size:{60, 60} anchor:{0.5, 0.5} rotation:0.00'
circuloPrincipal.size = CGSize(width: 225, height: 225)
circuloPrincipal.position = CGPoint(x: frame.width / 2, y: frame.height / 2)
circuloPrincipal.color = colorAzul
circuloPrincipal.colorBlendFactor = 1.0
circuloPrincipal.physicsBody = SKPhysicsBody(circleOfRadius: circuloPrincipal.size.height / 2)
circuloPrincipal.physicsBody?.contactTestBitMask = physicsCategory.circuloPrincipal
circuloPrincipal.physicsBody?.collisionBitMask = physicsCategory.enemigo
circuloPrincipal.physicsBody?.contactTestBitMask = physicsCategory.enemigo
circuloPrincipal.physicsBody?.affectedByGravity = false
circuloPrincipal.physicsBody?.dynamic = false
circuloPrincipal.name = "circuloPrincipal"
circuloPrincipal.zPosition = 5.0
circuloBlanco.size = CGSize(width: 60, height: 60)
circuloBlanco.position = CGPoint(x: frame.width / 2 - 105 , y: frame.height / 2 - 345)
circuloBlanco.color = colorBlanco
circuloBlanco.colorBlendFactor = 1.0
circuloBlanco.zPosition = 4.0
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
if gameStarted == false {
circuloVerde.removeFromParent()
circuloMorado.removeFromParent()
circuloRojo.removeFromParent()
circuloBlanco.removeFromParent()
circuloPrincipal.color = colorAzul
enemigoTimer = NSTimer.scheduledTimerWithTimeInterval(0.7, target: self, selector: Selector("enemigos"), userInfo: nil, repeats: true)
gameStarted = true
circuloPrincipal.runAction(SKAction.scaleTo(0.44, duration: 0.4))
score = 0
scoreLabel.text = "\(score)"
hits = 0
highscoreLabel.runAction(SKAction.fadeOutWithDuration(0.5))
}
circuloVerde.name = "button"
let touch = touches.first
let positionInScene = touch!.locationInNode(self)
let touchedNode = self.nodeAtPoint(positionInScene)
if let name = touchedNode.name {
if name == "button" {
circuloPrincipal.color = colorVerde
}
}
circuloAmarillo.name = "button2"
let touch2 = touches.first
let positionInScene2 = touch2!.locationInNode(self)
let touchedNode2 = self.nodeAtPoint(positionInScene2)
if let name = touchedNode2.name {
if name == "button2" {
circuloPrincipal.color = colorAmarillo
}
}
circuloAzul.name = "button3"
let touch3 = touches.first
let positionInScene3 = touch3!.locationInNode(self)
let touchedNode3 = self.nodeAtPoint(positionInScene3)
if let name = touchedNode3.name {
if name == "button3" {
//do my stuff
circuloPrincipal.color = colorAzul
}
}
circuloBlanco.name = "button4"
let touch4 = touches.first
let positionInScene4 = touch4!.locationInNode(self)
let touchedNode4 = self.nodeAtPoint(positionInScene4)
if let name = touchedNode4.name {
if name == "button4" {
circuloPrincipal.color = colorBlanco
}
}
circuloRojo.name = "button5"
let touch5 = touches.first
let positionInScene5 = touch5!.locationInNode(self)
let touchedNode5 = self.nodeAtPoint(positionInScene5)
if let name = touchedNode5.name {
if name == "button5" {
circuloPrincipal.color = colorRojo
}
}
circuloMorado.name = "button6"
let touch6 = touches.first
let positionInScene6 = touch6!.locationInNode(self)
let touchedNode6 = self.nodeAtPoint(positionInScene6)
if let name = touchedNode6.name {
if name == "button6" {
circuloPrincipal.color = colorMorado
}
}
}
you're trying to add a node but it already has a parent. its right there in the error message.
you can check to see if it already has a parent like this
let childNode = SKNode()
let parentNode = SKNode()
if childNode.parent == nil {
parentNode.addChild(childNode)
}

How can I match a random texture with another texture for animation?

I have a ball for which I have different colors. The ball has two textures(texture1 and texture2) that I run to do an animation on them. I have different colored balls. Once I call a random function to call any random ball(texture1), my other function doesn't match it with the same ball color(texture2). For instance, if my texture1 calls redBallUp, my other function doesn't match it with redballDown, but randomly calls a texture. Sometimes, it matches it up, but the animation keeps switching between different textures, and sometimes, it doesn't call texture2 at all.
Here's how I set it up:
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
let ballTexture1 = SKTexture(imageNamed: getRandomBallUp())
ballTexture1.filteringMode = SKTextureFilteringMode.Nearest
let ballTexture2 = SKTexture(imageNamed: getRandomBalldDown())
ballTexture2.filteringMode = SKTextureFilteringMode.Nearest
let anim = SKAction.animateWithTextures([ballTexture1, ballTexture2], timePerFrame: 0.15)
let upDown = SKAction.repeatActionForever(anim)
ball = SKSpriteNode(texture: ballTexture1)
ball.position = CGPoint(x: self.frame.size.width / 2.8, y:CGRectGetMidY(self.frame))
ball.runAction(upDown)
self.addChild(ball)
}
func getRandomBallUp() -> String{
let randomval = arc4random_uniform(6)
var ballUp = ""
switch(randomval)
{
case 0:
ballUp = "BlueBallUp"
case 1:
ballUp = "DarkBlueBallUp"
case 2:
ballUp = "GreenBallUp"
case 3:
ballUp = "PurpleBallUp"
case 4:
ballUp = "RedBallUp"
case 5:
ballUp = "YellowBallUp"
default:()
}
return ballUp
}
func getRandomBallDown() -> String{
var ballDown = ""
if (getRandomBallUp() == "BlueBallUp") {
ballDown = "BlueBallDown"
}
if (getRandomBallUp() == "DarkBlueBallUp") {
ballDown = "DarkBlueBallDown"
}
if (getRandomBallUp() == "GreenBallUp") {
ballDown = "GreenBallDown"
}
if (getRandomBallUp() == "PurpleBallUp") {
ballDown = "PurpleBallDown"
}
if (getRandomBallUp() == "RedBallUp") {
ballDown = "RedBallDown"
}
else if (getRandomBallUp() == "YellowBallUp") {
ballDown = "YellowBallDown"
}
return ballDown
}
Every time you call getRandomBallUp() you are generating a random value and returning a string based on that value. To avoid this, uou need to change your getRandomBallDown() to something like:
func getCorrespondingRandomBallDown(ballUp:String) -> String{
var ballDown = ""
if (ballUp == "BlueBallUp") {
ballDown = "BlueBallDown"
}
if (ballUp == "DarkBlueBallUp") {
ballDown = "DarkBlueBallDown"
}
if (getRandomBallUp() == "GreenBallUp") {
ballDown = "GreenBallDown"
}
if (ballUp == "PurpleBallUp") {
ballDown = "PurpleBallDown"
}
if (ballUp == "RedBallUp") {
ballDown = "RedBallDown"
}
else if (ballUp == "YellowBallUp") {
ballDown = "YellowBallDown"
}
return ballDown
}
You need to also change your didMoveToView:
override func didMoveToView(view: SKView) {
let ballUp = getRandomBallUp()
let ballTexture1 = SKTexture(imageNamed: ballUp)
ballTexture1.filteringMode = SKTextureFilteringMode.Nearest
let ballTexture2 = SKTexture(imageNamed: getCorrespondingRandomBallDown(ballUp)
ballTexture2.filteringMode = SKTextureFilteringMode.Nearest
let anim = SKAction.animateWithTextures([ballTexture1, ballTexture2], timePerFrame: 0.15)
let upDown = SKAction.repeatActionForever(anim)
ball = SKSpriteNode(texture: ballTexture1)
ball.position = CGPoint(x: self.frame.size.width / 2.8, y:CGRectGetMidY(self.frame))
ball.runAction(upDown)
self.addChild(ball)
}
beyowulf has the answer, but this is swift baby, lets use some of its features:
func getRandomBall() -> (up:String,down:String){
let randomval = arc4random_uniform(6)
var ball = ""
switch(randomval)
{
case 0:
ball = "BlueBall"
case 1:
ball = "DarkBlueBall"
case 2:
ball = "GreenBall"
case 3:
ball = "PurpleBall"
case 4:
ball = "RedBall"
case 5:
ball = "YellowBall"
default:()
}
return (up:"\(ball)Up",down:"\(ball)Down")
}
override func didMoveToView(view: SKView) {
let ballTextureName = getRandomBall()
let ballTexture1 = SKTexture(imageNamed: ballTextureName.up)
ballTexture1.filteringMode = SKTextureFilteringMode.Nearest
let ballTexture2 = SKTexture(imageNamed: ballTextureName.down)
ballTexture2.filteringMode = SKTextureFilteringMode.Nearest
let anim = SKAction.animateWithTextures([ballTexture1, ballTexture2], timePerFrame: 0.15)
let upDown = SKAction.repeatActionForever(anim)
ball = SKSpriteNode(texture: ballTexture1)
ball.position = CGPoint(x: self.frame.size.width / 2.8, y:CGRectGetMidY(self.frame))
ball.runAction(upDown)
self.addChild(ball)
}

Collect coins and add to score label in Sprite Kit

I'm trying to implement a simple scoring system into my game using this tutorial as a reference:
http://www.raywenderlich.com/87232/make-game-like-mega-jump-sprite-kit-swift-part-2
The problem is, if I try to implement as is, it crashes in the GameScene.swift on this line:
let another = whichNode as! GameObjectNode
Here are the main parts of the code where the player collects the coins. I can also invite you to my repo if you'd like to take a closer and better look. I know it can be hard from looking at the code I pasted up here.
GameObjectNode.swift:
enum CoinType: Int {
case Normal = 0
case Special
}
struct CollisionCategoryBitmask {
static let Player: UInt32 = 0x00
static let Coin: UInt32 = 0x01
static let Platform: UInt32 = 0x02
}
class GameObjectNode: SKNode {
func collisionWithPlayer(player: SKNode) -> Bool {
return false
}
func checkNodeRemoval(playerY: CGFloat) {
if playerY > self.position.y + 300.0 {
self.removeFromParent()
}
}
}
class CoinNode: GameObjectNode {
let coinSound = SKAction.playSoundFileNamed("StarPing.wav", waitForCompletion: false)
var coinType: CoinType!
override func collisionWithPlayer(player: SKNode) -> Bool {
// Boost the player up
player.physicsBody?.velocity = CGVector(dx: player.physicsBody!.velocity.dx, dy: 400.0)
// Play sound
runAction(coinSound, completion: {
// Remove this Star
self.removeFromParent()
})
// Award score
GameState.sharedInstance.score += (coinType == .Normal ? 20 : 100)
// Award stars
GameState.sharedInstance.coins += (coinType == .Normal ? 1 : 5)
// The HUD needs updating to show the new stars and score
return true
}
}
GameState.swift
class GameState {
var score: Int
var highScore: Int
var coins: Int
init() {
// Init
score = 0
highScore = 0
coins = 0
// Load game state
let defaults = NSUserDefaults.standardUserDefaults()
highScore = defaults.integerForKey("highScore")
coins = defaults.integerForKey("coins")
}
func saveState() {
// Update highScore if the current score is greater
highScore = max(score, highScore)
// Store in user defaults
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setInteger(highScore, forKey: "highScore")
defaults.setInteger(coins, forKey: "coins")
NSUserDefaults.standardUserDefaults().synchronize()
}
class var sharedInstance: GameState {
struct Singleton {
static let instance = GameState()
}
return Singleton.instance
}
}
And the GameScene.swift:
import SpriteKit
import CoreMotion
import GameplayKit
struct PhysicsCategory {
static let None: UInt32 = 0
static let Player: UInt32 = 0b1 // 1
static let PlatformNormal: UInt32 = 0b10 // 2
static let PlatformBreakable: UInt32 = 0b100 // 4
static let CoinNormal: UInt32 = 0b1000 // 8
static let CoinSpecial: UInt32 = 0b10000 // 16
static let Edges: UInt32 = 0b100000 // 32
}
class GameScene: SKScene, SKPhysicsContactDelegate {
// Other Properties
...
var player: SKSpriteNode!
// HUD
var hudNode: SKNode!
var lblScore: SKLabelNode!
var lblCoins: SKLabelNode!
override func didMoveToView(view: SKView) {
....
// HUD
hudNode = SKNode()
hudNode.zPosition = 1000
cameraNode.addChild(hudNode)
// Coins
let coin = SKSpriteNode(imageNamed: "powerup05_1")
coin.position = convertPoint(CGPoint(x: 300, y: self.size.height-100), toNode: cameraNode)
coin.zPosition = 1000
hudNode.addChild(coin)
lblCoins = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblCoins.fontSize = 70
lblCoins.fontColor = SKColor.whiteColor()
lblCoins.position = convertPoint(CGPoint(x: 375, y: self.size.height-100), toNode: cameraNode)
lblCoins.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Left
lblCoins.zPosition = 1000
lblCoins.text = String(format: "X %d", GameState.sharedInstance.coins)
hudNode.addChild(lblCoins)
// Score
// 4
lblScore = SKLabelNode(fontNamed: "ChalkboardSE-Bold")
lblScore.fontSize = 70
lblScore.fontColor = SKColor.whiteColor()
lblScore.position = convertPoint(CGPoint(x: self.size.width-325, y: self.size.height-100), toNode: cameraNode)
lblScore.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Right
lblScore.zPosition = 1000
lblScore.text = "0"
hudNode.addChild(lblScore)
}
func setupNodes() {
...
player = fgNode.childNodeWithName("Player") as! SKSpriteNode
}
func createStarAtPosition(position: CGPoint, ofType type: CoinType) -> CoinNode {
// 1
let node = CoinNode()
let thePosition = CGPoint(x: position.x * scaleFactor, y: position.y)
node.position = thePosition
node.name = "NODE_COIN"
// 2
node.coinType = type
var sprite: SKSpriteNode
if type == .Special {
sprite = SKSpriteNode(imageNamed: "CoinSpecial")
} else {
sprite = SKSpriteNode(imageNamed: "Coin")
}
node.addChild(sprite)
// 3
node.physicsBody = SKPhysicsBody(circleOfRadius: sprite.size.width / 2)
// 4
node.physicsBody?.dynamic = false
node.physicsBody?.categoryBitMask = CollisionCategoryBitmask.Coin
node.physicsBody?.collisionBitMask = 0
node.physicsBody?.contactTestBitMask = 0
return node
}
func didBeginContact(contact: SKPhysicsContact) {
let other = contact.bodyA.categoryBitMask == PhysicsCategory.Player ? contact.bodyB : contact.bodyA
var updateHUD = false
let whichNode = (contact.bodyA.node != player) ? contact.bodyA.node : contact.bodyB.node
// Code crashes here
let another = whichNode as! GameObjectNode
updateHUD = another.collisionWithPlayer(player)
if updateHUD {
lblCoins.text = String(format: "X %d", GameState.sharedInstance.coins)
lblScore.text = String(format: "%d", GameState.sharedInstance.score)
}
switch other.categoryBitMask {
case PhysicsCategory.CoinNormal:
if let coin = other.node as? SKSpriteNode {
emitParticles("CollectNormal", sprite: coin)
jumpPlayer()
runAction(soundCoin)
}
case PhysicsCategory.CoinSpecial:
if let coin = other.node as? SKSpriteNode {
emitParticles("CollectSpecial", sprite: coin)
boostPlayer()
runAction(soundBoost)
}
case PhysicsCategory.PlatformNormal:
if let platform = other.node as? SKSpriteNode {
if player.physicsBody!.velocity.dy < 0 {
platformAction(platform, breakable: false)
jumpPlayer()
runAction(soundJump)
}
}
case PhysicsCategory.PlatformBreakable:
if let platform = other.node as? SKSpriteNode {
if player.physicsBody!.velocity.dy < 0 {
platformAction(platform, breakable: true)
jumpPlayer()
runAction(soundBrick)
}
}
default:
break;
}
}
I dont understand the code you use in didBeganContact, but you can define the contact bodies in this way:
enum Ctg:UInt32
{
case Coin = 1
case Hero = 2
case Villain = 4
case Car = 8
}
var hero = SKSpriteNode()
hero.physicsBody = SKPhysicsBody(rectangleOfSize: hero.size)
hero.physicsBody?.categoryBitMask = Ctg.Hero.rawValue
hero.physicsBody?.contactTestBitMask = Ctg.Coin.rawValue | Ctg.Villian.rawValue
var coin = SKSpriteNode()
coin.physicsBody = SKPhysicsBody(rectangleOfSize: coin.size)
coin.physicsBody?.categoryBitMask = Ctg.Coin.rawValue
coin.physicsBody?.contactTestBitMask = Ctg.Hero.rawValue
func didBeginContact(contact: SKPhysicsContact)
{
var first = SKNode()
var sec = SKNode()
// this way you ensure that the first body is the most valuable Ctg (enum)
if contact.bodyA.node?.physicsBody?.categoryBitMask > contact.bodyB.node?.physicsBody?.categoryBitMask
{
first = contact.bodyA.node!
sec = contact.bodyB.node!
}
else
{
first = contact.bodyB.node!
sec = contact.bodyA.node!
}
// this part be sure that the category of first it is of most value that sec
if first.physicsBody!.categoryBitMask == Ctg.Hero.rawValue && sec.physicsBody!.categoryBitMask == Ctg.Coin.rawValue
{
hero.coins++
scene.labelCoins.text = String(coins)
}
if first.physicsBody!.categoryBitMask == Ctg.Villain.rawValue && sec.physicsBody!.categoryBitMask == Ctg.Hero.rawValue
{
gameOver = true
hero.removeFromParent()
lostGame()
}
}

How to make objects exempt from SKcameranode movement

I'm currently developing a scrolling platformer game, and I was wondering how I could have the joystick object move along with the screen but still be useable. Ive tried a number of things, but none of them have produced any viable options. At the moment, the joystick is usable but will scroll off the screen with the rest of the map.
Here is my code:
import SpriteKit
import UIKit
var map = SKNode()
var idleFrames = [SKTexture]()
var walkFrames = [SKTexture]()
var idleFrames1 = [SKTexture]()
var walkFrames1 = [SKTexture]()
var attackFrames1 = [SKTexture]()
var idling = 0
var bullets = 0
var bullet = SKSpriteNode()
var leaf = SKEmitterNode()
var hud: SKSpriteNode?
class GameScene: SKScene, SKPhysicsContactDelegate {
var sp33d: CGVector = CGVectorMake(0.0,0.0)
var knock: CGVector = CGVectorMake(-10.0, 0.0)
var knock1: CGVector = CGVectorMake(10.0, 0.0)
var jsp33d: CGFloat = 170
var gameStick: Joystick?
var player: SKSpriteNode?
var ground: SKSpriteNode?
var ground2: SKSpriteNode?
var ground3: SKSpriteNode?
var canJump = false
var specialbutton = SKSpriteNode(imageNamed: "special")
override func didMoveToView(view: SKView) {
/* Setup your scene here */
hud = self.childNodeWithName("hud") as? SKSpriteNode
gameStick = Joystick()
gameStick?.createJoystick(hud!.frame.width/4, nameBack: "joystick", nameMoving: "joystick1")
gameStick!.backPart!.zPosition = 4
gameStick!.movingPart!.zPosition = 5
map.addChild(gameStick!.backPart!)
map.addChild(gameStick!.movingPart!)
self.addChild(map)
player = self.childNodeWithName("player") as? SKSpriteNode
ground = self.childNodeWithName("testGround") as? SKSpriteNode
ground2 = self.childNodeWithName("testGround2") as? SKSpriteNode
player?.physicsBody?.categoryBitMask = category.player
ground?.physicsBody?.categoryBitMask = category.ground
ground2?.physicsBody?.categoryBitMask = category.ground
player?.physicsBody?.collisionBitMask = category.ground
ground?.physicsBody?.collisionBitMask = category.player
player!.position = CGPoint(x: CGRectGetMidX(self.frame), y: 70)
specialbutton.position = CGPointMake(600, 83)
specialbutton.xScale = 0.165
specialbutton.yScale = 0.165
specialbutton.alpha = 0.5
map.addChild(specialbutton)
camera = self.childNodeWithName("camera") as? SKCameraNode
camera?.position = player!.position
if charnumber == 2{
player?.texture = SKTexture(imageNamed:"Sarah")
}
let idleAtlas = SKTextureAtlas(named: "idle.atlas")
var idleframes = [SKTexture]()
for var i=1; i<=4; i++ {
let idleframe = "JohnIdle\(i)"
idleframes.append(idleAtlas.textureNamed(idleframe))
}
idleFrames = idleframes
let walkAtlas = SKTextureAtlas(named: "jrun.atlas")
var walkframes = [SKTexture]()
for var i=1; i<=8; i++ {
let walkframe = "Johnrun\(i)"
walkframes.append(walkAtlas.textureNamed(walkframe))
}
walkFrames = walkframes
let idleAtlas1 = SKTextureAtlas(named: "Sarahidle.atlas")
var idleframes1 = [SKTexture]()
for var i=1; i<=4; i++ {
let idleframe1 = "SarahIdle\(i)"
idleframes1.append(idleAtlas1.textureNamed(idleframe1))
}
idleFrames1 = idleframes1
let walkAtlas1 = SKTextureAtlas(named: "Sarahrun.atlas")
var walkframes1 = [SKTexture]()
for var i=1; i<=8; i++ {
let walkframe1 = "Sarahrun\(i)"
walkframes1.append(walkAtlas1.textureNamed(walkframe1))
}
walkFrames1 = walkframes1
let attackAtlas1 = SKTextureAtlas(named: "sattack.atlas")
var attackframes1 = [SKTexture]()
for var i=1; i<=9; i++ {
let attackframe1 = "sattack\(i)"
attackframes1.append(attackAtlas1.textureNamed(attackframe1))
}
attackFrames1 = attackframes1
self.physicsWorld.gravity = CGVectorMake(0, -10.0)
self.physicsWorld.contactDelegate = self
}
func didBeginContact(contact:SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == category.player) && (contact.bodyB.categoryBitMask == category.ground) {
idling = 0
johnmove()
print("hit")
canJump = true
}else{
}
}
func didEndContact(contact: SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == category.player) && (contact.bodyB.categoryBitMask == category.ground) {
canJump = false
}
}
func bulletfire(){
bullet = SKSpriteNode(imageNamed: "bullet1")
leaf = SKEmitterNode(fileNamed: "leafParticle")!
bullets = bullets + 1
bullet.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(0.1, 0.1))
bullet.physicsBody?.collisionBitMask = category.ground
bullet.xScale = 0.016
bullet.yScale = 0.016
bullet.physicsBody?.affectedByGravity = false
self.addChild(bullet)
self.addChild(leaf)
if player?.xScale == 1{
bullet.xScale = -0.016
bullet.position.x = (player?.position.x)! + 21.5
bullet.position.y = (player?.position.y)! + 15.4
bullet.physicsBody?.velocity = (CGVectorMake(1000.0, 0.0))
}else{
bullet.position.x = (player?.position.x)! - 21.5
bullet.position.y = (player?.position.y)! + 15.4
bullet.physicsBody?.velocity = (CGVectorMake(-1000.0, 0.0))
}
let action = SKAction.sequence([SKAction.waitForDuration(1), SKAction.removeFromParent()])
bullet.runAction(action, completion: {bullets = bullets - 1})
leaf.runAction(action)
}
func move(){
if player?.xScale == 1 {
player?.size = CGSizeMake(80,80)
player?.position.x = (player?.position.x)! - 20
}else{
player?.size = CGSizeMake(80,80)
player?.position.x = (player?.position.x)! + 20
}
}
func johnmove() {
if charnumber == 1 {
if idling == 1 {
player?.size = CGSizeMake(80,80)
player?.removeActionForKey("idle")
player?.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(walkFrames, timePerFrame: 0.12, resize: false, restore: true)),withKey: "walk")
}
else if idling == 0 {
player?.removeActionForKey("walk")
player?.size = CGSizeMake(80,80)
player?.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(idleFrames, timePerFrame: 0.6, resize: false, restore: true)),withKey: "idle")
}else if idling == 2 {
player?.removeActionForKey("walk")
player?.removeActionForKey("idle")
player?.size = CGSizeMake(80,80)
player?.texture = SKTexture(imageNamed: "JohnJump.png")
}
}else{
sarahhmove()
}
}
func sarahhmove() {
if idling == 1 {
player?.removeActionForKey("idle1")
player?.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(walkFrames1, timePerFrame: 0.12, resize: true, restore: true)),withKey: "walk1")
}
else if idling == 0 {
player?.removeActionForKey("walk1")
player?.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(idleFrames1, timePerFrame: 0.6, resize: false, restore: true)),withKey: "idle1")
}else if idling == 2 {
player?.removeActionForKey("wal1k")
player?.removeActionForKey("idle1")
player?.texture = SKTexture(imageNamed: "SarahJump.png")
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
var nodeTouched = SKNode()
nodeTouched = self.nodeAtPoint(location)
if nodeTouched.name == "joystick1" {
gameStick?.movingPart?.position = location
if location.x > gameStick!.backPart!.position.x + gameStick!.backPart!.frame.width/2{
gameStick?.movingPart?.position = CGPointMake(gameStick!.backPart!.position.x + gameStick!.backPart!.frame.width/2, gameStick!.movingPart!.position.y)
}
if location.y > gameStick!.backPart!.position.y + gameStick!.backPart!.frame.height/2{
gameStick?.movingPart?.position = CGPointMake(gameStick!.movingPart!.position.x, gameStick!.backPart!.position.y + gameStick!.backPart!.frame.height/2)
}
}
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in (touches ) {
let location = touch.locationInNode(self)
var nodeTouched = SKNode()
nodeTouched = self.nodeAtPoint(location)
if nodeTouched.name == "joystick1" {
gameStick?.movingPart?.position = location
if location.x > gameStick!.backPart!.position.x + gameStick!.backPart!.frame.width/2{
gameStick?.movingPart?.position = CGPointMake(gameStick!.backPart!.position.x + gameStick!.backPart!.frame.width/2, gameStick!.movingPart!.position.y)
}
if location.y > gameStick!.backPart!.position.y + gameStick!.backPart!.frame.height/2{
gameStick?.movingPart?.position = CGPointMake(gameStick!.movingPart!.position.x, gameStick!.backPart!.position.y + gameStick!.backPart!.frame.height/2)
}
}else if idling == 0 && charnumber == 2{
player?.size = CGSizeMake(80,80)
player?.removeAllActions()
if player?.xScale == 1 {
player?.size = CGSizeMake(80,80)
player?.position.x = (player?.position.x)! + 20
}else{
player?.size = CGSizeMake(80,80)
player?.position.x = (player?.position.x)! - 20
}
player?.size = CGSizeMake(80,80)
player?.runAction(SKAction.repeatAction(SKAction.animateWithTextures(attackFrames1, timePerFrame: 0.09, resize: true, restore: true),count: 1),completion: {self.move()})
player?.size = CGSizeMake(80,80)
player?.texture = SKTexture(imageNamed: "Sarah")
}else if charnumber == 1 && idling == 0{
player?.removeAllActions()
bulletfire()
let yrand = (arc4random_uniform(100) + 50)
let xrand = (arc4random_uniform(300) + 80)
let cartridge = SKSpriteNode(imageNamed: "casing")
cartridge.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(0.1, 0.1))
cartridge.physicsBody?.collisionBitMask = category.ground
cartridge.xScale = 0.05
cartridge.yScale = 0.05
cartridge.zPosition = 3
cartridge.physicsBody?.restitution = 0.5
let spin = SKAction.rotateByAngle(CGFloat(M_PI), duration:0.6)
cartridge.runAction(SKAction.repeatActionForever(spin))
cartridge.physicsBody?.dynamic = true
let flash = SKEmitterNode(fileNamed: "muzzleFlash")
if player?.xScale == 1{
leaf.xScale = -1
flash?.position.x = (player?.position.x)! + 40
flash?.position.y = (player?.position.y)! + 15.3
cartridge.position.x = (player?.position.x)! + 27
cartridge.position.y = (player?.position.y)! + 15.3
player?.physicsBody?.applyImpulse(knock)
cartridge.physicsBody?.velocity = CGVectorMake(-CGFloat(yrand), CGFloat(xrand))
}else{
flash?.position.x = (player?.position.x)! - 40
flash?.position.y = (player?.position.y)! + 15.3
flash?.xAcceleration = -5000
cartridge.position.x = (player?.position.x)! - 27
cartridge.position.y = (player?.position.y)! + 15.3
player?.physicsBody?.applyImpulse(knock1)
cartridge.physicsBody?.velocity = CGVectorMake(CGFloat(yrand), CGFloat(xrand))
}
flash?.zPosition = 3
flash?.xScale = 0.15
flash?.yScale = 0.15
self.addChild(flash!)
self.addChild(cartridge)
let action = SKAction.sequence([SKAction.waitForDuration(0.15), SKAction.removeFromParent()])
let action1 = SKAction.sequence([SKAction.waitForDuration(1.5), SKAction.removeFromParent()])
flash?.runAction(action)
cartridge.runAction(action1)
johnmove()
}
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
var nodeTouched = SKNode()
nodeTouched = self.nodeAtPoint(location)
if nodeTouched.name == "joystick1" {
let act = SKAction.moveTo(gameStick!.backPart!.position, duration: 0.2)
gameStick?.movingPart?.runAction(act)
}
}
}
override func update(currentTime: CFTimeInterval) {
hud!.position = (camera?.position)!
let action = SKAction.moveTo((player?.position)!, duration: 0.01)
camera!.runAction(action)
player?.size = CGSizeMake(80,80)
leaf.position = bullet.position
print(canJump)
if (sp33d.dx > 1.5 || sp33d.dx < -1.5) && idling != 1 && idling != 2 {
idling = 1
johnmove()
}else if sp33d.dx < 0.1 && sp33d.dx > -0.1 && idling != 0 && idling != 2{
idling = 0
johnmove()
}
if sp33d.dx > 0.1 {
player!.xScale = 1
} else if sp33d.dx < -0.1 {
player!.xScale = -1
}
/* Called before each frame is rendered */
let vX = gameStick!.movingPart!.position.x - gameStick!.backPart!.position.x
let vY: CGFloat = gameStick!.movingPart!.position.y
if vY > gameStick!.backPart!.position.y + 20 && canJump == true{
sp33d = CGVectorMake(vX/13, jsp33d)
idling = 2
johnmove()
}else{
sp33d = CGVectorMake(vX/13, 0)
}
player?.physicsBody?.applyImpulse(sp33d)
}
}
This is the class in which the joystick is created:
import Foundation
import UIKit
import SpriteKit
class Joystick: UIView {
var movingPart: SKSpriteNode?
var backPart: SKSpriteNode?
let speed: CGFloat = 0.4
var joyStickCenter: CGPoint?
func createJoystick(dimensions: CGFloat, nameBack: String, nameMoving: String)
{
backPart = SKSpriteNode(imageNamed: "joystick")
backPart?.size = CGSizeMake(dimensions, dimensions)
backPart?.position = CGPoint(x: backPart!.size.width/2, y: backPart!.size.width/2)
backPart?.name = nameBack
backPart?.alpha = 0.4
movingPart = SKSpriteNode(imageNamed: "joystick")
movingPart?.size = CGSizeMake(dimensions*0.5, dimensions*0.5)
movingPart?.position = backPart!.position
movingPart?.name = nameMoving
movingPart?.alpha = 0.8
joyStickCenter = backPart!.position
}
func getDistance(p1: CGPoint, p2: CGPoint) -> Double
{
let firstPow = p2.x-p1.x
let secondPow = p2.y-p1.y
var squaredAdded = pow(firstPow, 2)
squaredAdded += pow(secondPow, 2)
let theSquirt = sqrt(Double(squaredAdded))
return theSquirt
}
func resetMovingPart()
{
movingPart?.runAction(SKAction.moveTo(joyStickCenter!, duration: 0.4))
}
func calcXYDiff(loc: CGPoint) -> CGPoint
{
let oldMovingPartPoint = movingPart?.position
movingPart?.position = loc
if movingPart!.position.x-joyStickCenter!.x > backPart!.frame.width/2
{
movingPart?.position.x = oldMovingPartPoint!.x
}
if movingPart!.position.y-joyStickCenter!.y > backPart!.frame.height/2
{
movingPart?.position.y = oldMovingPartPoint!.y
}
let x = loc.x - joyStickCenter!.x
let y = loc.y - joyStickCenter!.y
return CGPoint(x: x*speed, y: y*speed)
}
Any help would be greaty appreciated.
Thanks in advance!
Try calling the resetMovingPart() in your update() func.

Resources