How to make objects exempt from SKcameranode movement - ios

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.

Related

Why am I getting "Exception caught in AudioQueueInternalNotifyRunning - error -66671" when playing audio?

I have three different AVAudio instances. When trying to play my sound that is "audioPlayer3" I get an exception. Can someone take a look for me?" Also when clicking the button "playAgain"
button it plays "audioPlayer3" and I am not sure why. "audioPlayer" and audioPlayer2 work just fine. The issue is only with "audioPlayer3".
import AVFoundation
import SpriteKit
import GameplayKit
import GameKit
class EggCatchScene: SKScene {
var mainMenuButton = SKSpriteNode(imageNamed: "mainmenuButton2")
var isfacingRight = true;
var isfacingLeft = false
var audioPlayer3 : AVAudioPlayer!
var audioPlayer = AVAudioPlayer()
var audioPlayer2 = AVAudioPlayer()
var submitButton = SKSpriteNode(imageNamed: "submitButton.png")
var scoresubmitAlert = SKSpriteNode(imageNamed: "scoresubmittedAlert.png")
var playagainButton2 = SKSpriteNode(imageNamed: "playagainButton")
var levelLabel: SKLabelNode!
var scoreLabel: SKLabelNode!
var gameoverscoreLabel: SKLabelNode!
var birdSprite = SKSpriteNode(imageNamed: "birdAnimation1.png")
var playagainButton = SKSpriteNode(imageNamed: "playagainButton")
var gameoverScreen = SKSpriteNode(imageNamed: "gameoverScreen")
var leftbuttonisPressed = false
var rightbuttonisPressed = false
var score = 0
private var bear = SKSpriteNode()
private var bearWalkingFrames: [SKTexture] = []
var rightButton = SKSpriteNode(imageNamed: "rightButton")
var eggcatchBackground = SKSpriteNode(imageNamed: "eggcatchBackground")
var leftButton = SKSpriteNode(imageNamed: "leftButton")
var eggcatchGround = SKSpriteNode(imageNamed: "eggcatchGround2")
var flyButton = SKSpriteNode(imageNamed: "upButton")
var eggSprite = SKSpriteNode(imageNamed: "eggSprite")
var number = Int.random(in: 20..<620)
override func didMove(to view: SKView) {
let sound = Bundle.main.path(forResource: "bgMusic.mp3", ofType: nil)!
let url = URL(fileURLWithPath: sound)
do{
audioPlayer2 = try AVAudioPlayer(contentsOf: url)
audioPlayer2.play()
audioPlayer2.numberOfLoops = 1
} catch {
print(error)
}
let atlas = SKTextureAtlas(named: "BirdAnimation")
let m1 = atlas.textureNamed("birdAnimation1.png")
let m2 = atlas.textureNamed("birdAnimation2.png")
let m3 = atlas.textureNamed("birdAnimation3.png")
let m4 = atlas.textureNamed("birdAnimation4.png")
let m5 = atlas.textureNamed("birdAnimation5.png")
let textures = [m1, m2, m3, m4, m5]
let meleeAnimation = SKAction.animate(with: textures, timePerFrame: 0.07)
birdSprite.run(SKAction.repeatForever(meleeAnimation))
birdSprite.position = CGPoint(x: frame.midX, y: frame.midY)
birdSprite.zPosition = 2
birdSprite.setScale(1)
self.addChild(birdSprite)
eggcatchBackground.position = CGPoint(x: frame.midX, y: frame.midY)
eggcatchBackground.zPosition = 0
eggcatchBackground.size.height = self.size.height
eggcatchBackground.size.width = self.size.width
self.addChild(eggcatchBackground)
mainMenuButton.isHidden = true
mainMenuButton.position = CGPoint(x: frame.midX, y: frame.midY - 260)
mainMenuButton.zPosition = 5
mainMenuButton.setScale(0.5)
self.addChild(mainMenuButton)
submitButton.isHidden = true
submitButton.position = CGPoint(x: frame.midX, y: frame.midY - 75)
submitButton.zPosition = 5
submitButton.setScale(0.5)
self.addChild(submitButton)
gameoverScreen.isHidden = true
gameoverScreen.position = CGPoint(x: frame.midX, y: frame.midY)
gameoverScreen.zPosition = 5
gameoverScreen.setScale(0.5)
self.addChild(gameoverScreen)
eggSprite.position = CGPoint(x: frame.midX, y: self.size.height)
eggSprite.zPosition = 2
eggSprite.setScale(0.2)
self.addChild(eggSprite)
eggcatchGround.position = CGPoint(x: frame.midX, y: 25)
eggcatchGround.zPosition = 2
eggcatchGround.size.width = self.size.width
self.addChild(eggcatchGround)
scoresubmitAlert.isHidden = true
scoresubmitAlert.position = CGPoint(x: frame.midX, y:frame.midY + 65)
scoresubmitAlert.zPosition = 3
scoresubmitAlert.setScale(0.7)
self.addChild(scoresubmitAlert)
flyButton.position = CGPoint(x: 550, y:150 )
flyButton.zPosition = 3
flyButton.setScale(0.2)
self.addChild(flyButton)
playagainButton.isHidden = true
playagainButton.position = CGPoint(x: frame.midX, y:frame.midY )
playagainButton.zPosition = 3
playagainButton.setScale(0.5)
self.addChild(playagainButton)
playagainButton2.isHidden = true
playagainButton2.position = CGPoint(x: frame.midX, y:frame.midY - 320 )
playagainButton2.zPosition = 3
playagainButton2.setScale(0.5)
self.addChild(playagainButton2)
rightButton.position = CGPoint(x: 240, y:150 )
rightButton.zPosition = 3
rightButton.setScale(0.2)
self.addChild(rightButton)
leftButton.position = CGPoint(x: 85, y:150 )
leftButton.zPosition = 3
leftButton.setScale(0.2)
self.addChild(leftButton)
scoreLabel = SKLabelNode(fontNamed: "Chalkduster")
scoreLabel.zPosition = 2
scoreLabel.fontColor = UIColor.red
scoreLabel.position = CGPoint(x: 100, y: 800)
addChild(scoreLabel)
levelLabel = SKLabelNode(fontNamed: "Chalkduster")
levelLabel.zPosition = 2
levelLabel.fontColor = UIColor.red
levelLabel.position = CGPoint(x: 550, y: 800)
addChild(levelLabel)
}
func checkforCollision(){
if(eggSprite.frame.intersects(eggcatchGround.frame)) || (birdSprite.frame.intersects(eggcatchGround.frame)){
let sound = Bundle.main.path(forResource: "gameoverSound.wav", ofType: nil)!
let url = URL(fileURLWithPath: sound)
do{
audioPlayer3 = try AVAudioPlayer(contentsOf: url)
audioPlayer3.play()
audioPlayer3.numberOfLoops = 0
} catch {
print(error)
}
eggSprite.position.y = 960
submitButton.isHidden = false
playagainButton.isHidden = false
self.birdSprite.removeFromParent()
self.eggSprite.removeFromParent()
self.rightButton.removeFromParent()
self.leftButton.removeFromParent()
self.flyButton.removeFromParent()
print("Game Over")
}
}
override func update(_ currentTime: TimeInterval){
birdSprite.position.y -= 1
checkforCollision()
scoreLabel.text = "Score: \(score)"
if(rightbuttonisPressed == true){
birdSprite.xScale = 1;
birdSprite.position.x += 10
}
if(leftbuttonisPressed == true){
birdSprite.position.x -= 10
birdSprite.xScale = -1;
}
if (score <= 10){
levelLabel.text = "Level 1"
eggSprite.position.y -= 1
}
if (score >= 10){
levelLabel.text = "Level 2"
eggSprite.position.y -= 1.1
}
if (score >= 20){
levelLabel.text = "Level 3"
eggSprite.position.y -= 1.2
}
if (score >= 30){
levelLabel.text = "Level 4"
eggSprite.position.y -= 1.3
}
if (score >= 40){
levelLabel.text = "Level 5"
eggSprite.position.y -= 1.4
}
if (score >= 60){
levelLabel.text = "Level 6"
eggSprite.position.y -= 1.5
}
if (score >= 70){
levelLabel.text = "Level 7"
eggSprite.position.y -= 1.6
}
if (score >= 80){
levelLabel.text = "Level 8"
eggSprite.position.y -= 1.7
}
if (score >= 90){
levelLabel.text = "Level 9"
eggSprite.position.y -= 1.8
}
if (score >= 100){
levelLabel.text = "Level 10"
eggSprite.position.y -= 1.9
}
if (score >= 110){
levelLabel.text = "Level 11"
eggSprite.position.y -= 2
}
if (score >= 120){
levelLabel.text = "Level 12"
eggSprite.position.y -= 2.1
}
if (score >= 130){
levelLabel.text = "Level 13"
eggSprite.position.y -= 2.2
}
if (score >= 140){
levelLabel.text = "Level 14"
eggSprite.position.y -= 2.3
}
if (score >= 150){
levelLabel.text = "Max"
eggSprite.position.y -= 2.4
}
/* if(birdSprite.frame.intersects(eggcatchGround.frame)){
// gameoverScreen.isHidden = false
let sound = Bundle.main.path(forResource: "gameoverSound", ofType: "mp3")!
let url = URL(fileURLWithPath: sound)
do{
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.play()
audioPlayer.numberOfLoops = 0
} catch {
print(error)
}
submitButton.isHidden = false
playagainButton.isHidden = false
self.birdSprite.removeFromParent()
self.eggSprite.removeFromParent()
self.rightButton.removeFromParent()
self.leftButton.removeFromParent()
self.flyButton.removeFromParent()
print("Game Over")
}*/
let xRange = SKRange(lowerLimit:0,upperLimit:size.width)
let yRange = SKRange(lowerLimit:0,upperLimit:size.height)
//sprite.constraints = [SKConstraint.positionX(xRange,Y:yRange)] // iOS 9
birdSprite.constraints = [SKConstraint.positionX(xRange,y:yRange)] // iOS 10
if(eggSprite.frame.intersects(birdSprite.frame)){
let sound = Bundle.main.path(forResource: "itemGet.wav", ofType: nil)!
let url = URL(fileURLWithPath: sound)
do{
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.play()
audioPlayer.numberOfLoops = 0
} catch {
print(error)
}
eggSprite.position.y = self.size.height
//eggSprite.position.x = number
score += 1
}
}
/*func startTimer()
{
countdownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(decrementCounter), userInfo: nil, repeats: true)
}*/
func decrementTimer(){
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if submitButton.frame.contains(location) {
//submitButton.isHidden = true
submitButton.removeFromParent()
mainMenuButton.isHidden = false
playagainButton.removeFromParent()
playagainButton2.isHidden = false
scoresubmitAlert.isHidden = false
let score1 = GKScore(leaderboardIdentifier: "birdmemoirsleaderboard")
score1.value = Int64(score)
GKScore.report([score1]) { error in
guard error == nil else {
print(error?.localizedDescription ?? "")
return
}
print("done")
}
print("clicked")
}
if playagainButton.frame.contains(location) {
if let eggcatchScene = EggCatchScene(fileNamed: "EggCatchScene") {
let eggcatchScene = EggCatchScene(size: CGSize(width:640, height: 960))
self.view?.presentScene(eggcatchScene, transition: SKTransition.fade(withDuration: 1))
}
}
if playagainButton2.frame.contains(location) {
if let eggcatchScene = EggCatchScene(fileNamed: "EggCatchScene") {
let eggcatchScene = EggCatchScene(size: CGSize(width:640, height: 960))
self.view?.presentScene(eggcatchScene, transition: SKTransition.fade(withDuration: 1))
}
}
if mainMenuButton.frame.contains(location) {
if let mainmenuScene = GameScene2(fileNamed: "GameScene2") {
let mainmenuScene = GameScene2(size: CGSize(width:640, height: 960))
self.view?.presentScene(mainmenuScene, transition: SKTransition.fade(withDuration: 1))
}
}
if flyButton.frame.contains(location) {
birdSprite.position.y += 50
}
if rightButton.frame.contains(location) {
print("clicked")
rightbuttonisPressed = true
//sprite.position.x += 10
}
if leftButton.frame.contains(location) {
print("clicked")
leftbuttonisPressed = true
birdSprite.xScale = -1; }
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
if leftButton.contains(touch.location(in: self)) {
leftbuttonisPressed = false
}
if rightButton.contains(touch.location(in: self)) {
rightbuttonisPressed = false
}
}
}```

Collide type source error - spritekit swift game

So I have adjusted my games ball type from a shape to an image which forced me to redo the physics of my game. I am new to swift and have struggled with fixing my collisions in my swift game.
class GameScene: SKScene, GameDelegate, SKPhysicsContactDelegate {
var ball: Ball!
let ballSpeedX = CGFloat(500)
//ball = Ball(imageNamed:"colorBall.png")
enum CollisionTypes: UInt32 {
case Floor = 1
case Ball = 2
}
// board
let boards = Boards.make(CollideType.BoardStart.rawValue)
var lastBoard: SKNode?
var boardSpeedY: CGFloat { get { return CGFloat(160) * accelerate }}
let boardDistanceY = CGFloat(300)
let boardYDistanceHide = CGFloat(30)
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVectorMake(0, 0)
self.physicsWorld.contactDelegate = self
let flooeBody = SKPhysicsBody.init(edgeLoopFromRect: self.frame)
self.physicsBody = floorBody
self.physicsBody!.affectedByGravity = false
self.physicsBody!.usesPreciseCollisionDetection = true
self.physicsBody!.dynamic = true
self.physicsBody!.mass = 0
self.physicsBody!.friction = 0
self.physicsBody!.linearDamping = 0
self.physicsBody!.angularDamping = 0
self.physicsBody!.restitution = 1
self.physicsBody!.categoryBitMask = CollisionTypes.Floor.rawValue
self.physicsBody!.contactTestBitMask = CollisionTypes.Ball.rawValue
// Prepare the ball - physics engine.
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.frame.width/2)
ball.physicsBody!.affectedByGravity = true
ball.physicsBody!.restitution = 0.8
ball.physicsBody!.linearDamping = 0
ball.physicsBody!.friction = 0.3
ball.physicsBody!.dynamic = true
ball.physicsBody!.mass = 0.5
ball.physicsBody!.allowsRotation = true
ball.physicsBody!.categoryBitMask = CollisionTypes.Ball.rawValue
ball.physicsBody!.contactTestBitMask = CollisionTypes.Floor.rawValue
ball.physicsBody!.collisionBitMask = CollisionTypes.Floor.rawValue
ball.hidden = false
self.addChild(ball)
// scene
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody!.categoryBitMask = CollideType.Scene.toMask()
self.physicsBody!.dynamic = false
self.physicsBody!.friction = 0
// ceil
let ceil = SKShapeNode(rectOfSize: CGSize(width: self.frame.width, height: 2))
ceil.position.x = CGRectGetMidX(self.frame)
ceil.position.y = self.frame.height - CGRectGetMidY(ceil.frame)
ceil.physicsBody = SKPhysicsBody(rectangleOfSize: ceil.frame.size)
ceil.physicsBody!.categoryBitMask = CollideType.Ceil.toMask()
ceil.physicsBody!.dynamic = false
ceil.alpha = 0
self.addChild(ceil)
// floor
let floor = SKShapeNode(rectOfSize: CGSize(width: self.frame.width, height: 2))
floor.position.x = CGRectGetMidX(self.frame)
floor.position.y = CGRectGetMidY(floor.frame)
floor.physicsBody = SKPhysicsBody(rectangleOfSize: floor.frame.size)
//floor.physicsBody!.categoryBitMask = CollideType.Floor.toMask() two
floor.physicsBody!.dynamic = false
floor.alpha = 0
self.addChild(floor)
}
That is the scene and physics I attempted to set up and was directed with. Below is the collide errors which cause the app to crash upon touch.
func didBeginContact(contact: SKPhysicsContact) {
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollisionTypes.Floor.rawValue && contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue
let ballAndBoardMask = CollideType.Ball.toMask() | boards.usedCollideMasks
// ball and board error: CANNOT CONVERT VALUE OF TYPE BOOL TO EXPCTD ARG TYPE UIINT32
if bitMaskAAndB | ballAndBoardMask == ballAndBoardMask {
let boardNode: SKNode! = contact.bodyA.categoryBitMask == CollideType.Ball.toMask() ? contact.bodyB.node : contact.bodyA.node
let board = boardNode.bind as! BoardDelegate
board.didBeginContact(boardNode, ball: ball, contact: contact, game: self)
}
// ball and ceil => ERROR
else if bitMaskAAndB == CollideType.toMask([.Ball, .Ceil]) {
stopGame()
}
// ball and floor => stop game
else if bitMaskAAndB == CollideType.toMask([.Ball, .Floor]) {
stopGame()
}
}
func didEndContact(contact: SKPhysicsContact) {
let ballAndBoardMask = CollideType.Ball.toMask() | boards.usedCollideMasks
// ball and board, handle it by board delegate
if contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask | ballAndBoardMask == ballAndBoardMask {
let boardNode: SKNode! = contact.bodyA.categoryBitMask == CollideType.Ball.toMask() ? contact.bodyB.node : contact.bodyA.node
let board = boardNode.bind as! BoardDelegate
board.didEndContact(boardNode, ball: ball, contact: contact, game: self)
}
}
CollideType definition as below:
enum CollideType: Int {
case Scene = 0
case Ceil = 1
case Floor = 2
case Ball = 3
case BoardStart = 4
func toMask()-> UInt32 {
return UInt32(1 << self.rawValue)
}
static func toMask(masks: [CollideType])-> UInt32 {
var toMask = UInt32(0)
for type in masks {
toMask |= type.toMask()
}
return toMask
}
So the issue now is that you have two definition for your masks:
Remove this one:
enum CollisionTypes: UInt32 {
case Floor = 1
case Ball = 2
}
Use only this one:
enum CollideType: Int {
case Scene = 0
case Ceil = 1
case Floor = 2
case Ball = 3
case BoardStart = 4
func toMask()-> UInt32 {
return UInt32(1 << self.rawValue)
}
static func toMask(masks: [CollideType])-> UInt32 {
var toMask = UInt32(0)
for type in masks {
toMask |= type.toMask()
}
return toMask
}
Correct all code to match with CollideType definitions.
Correct this line in didBeginContact:
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollisionTypes.Floor.rawValue && contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue
with:
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollideType.Floor.toMask() ? contact.bodyB.categoryBitMask : CollideType.Ball.toMask()
If you have correct all you will don't have yet this error:
// ball and ceil => ERROR

ios Swift - Group separated sprites with syncronized animation

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)

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()
}
}

Resources