Sprite Kit how to apply boundaries - ios

I am currently new for sprite kit and I am very confused my player goes all the way right outside of the frame, however I have included this part of code
let frame = SKPhysicsBody(edgeLoopFrom: self.frame)
frame.friction = 0
frame.restitution = 1
frame.categoryBitMask = bitMask.frame.rawValue
frame.contactTestBitMask = bitMask.player.rawValue
frame.collisionBitMask = bitMask.player.rawValue
self.physicsBody = frame
The full code is bellow
class GameScene : SKScene, SKPhysicsContactDelegate {
let background = SKSpriteNode(imageNamed: "bg")
let player = SKSpriteNode(imageNamed: "PlayerJump")
let ground = SKSpriteNode(imageNamed: "ground")
let gameOverLine = SKSpriteNode(color: .red, size: CGSize(width: 900, height: 10))
let rightBorderLine = SKSpriteNode(color: .red, size: CGSize(width: 10, height: 900))
let scoreLabel = SKLabelNode()
let bestScoreLabel = SKLabelNode()
let defaults = UserDefaults.standard
let cam = SKCameraNode()
let motionManager = CMMotionManager()
var firstTouch = false
var score = 0
var bestScore = 0
var multi: CGFloat = 0.0
enum bitMask: UInt32 {
case player = 0b1
case platform = 0b10
case gameOverLine
case frame
}
override func didMove(to view: SKView) {
self.size = CGSize(width: UIScreen.main.bounds.width * 2, height: UIScreen.main.bounds.height * 2)
self.anchorPoint = .zero
background.position = CGPoint(x: size.width / 2, y: size.height / 2)
background.zPosition = 1
addChild(background)
physicsWorld.contactDelegate = self
ground.position = CGPoint(x: size.width / 2, y: 10)
ground.zPosition = 5
ground.setScale(2.5)
ground.physicsBody = SKPhysicsBody(rectangleOf: ground.size)
ground.physicsBody?.isDynamic = false
ground.physicsBody?.allowsRotation = false
ground.physicsBody?.affectedByGravity = false
addChild(ground)
player.position = CGPoint(x: size.width / 2, y: size.height/8)
player.zPosition = 10
player.setScale(1.8)
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.height / 2)
player.physicsBody?.isDynamic = false
player.physicsBody?.restitution = 1
player.physicsBody?.friction = 0
player.physicsBody?.angularDamping = 1
player.physicsBody?.categoryBitMask = bitMask.player.rawValue
player.physicsBody?.collisionBitMask = 0
player.physicsBody?.contactTestBitMask = bitMask.platform.rawValue | bitMask.gameOverLine.rawValue
// player.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
addChild(player)
gameOverLine.position = CGPoint(x: player.position.x, y: player.position.y - 240)
gameOverLine.zPosition = -1
gameOverLine.physicsBody = SKPhysicsBody(rectangleOf: gameOverLine.size)
gameOverLine.physicsBody?.affectedByGravity = false
gameOverLine.physicsBody?.allowsRotation = false
gameOverLine.physicsBody?.categoryBitMask = bitMask.gameOverLine.rawValue
gameOverLine.physicsBody?.contactTestBitMask = bitMask.platform.rawValue | bitMask.player.rawValue
addChild(gameOverLine)
scoreLabel.position.x = 125
scoreLabel.zPosition = 20
scoreLabel.fontColor = .black
scoreLabel.fontSize = 32
scoreLabel.fontName = "Helvectica"
scoreLabel.text = "Score: \(score)"
addChild(scoreLabel)
bestScore = defaults.integer(forKey: "best")
bestScoreLabel.position.x = 625
bestScoreLabel.zPosition = 20
bestScoreLabel.fontColor = .black
bestScoreLabel.fontSize = 32
bestScoreLabel.fontName = "Helvectica"
bestScoreLabel.text = "Bestscore: \(bestScore)"
addChild(bestScoreLabel)
makePlatform()
makePlatform2()
makePlatform3()
makePlatform4()
makePlatform5()
makePlatform6()
// if motionManager.isAccelerometerActive == true {
// motionManager.accelerometerUpdateInterval = 20/60
//
// motionManager.startAccelerometerUpdates(to: OperationQueue()) { data, error in
//
// self.multi = Float(data!.acceleration.x) * 10
// self.player.position = CGPoint(x: self.player.position.x + CGFloat(self.multi), y: self.player.position.y)
// }
// }
if motionManager.isAccelerometerAvailable {
motionManager.accelerometerUpdateInterval = 0.10
motionManager.startAccelerometerUpdates(to: .main) {
(data, error) in
guard let data = data, error == nil else {
return
}
let currentX = self.player.position.x
self.multi = currentX + CGFloat(data.acceleration.x * 1300)
}
}
let frame = SKPhysicsBody(edgeLoopFrom: self.frame)
frame.friction = 0
frame.restitution = 1
frame.categoryBitMask = bitMask.frame.rawValue
frame.contactTestBitMask = bitMask.player.rawValue
frame.collisionBitMask = bitMask.player.rawValue
self.physicsBody = frame
cam.setScale(3)
cam.position.x = player.position.x
camera = cam
}
override func update(_ currentTime: TimeInterval) {
cam.position.y = player.position.y + 350
background.position.y = player.position.y
if player.physicsBody!.velocity.dy > 0 {
gameOverLine.position.y = player.position.y - 600
}
scoreLabel.position.y = player.position.y + 1050
bestScoreLabel.position.y = player.position.y + 1050
let action = SKAction.moveTo(x: multi, duration: 1)
player.run(action)
}
func didBegin(_ contact: SKPhysicsContact) {
let contactA: SKPhysicsBody
let contactB: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
contactA = contact.bodyA //Player
contactB = contact.bodyB //Platform
} else {
contactA = contact.bodyB //Player
contactB = contact.bodyA //Platform
}
if contactA.categoryBitMask == bitMask.platform.rawValue && contactB.categoryBitMask == bitMask.gameOverLine.rawValue {
contactA.node?.removeFromParent()
}
if contactA.categoryBitMask == bitMask.player.rawValue && contactB.categoryBitMask == bitMask.platform.rawValue {
if player.physicsBody!.velocity.dy < 0 {
player.physicsBody?.velocity = CGVector(dx: player.physicsBody!.velocity.dx, dy: 1400)
contactB.node?.removeFromParent()
makePlatform5()
makePlatform6()
addScore()
}
}
if contactA.categoryBitMask == bitMask.player.rawValue && contactB.categoryBitMask == bitMask.gameOverLine.rawValue {
gameOver()
}
}
// override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
// for touch in touches {
// let location = touch.location(in: self)
//
// player.position.x = location.x
// }
// }
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
player.physicsBody?.isDynamic = true
if firstTouch == false {
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 1800))
}
firstTouch = true
}
func makePlatform() {
let platform = SKSpriteNode(imageNamed: "ground")
platform.position = CGPoint(x: GKRandomDistribution(lowestValue: 70, highestValue: 700).nextInt(), y: GKRandomDistribution(lowestValue: 140, highestValue: 300).nextInt() + Int(player.position.y))
platform.zPosition = 5
platform.setScale(0.30)
platform.physicsBody = SKPhysicsBody(rectangleOf: platform.size)
platform.physicsBody?.isDynamic = false
platform.physicsBody?.allowsRotation = false
platform.physicsBody?.affectedByGravity = false
platform.physicsBody?.categoryBitMask = bitMask.platform.rawValue
platform.physicsBody?.collisionBitMask = 0
platform.physicsBody?.contactTestBitMask = bitMask.player.rawValue
addChild(platform)
}
func makePlatform2() {
let platform = SKSpriteNode(imageNamed: "ground")
platform.position = CGPoint(x: GKRandomDistribution(lowestValue: 70, highestValue: 700).nextInt(), y: GKRandomDistribution(lowestValue: 350, highestValue: 550).nextInt() + Int(player.position.y))
platform.zPosition = 5
platform.setScale(0.30)
platform.physicsBody = SKPhysicsBody(rectangleOf: platform.size)
platform.physicsBody?.isDynamic = false
platform.physicsBody?.allowsRotation = false
platform.physicsBody?.affectedByGravity = false
platform.physicsBody?.categoryBitMask = bitMask.platform.rawValue
platform.physicsBody?.collisionBitMask = 0
platform.physicsBody?.contactTestBitMask = bitMask.player.rawValue
addChild(platform)
}
func makePlatform3() {
let platform = SKSpriteNode(imageNamed: "ground")
platform.position = CGPoint(x: GKRandomDistribution(lowestValue: 70, highestValue: 700).nextInt(), y: GKRandomDistribution(lowestValue: 600, highestValue: 800).nextInt() + Int(player.position.y))
platform.zPosition = 5
platform.setScale(0.30)
platform.physicsBody = SKPhysicsBody(rectangleOf: platform.size)
platform.physicsBody?.isDynamic = false
platform.physicsBody?.allowsRotation = false
platform.physicsBody?.affectedByGravity = false
platform.physicsBody?.categoryBitMask = bitMask.platform.rawValue
platform.physicsBody?.collisionBitMask = 0
platform.physicsBody?.contactTestBitMask = bitMask.player.rawValue
addChild(platform)
}
func makePlatform4() {
let platform = SKSpriteNode(imageNamed: "ground")
platform.position = CGPoint(x: GKRandomDistribution(lowestValue: 70, highestValue: 700).nextInt(), y: GKRandomDistribution(lowestValue: 850, highestValue: 1050).nextInt() + Int(player.position.y))
platform.zPosition = 5
platform.setScale(0.30)
platform.physicsBody = SKPhysicsBody(rectangleOf: platform.size)
platform.physicsBody?.isDynamic = false
platform.physicsBody?.allowsRotation = false
platform.physicsBody?.affectedByGravity = false
platform.physicsBody?.categoryBitMask = bitMask.platform.rawValue
platform.physicsBody?.collisionBitMask = 0
platform.physicsBody?.contactTestBitMask = bitMask.player.rawValue
addChild(platform)
}
func makePlatform5() {
let platform = SKSpriteNode(imageNamed: "ground")
platform.position = CGPoint(x: GKRandomDistribution(lowestValue: 70, highestValue: 700).nextInt(), y: GKRandomDistribution(lowestValue: 1100, highestValue: 1300).nextInt() + Int(player.position.y))
platform.zPosition = 5
platform.setScale(0.30)
platform.physicsBody = SKPhysicsBody(rectangleOf: platform.size)
platform.physicsBody?.isDynamic = false
platform.physicsBody?.allowsRotation = false
platform.physicsBody?.affectedByGravity = false
platform.physicsBody?.categoryBitMask = bitMask.platform.rawValue
platform.physicsBody?.collisionBitMask = 0
platform.physicsBody?.contactTestBitMask = bitMask.player.rawValue
addChild(platform)
}
func makePlatform6() {
let platform = SKSpriteNode(imageNamed: "ground")
platform.position = CGPoint(x: GKRandomDistribution(lowestValue: 70, highestValue: 700).nextInt(), y: GKRandomDistribution(lowestValue: 1350, highestValue: 1550).nextInt() + Int(player.position.y))
platform.zPosition = 5
platform.setScale(0.30)
platform.physicsBody = SKPhysicsBody(rectangleOf: platform.size)
platform.physicsBody?.isDynamic = false
platform.physicsBody?.allowsRotation = false
platform.physicsBody?.affectedByGravity = false
platform.physicsBody?.categoryBitMask = bitMask.platform.rawValue
platform.physicsBody?.collisionBitMask = 0
platform.physicsBody?.contactTestBitMask = bitMask.player.rawValue
addChild(platform)
}
func gameOver() {
let gameOverScene = GameOverScene(size: self.size)
let transition = SKTransition.crossFade(withDuration: 0.5)
view?.presentScene(gameOverScene, transition: transition)
if score > bestScore {
bestScore = score
defaults.set(bestScore, forKey: "best")
}
}
func addScore() {
score += 1
scoreLabel.text = "Score: \(score)"
}
}

Related

Moving SKSpriteNode with touch, speeds up at half screen point

I'm working on a 2-d Platformer style game. I'm very new to IOS and Swift development. I'm attempting to use a button (a different node) to move my character across the screen from left to right. It works fine until I reach the halfway point then it speeds up dramatically and letting go of the touch of the button doesn't always stop it. Sometimes it requires another touch. Also the background doesn't appear to keep up with the player. Once the player hits mid screen the background should shift as the player continues moving.
I've pieced what I've done together from multiple tutorials SO examples but I'm stuck on this point.
class StoryModeScene: SKScene, SKPhysicsContactDelegate {
var tileMap = JSTileMap(named: "legend1Level1.tmx")
var tileSize:CGSize!
var xPointsToMovePerSecond:CGFloat = 0
var rightMoveButton = SKSpriteNode(imageNamed: "right-move")
var leftMoveButton = SKSpriteNode(imageNamed: "left-move")
var jumpButton = SKSpriteNode(imageNamed: "a-button")
var fireButton = SKSpriteNode(imageNamed: "b-button")
var forwardMarch:Bool = false
var mightAsWellJump:Bool = false
var onGround:Bool = true
//CREATE THE PLAYER ATLAS FOR ANIMATION
let playerAtlas = SKTextureAtlas(named:"legend1")
var playerSprites = Array<Any>()
var player = SKSpriteNode(imageNamed: "legend1")
var repeatActionPlayer = SKAction()
override func didMove(to view: SKView) {
/* Setup your scene here */
setupScene()
addPlayer()
//PREPARE TO ANIMATE THE PLAYER AND REPEAT THE ANIMATION FOREVER
let animatedPlayer = SKAction.animate(with: self.playerSprites as! [SKTexture], timePerFrame: 0.1)
self.repeatActionPlayer = SKAction.repeatForever(animatedPlayer)
leftMoveButton.position.x = 64
leftMoveButton.position.y = 64
leftMoveButton.name = "moveLeft"
addChild(leftMoveButton)
rightMoveButton.position.x = 124
rightMoveButton.position.y = 64
rightMoveButton.name = "moveRight"
addChild(rightMoveButton)
jumpButton.position.x = 771
jumpButton.position.y = 64
jumpButton.name = "jumpButton"
addChild(jumpButton)
fireButton.position.x = 836
fireButton.position.y = 64
fireButton.name = "fireButton"
addChild(fireButton)
}
override func update(_ currentTime: TimeInterval) {
if (forwardMarch) {
//let moveAction = SKAction.moveBy(x: 3, y: 0, duration: 1)
//let repeatForEver = SKAction.repeatForever(moveAction)
//let seq = SKAction.sequence([moveAction, repeatForEver])
//run the action on your ship
//player.run(seq)
player.position.x = player.position.x + 3
setViewpointCenter(player.position)
}
if (mightAsWellJump) {
let jumpForce = CGPoint(x: 0.0, y: 310.0)
let jumpCutoff: Float = 150.0
if mightAsWellJump && onGround {
player.physicsBody!.velocity = CGVector(dx: player.physicsBody!.velocity.dx + jumpForce.x, dy: player.physicsBody!.velocity.dy + jumpForce.y)
onGround = false
} else if !mightAsWellJump && player.physicsBody!.velocity.dy > CGFloat(jumpCutoff) {
player.physicsBody!.velocity = CGVector(dx: player.physicsBody!.velocity.dx, dy: CGFloat(jumpCutoff))
}
player.position = CGPoint(x: player.position.x, y: player.position.y + 5);
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches) {
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name {
if name == "jumpButton" {
mightAsWellJump = true
player.texture = SKTexture(imageNamed: "legend1_jump")
}
if name == "moveRight" {
forwardMarch = true
self.player.run(repeatActionPlayer)
}
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
if rightMoveButton.contains(touch.location(in: self)) {
forwardMarch = false
player.removeAllActions()
player.texture = SKTexture(imageNamed: "legend1")
}
if jumpButton.contains(touch.location(in: self)) {
mightAsWellJump = false
player.removeAllActions()
player.texture = SKTexture(imageNamed: "legend1")
}
}
func setViewpointCenter(_ position: CGPoint) {
var x = max(position.x, size.width / 2)
var y = max(position.y, size.height / 2)
x = min(x, (tileMap!.mapSize.width * tileMap!.tileSize.width) - size.width / 2)
y = min(y, (tileMap!.mapSize.height * tileMap!.tileSize.height) - size.height / 2)
let actualPosition = CGPoint(x: CGFloat(x), y: CGFloat(y))
let centerOfView = CGPoint(x: size.width / 2, y: size.height / 2)
let viewPoint = CGPoint(x: (centerOfView.x - actualPosition.x) * 3, y: centerOfView.y - actualPosition.y)
tileMap!.position = viewPoint
}
func setupScene() {
playerSprites.append(playerAtlas.textureNamed("legend1_0"))
playerSprites.append(playerAtlas.textureNamed("legend1_1"))
playerSprites.append(playerAtlas.textureNamed("legend1_2"))
playerSprites.append(playerAtlas.textureNamed("legend1_3"))
playerSprites.append(playerAtlas.textureNamed("legend1_4"))
playerSprites.append(playerAtlas.textureNamed("legend1_5"))
backgroundColor = UIColor(red: 165.0/255.0, green: 216.0/255.0, blue: 255.0/255.0, alpha: 1.0)
physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
anchorPoint = CGPoint(x: 0, y: 0)
position = CGPoint(x: 0, y: 0)
let point = tileMap!.calculateAccumulatedFrame()
print (point)
tileMap!.position = CGPoint(x: 0, y: 0)
addChild(tileMap!)
addFloor()
}
func addFloor() {
for a in 0..<Int(tileMap!.mapSize.width) {
for b in 0..<Int(tileMap!.mapSize.height) {
let layerInfo:TMXLayerInfo = tileMap!.layers.firstObject as! TMXLayerInfo
let point = CGPoint(x: a, y: b)
let walls = tileMap!.layerNamed("Walls")
let wallInfo:TMXLayerInfo = walls!.layerInfo
let wallGIDs = wallInfo.layer.tileGid(at: wallInfo.layer.point(forCoord: point))
if wallGIDs > 0 {
//print (wallGIDs)
//let node = walls
let node = wallInfo.layer.tile(atCoord: point)
node!.physicsBody = SKPhysicsBody(rectangleOf: node!.size)
node!.physicsBody?.isDynamic = false
}
}
}
}
func addPlayer() {
tileSize = tileMap?.tileSize
player.position = CGPoint(x: tileSize.width + player.size.width/2, y: tileSize.height + player.size.height*8)
let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 50, height: 95))
player.physicsBody = SKPhysicsBody(rectangleOf: rect.size)
player.physicsBody!.velocity = CGVector(dx: 0.0, dy: 0.0)
player.physicsBody!.isDynamic = true
player.physicsBody!.restitution = 0
player.physicsBody!.allowsRotation = false
player.physicsBody!.friction = 1.0
addChild(player)
}
}
Holding the rightMoveButton should move at a consistent pace to the right. As the player gets to mid screen the view point of the background should shift until it reaches the end of the background at which point the player can move off screen and complete the level. Releasing the button should allow the player to stop.
You can move the scene as the character moves by creating an SKCameraNode. You then can choose when to move the camera to create the right affect. Make sure to set the camera as your game’s camera. You can learn about cameras here. As for the speeding up, I assume it has something to do with your physicsBody. If you’re interested about player movement, you could look here or here. There are many other great videos and sites online, which you could find by searching “SpriteKit player movement.”
Eli Front's answer pointed me in the right direction. I still have some issues with this code but the answer to my question was using SKCamera node as Eli pointed out. I just wanted to post the code that works so if anyone has a similar question there's a code example as far as camera moving with the player. The speed issue was essentially an optical illusion with the background moving too fast.
Note that the controls are children of the camera. That is so they move with the camera as well otherwise as your node moves the controls would move off screen.
import UIKit
import SpriteKit
import GameKit
class StoryModeScene: SKScene, SKPhysicsContactDelegate {
var tileMap = JSTileMap(named: "legend1Level1.tmx")
var tileSize:CGSize!
var xPointsToMovePerSecond:CGFloat = 0
var rightMoveButton = SKSpriteNode(imageNamed: "right-move")
var leftMoveButton = SKSpriteNode(imageNamed: "left-move")
var jumpButton = SKSpriteNode(imageNamed: "a-button")
var fireButton = SKSpriteNode(imageNamed: "b-button")
var forwardMarch:Bool = false
var mightAsWellJump:Bool = false
var onGround:Bool = true
//CREATE THE Player ATLAS FOR ANIMATION
let playerAtlas = SKTextureAtlas(named:"legend1")
var playerSprites = Array<Any>()
var player = SKSpriteNode(imageNamed: "legend1")
var repeatActionPlayer = SKAction()
let cam = SKCameraNode()
var previousUpdateTime: TimeInterval = 0
override func didMove(to view: SKView) {
// SETUP CAMERA
self.camera = cam
scene?.addChild(cam)
cam.position.x = 448
cam.position.y = 212
setupScene()
addPlayer()
//PREPARE TO ANIMATE THE PLAYER AND REPEAT THE ANIMATION FOREVER
let animatedPlayer = SKAction.animate(with: self.playerSprites as! [SKTexture], timePerFrame: 0.1)
self.repeatActionPlayer = SKAction.repeatForever(animatedPlayer)
// SETUP CONTROLS
leftMoveButton.position.x = -338
leftMoveButton.position.y = -112
leftMoveButton.name = "moveLeft"
leftMoveButton.zPosition = 5
cam.addChild(leftMoveButton)
rightMoveButton.position.x = -278
rightMoveButton.position.y = -112
rightMoveButton.name = "moveRight"
cam.addChild(rightMoveButton)
jumpButton.position.x = 278
jumpButton.position.y = -112
jumpButton.name = "jumpButton"
jumpButton.zPosition = 5
cam.addChild(jumpButton)
fireButton.position.x = 338
fireButton.position.y = -112
fireButton.name = "fireButton"
cam.addChild(fireButton)
}
override func update(_ currentTime: TimeInterval) {
if (forwardMarch) {
if player.position.x > 448 && player.position.x < 1800 {
cam.position.x = player.position.x
} else if player.position.x >= 1800 {
cam.position.x = 1800
}
setViewpointCenter(player.position)
player.position.x = player.position.x + 3
}
if (mightAsWellJump) {
let jumpForce = CGPoint(x: 0.0, y: 310.0)
let jumpCutoff: Float = 150.0
if mightAsWellJump && onGround {
player.physicsBody!.velocity = CGVector(dx: player.physicsBody!.velocity.dx + jumpForce.x, dy: player.physicsBody!.velocity.dy + jumpForce.y)
onGround = false
} else if !mightAsWellJump && player.physicsBody!.velocity.dy > CGFloat(jumpCutoff) {
player.physicsBody!.velocity = CGVector(dx: player.physicsBody!.velocity.dx, dy: CGFloat(jumpCutoff))
}
player.position = CGPoint(x: player.position.x, y: player.position.y + 5);
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches) {
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name {
if name == "jumpButton" {
mightAsWellJump = true
player.texture = SKTexture(imageNamed: "legend1_jump")
}
if name == "moveRight" {
player.physicsBody!.velocity.dy = 0.0
forwardMarch = true
self.player.run(repeatActionPlayer)
}
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in (touches) {
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name {
if name == "jumpButton" {
mightAsWellJump = false
player.removeAllActions()
player.texture = SKTexture(imageNamed: "legend1")
player.physicsBody!.velocity = CGVector(dx: 0.0, dy: 0.0)
}
if name == "moveRight" {
player.removeAllActions()
player.texture = SKTexture(imageNamed: "legend1")
forwardMarch = false
}
}
}
}
func setViewpointCenter(_ position: CGPoint) {
var x = max(position.x, size.width / 2)
var y = max(position.y, size.height / 2)
x = min(x, (tileMap!.mapSize.width * tileMap!.tileSize.width) - size.width / 2)
y = min(y, (tileMap!.mapSize.height * tileMap!.tileSize.height) - size.height / 2)
let actualPosition = CGPoint(x: CGFloat(x), y: CGFloat(y))
let centerOfView = CGPoint(x: size.width / 2, y: size.height / 2)
let viewPoint = CGPoint(x: centerOfView.x - actualPosition.x, y: centerOfView.y - actualPosition.y)
if (actualPosition.x > 1800) {
tileMap!.position = tileMap!.position
} else {
tileMap!.position = viewPoint
}
}
func setupScene() {
// ADD PLAYER SPRITES #TODO MAKE THIS DYNAMIC
playerSprites.append(playerAtlas.textureNamed("legend1_0"))
playerSprites.append(playerAtlas.textureNamed("legend1_1"))
playerSprites.append(playerAtlas.textureNamed("legend1_2"))
playerSprites.append(playerAtlas.textureNamed("legend1_3"))
playerSprites.append(playerAtlas.textureNamed("legend1_4"))
playerSprites.append(playerAtlas.textureNamed("legend1_5"))
backgroundColor = UIColor(red: 165.0/255.0, green: 216.0/255.0, blue: 255.0/255.0, alpha: 1.0)
anchorPoint = CGPoint(x: 0, y: 0)
position = CGPoint(x: 0, y: 0)
// let point = tileMap!.calculateAccumulatedFrame()
tileMap!.position = CGPoint(x: 0, y: 0)
addChild(tileMap!)
addFloor()
}
func addFloor() {
for a in 0..<Int(tileMap!.mapSize.width) {
for b in 0..<Int(tileMap!.mapSize.height) {
// let layerInfo:TMXLayerInfo = tileMap!.layers.firstObject as! TMXLayerInfo
let point = CGPoint(x: a, y: b)
let walls = tileMap!.layerNamed("Walls")
let wallInfo:TMXLayerInfo = walls!.layerInfo
let wallGIDs = wallInfo.layer.tileGid(at: wallInfo.layer.point(forCoord: point))
if wallGIDs > 0 {
let node = wallInfo.layer.tile(atCoord: point)
node!.physicsBody = SKPhysicsBody(rectangleOf: node!.size)
node!.physicsBody?.isDynamic = false
}
}
}
}
func addPlayer() {
tileSize = tileMap?.tileSize
player.position = CGPoint(x: tileSize.width + player.size.width/2, y: tileSize.height + player.size.height*8)
let rect = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 50, height: 95))
player.physicsBody = SKPhysicsBody(rectangleOf: rect.size)
player.physicsBody!.velocity = CGVector(dx: 0.0, dy: 0.0)
player.physicsBody!.isDynamic = true
player.physicsBody!.restitution = 0
player.physicsBody!.allowsRotation = false
player.physicsBody!.friction = 1.0
player.physicsBody!.mass = 1.0
addChild(player)
}
}
As I mentioned I still have some issues like the player node floating/flying when I jump/run at the same time. The 1st jump is the correct height and all subsequent jumps are smaller etc but I'm working on figuring those out.

The enemy's healthbar decreases in its entirety with a single collision

he problem is that when the player collides with the enemy the health of the enemy in healthBar does not decrease the indicated amount. it simply decreases in its entirety
I can not find a way to update the enemy's healthbar in the func update and try the func didBegin (_ contact: SKPhysicsContact)
enter code here
func initZombie(){
let enemy = Enemigo(imageNamed: "zombie1")
var textures:[SKTexture] = []
for i in 1...2 {
textures.append(SKTexture(imageNamed: "zombie\(i)"))
}
let anima:SKAction = SKAction.animate(with: textures, timePerFrame: 15.0)
enemy.run(SKAction.group([
SKAction.repeatForever(anima),
SKAction.speed(to: 60.0, duration: 0)
]),withKey: "animation")
enemy.healt = 300
enemy.exp = 100
enemy.barraEnemy = SKSpriteNode(color: SKColor.green, size: enemy.barravidaSizeE)
enemy.barraEnemyBack = SKSpriteNode(color: SKColor.red, size: CGSize(width: enemy.barravidaSizeE.width + 300, height: enemy.barravidaSizeE.height + 30))
enemy.barraEnemy.position = CGPoint(x: enemy.position.x , y: enemy.position.y - 150)
enemy.barraEnemy.zPosition = 101
enemy.barraEnemy.anchorPoint = CGPoint(x: 0.0 , y: 0.5)
enemy.addChild(enemy.barraEnemy)
enemy.barraEnemyBack.position = CGPoint(x: enemy.position.x , y: enemy.position.y - 150)
enemy.barraEnemyBack.zPosition = 100
enemy.barraEnemyBack.anchorPoint = CGPoint(x: 0.0, y: 0.5)
enemy.addChild(enemy.barraEnemyBack)
enemy.barraEnemy.size = CGSize(width: enemy.barravidaSizeE.width + CGFloat(enemy.healt) , height: enemy.barravidaSizeE.height + 30)
enemy.zPosition = 100
//enemy.position = CGPoint(x: size.width/2, y: size.height/2)
enemy.position = CGPoint(x:random(min: -1100 , max: 1100), y: random(min: -400 , max: 400))
enemy.name = "zombie"
enemy.setScale(0.4)
addChild(enemy)
enemy.physicsBody = SKPhysicsBody.init(rectangleOf: enemy.size)
enemy.physicsBody?.allowsRotation = true
enemy.physicsBody?.affectedByGravity = false
enemy.physicsBody?.categoryBitMask = 3
enemy.physicsBody?.collisionBitMask = 1
enemy.physicsBody?.contactTestBitMask = 1
enemy.physicsBody?.isDynamic = true
}
enter
code
here
func didBegin(_ contact: SKPhysicsContact) {
var firstBody:SKPhysicsBody
var secondBody:SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
}else{
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if firstBody.categoryBitMask == 1 && secondBody.categoryBitMask == 2 {
life += 100
secondBody.node?.removeFromParent()
}
if firstBody.categoryBitMask == 1 && secondBody.categoryBitMask == 3 {
score += 1
if let myEnemy = secondBody.node as? Enemigo {
myEnemy.healt -= playerAtack
life -= zombieAtack
myEnemy.barraEnemy.size = CGSize(width: myEnemy.barravidaSizeE.width + CGFloat(myEnemy.healt), height: myEnemy.barravidaSizeE.height)
print(myEnemy.healt)
if myEnemy.healt <= 0 {
playerAtack += 10
life += 100
spawnItem(point: secondBody.node!.position)
secondBody.node?.removeFromParent()
}
}
}
}

How do I make an object bounce off the edges in swift

I am trying to make my 'Enemy' bounce off all the boundaries. For example, when the Enemy collides with the left, right, top and bottom of the screen, it should change direction.
This is my current code:
import SpriteKit
import GameplayKit
struct Physics {
static let Enemy: UInt32 = 0x1 << 1
let BorderCategory : UInt32 = 0x1 << 2
let BottomCategory : UInt32 = 0x1 << 3
let BallCategory : UInt32 = 0x1 << 4
}
class GameScene: SKScene {
var Enemy = SKSpriteNode()
var gameStarted = Bool()
var gameState = "running"
var destX : CGFloat = 0.0
var destY : CGFloat = 0.0
var score = 0
override func didMove(to view: SKView) {
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
let screenSize: CGRect = UIScreen.main().bounds // get the screen size
let screenWidth = screenSize.width //get the width
let screenHeight = screenSize.height //get the height
Enemy = SKSpriteNode(imageNamed: "red2")
Enemy.size = CGSize(width: 60, height: 70)
Enemy.position = (CGPoint(x: self.frame.width / 6 - Enemy.frame.width, y: self.frame.height / 10))
Enemy.physicsBody = SKPhysicsBody(circleOfRadius: Enemy.frame.height / 2)
Enemy.physicsBody?.categoryBitMask = Physics.Enemy
//Enemy.physicsBody?.categoryBitMask = Physics.Ground | Physics.wall
//Enemy.physicsBody?.contactTestBitMask = Physics.Ground | Physics.wall
Enemy.physicsBody?.affectedByGravity = false
Enemy.physicsBody?.isDynamic = true
self.addChild(Enemy)
Enemy.physicsBody?.velocity = CGVector(dx: 50, dy: 50)
if (Enemy.position.x == screenWidth) {
Enemy.physicsBody?.velocity = CGVector(dx: -50, dy: 0) // change direction at edge DOESN'T WORK
}
if(Enemy.position.y == screenHeight){
Enemy.physicsBody?.velocity = CGVector(dx: 0, dy: -50) //change direction at edge DOESN'T WORK
}
}
OK, based on your code I've written a working bouncing sprite. It uses the physics-engine to achieve this, rather than manually changing the direction (which I guess is how you should go about doing this).
override func didMove(to view: SKView) {
let borderBody = SKPhysicsBody(edgeLoopFrom: frame)
borderBody.friction = 0
borderBody.categoryBitMask = Physics.wall
physicsBody = borderBody
let enemy = enemySprite(size: CGSize(width: 60, height: 70), position: CGPoint(x: frame.size.width/2, y: frame.size.height/2))
addChild(enemy)
let force = SKAction.applyForce(CGVector(dx: 300, dy: 300) , duration: 0.1)
enemy.run(force)
}
func enemySprite(size: CGSize, position: CGPoint) -> SKSpriteNode {
let enemy = SKSpriteNode(color: SKColor.red(), size: CGSize(width: 60, height: 80))
enemy.position = CGPoint(x: frame.width/2, y: frame.height/2)
enemy.physicsBody = SKPhysicsBody(circleOfRadius: enemy.frame.height / 2) // A bit silly with circle, but you seem to have an image for this use
enemy.physicsBody?.categoryBitMask = Physics.enemy
enemy.physicsBody?.restitution = 1
enemy.physicsBody?.friction = 0
enemy.physicsBody?.collisionBitMask = Physics.wall
enemy.physicsBody?.affectedByGravity = false
enemy.physicsBody?.angularDamping = 0
enemy.physicsBody?.linearDamping = 0
return enemy
}
A question to consider is also how you set up the scene? Is the scene-size the same as the view-size? Otherwise the scene's physicsBody will not make the ball bounce where you expect it to...
It won't (in most cases) because of your conditions - using equal to operators instead of greater/lower than.
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
// Create enemy with physics body attached and add it to the scene
let enemy = SKSpriteNode(color: SKColor.greenColor(), size: CGSize(width: 20, height: 20))
enemy.name = "enemy"
enemy.position = CGPoint(x: size.width / 2, y: size.height / 2)
enemy.physicsBody = SKPhysicsBody(rectangleOfSize: enemy.size)
enemy.physicsBody!.affectedByGravity = false
enemy.physicsBody!.linearDamping = 0
enemy.physicsBody!.mass = 0.1
enemy.physicsBody!.velocity = CGVector(dx: 150, dy: 0)
addChild(enemy)
}
override func didSimulatePhysics() {
let enemy = childNodeWithName("enemy")!
if (enemy.position.x > size.width && enemy.physicsBody!.velocity.dx > 0)
|| (enemy.position.x < 0 && enemy.physicsBody!.velocity.dx < 0) {
enemy.physicsBody!.velocity.dx *= -1
}
}
}

flappy bird clone Xcode 7 Swift 2 how to reset rotation

I learn how to create games on iOS. And now I create a Flappy bird clone.
Flappy Bird Clone
And I'm stack on that - when bird touch some pipe it begin rotate. And game of course is over. But when I start a new game Bird still rotates.
If I put this line
bird.physicsBody?.allowsRotation = false
in the GameScene.swift then bird stop rotate at all. That is not what I want. I want to allow rotation. But when start a new game Bird should be in default position and do not rotate.
What should I do to make it work? Thanks for help.
//
// GameScene.swift
// Flappy Bird
//
// Created by Admin on 10.10.15.
// Copyright (c) 2015 Alex. All rights reserved.
//
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var score = 0
var gameOver = false
var gameOverLabel = SKLabelNode()
var scoreLabel = SKLabelNode ()
var bird = SKSpriteNode()
var bg = SKSpriteNode()
var movingObjects = SKSpriteNode()
var labelContainer = SKSpriteNode()
var pipe1 = SKSpriteNode()
var pipe2 = SKSpriteNode()
enum ColliderType: UInt32 {
case Bird = 1
case Object = 2
case Gap = 4
}
func makeBg () {
let bgTexture = SKTexture(imageNamed: "bg.png")
let movebg = SKAction.moveByX(-bgTexture.size().width, y: 0, duration: 10)
let replacebg = SKAction.moveByX(bgTexture.size().width, y: 0, duration: 0)
let movebgForever = SKAction.repeatActionForever(SKAction.sequence([movebg,replacebg]))
for var i: CGFloat = 0; i<2; i++ {
bg = SKSpriteNode(texture: bgTexture)
bg.position = CGPoint(x: bgTexture.size().width / 2 + bgTexture.size().width * i, y: CGRectGetMidY(self.frame))
bg.zPosition = -5
bg.size.height = self.frame.height
bg.runAction(movebgForever)
movingObjects.addChild(bg)
}
}
override func didMoveToView(view: SKView) {
self.physicsWorld.contactDelegate = self
self.addChild(movingObjects)
self.addChild(labelContainer)
makeBg()
scoreLabel.fontName = "Helvetica"
scoreLabel.fontSize = 60
scoreLabel.text = "0"
scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame), self.frame.size.height - 70)
addChild(scoreLabel)
let birdTexture = SKTexture(imageNamed: "flappy1.png")
let birdTexture2 = SKTexture(imageNamed: "flappy2.png")
let animation = SKAction.animateWithTextures([birdTexture,birdTexture2], timePerFrame: 0.1)
let makeBirdFlap = SKAction.repeatActionForever(animation)
bird = SKSpriteNode(texture: birdTexture)
bird.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
bird.runAction(makeBirdFlap)
bird.physicsBody = SKPhysicsBody(circleOfRadius: birdTexture.size().height/2)
bird.physicsBody!.dynamic = true
bird.physicsBody!.categoryBitMask = ColliderType.Bird.rawValue
bird.physicsBody?.contactTestBitMask = ColliderType.Object.rawValue
bird.physicsBody?.collisionBitMask = ColliderType.Object.rawValue
self.addChild(bird)
var ground = SKNode()
ground.position = CGPointMake(0, 0)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.size.width, 1))
ground.physicsBody!.dynamic = false
ground.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
ground.physicsBody?.contactTestBitMask = ColliderType.Object.rawValue
ground.physicsBody?.collisionBitMask = ColliderType.Object.rawValue
self.addChild(ground)
_ = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector("makePipes"), userInfo: nil, repeats: true)
}
func makePipes () {
let gapHeight = bird.size.height * 4
let movementAmount = arc4random() % UInt32(self.frame.size.height / 2)
let pipeOffset = CGFloat(movementAmount) - self.frame.size.height / 4
let movePipes = SKAction.moveByX(-self.frame.size.width * 2, y: 0, duration: NSTimeInterval (self.frame.size.width / 100))
let removePipes = SKAction.removeFromParent()
let moveAndRemovePipes = SKAction.sequence([movePipes,removePipes])
let pipeTexture1 = SKTexture(imageNamed: "pipe1.png")
let pipe1 = SKSpriteNode(texture: pipeTexture1)
pipe1.position = CGPoint(x: CGRectGetMidX(self.frame) + self.frame.size.width, y: CGRectGetMidY(self.frame) + pipeTexture1.size().height/2 + gapHeight/2 + pipeOffset)
pipe1.runAction(moveAndRemovePipes)
pipe1.physicsBody = SKPhysicsBody(rectangleOfSize: pipeTexture1.size())
pipe1.physicsBody?.dynamic = false
pipe1.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
pipe1.physicsBody?.contactTestBitMask = ColliderType.Object.rawValue
pipe1.physicsBody?.collisionBitMask = ColliderType.Object.rawValue
movingObjects.addChild(pipe1)
let pipeTexture2 = SKTexture(imageNamed: "pipe2.png")
let pipe2 = SKSpriteNode(texture: pipeTexture2)
pipe2.position = CGPoint(x: CGRectGetMidX(self.frame) + self.frame.size.width, y: CGRectGetMidY(self.frame) - pipeTexture2.size().height/2 - gapHeight/2 + pipeOffset)
pipe2.runAction(moveAndRemovePipes)
pipe2.physicsBody = SKPhysicsBody(rectangleOfSize: pipeTexture2.size())
pipe2.physicsBody!.dynamic = false
pipe2.physicsBody!.categoryBitMask = ColliderType.Object.rawValue
pipe2.physicsBody!.contactTestBitMask = ColliderType.Object.rawValue
pipe2.physicsBody!.collisionBitMask = ColliderType.Object.rawValue
movingObjects.addChild(pipe2)
var gap = SKNode()
gap.position = CGPoint(x: CGRectGetMidX(self.frame) + self.frame.size.width, y: CGRectGetMidY(self.frame) + pipeOffset)
gap.runAction(moveAndRemovePipes)
gap.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(pipe1.size.width, gapHeight))
gap.physicsBody?.dynamic = false
gap.physicsBody!.categoryBitMask = ColliderType.Gap.rawValue
gap.physicsBody!.contactTestBitMask = ColliderType.Bird.rawValue
gap.physicsBody!.collisionBitMask = ColliderType.Gap.rawValue
movingObjects.addChild(gap)
}
func didBeginContact(contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == ColliderType.Gap.rawValue || contact.bodyB.categoryBitMask == ColliderType.Gap.rawValue {
score++
scoreLabel.text = String(score)
} else {
if gameOver == false {
gameOver = true
self.speed = 0
gameOverLabel.fontName = "Helvetica"
gameOverLabel.fontSize = 30
gameOverLabel.text = "Game is over. Tap to play again."
gameOverLabel.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
labelContainer.addChild(gameOverLabel)
}
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if gameOver == false {
bird.physicsBody!.velocity = CGVectorMake(0, 0)
bird.physicsBody!.applyImpulse(CGVectorMake(0, 50))
} else {
score = 0
scoreLabel.text = "0"
bird.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
bird.physicsBody?.velocity = CGVectorMake(0, 0)
bird.physicsBody!.allowsRotation = false
movingObjects.removeAllChildren()
makeBg()
self.speed = 1
gameOver = false
labelContainer.removeAllChildren()
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
An easy solution is to reset the bird's angular speed and rotation angle. Modify the code in touchesBegan which is invoked when game is over:
bird.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
bird.physicsBody?.velocity = CGVectorMake(0, 0)
bird.physicsBody?.angularVelocity = 0
bird.zRotation = 0

app keeps crashing , Terminating app due to uncaught exception 'NSInvalidArgumentException'

I am creating a game where random objects fall in random places and there is a ball with a fixed y-axis and keeps moving along the x-axis , and it has to move throw the objects , and i am trying to count the scores and the way i do it is i created a physics object and it is places in the same y-axis as the ball , and when the objects collide the score function should be called and increment the score by 1, but for some reason the app keeps crashing and it gives me this error.
2015-07-13 01:23:17.242 WalkRun[26792:3773366] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Attemped to add a SKNode which already has a parent: <SKSpriteNode> name:'(null)' texture:[<SKTexture> 'shortwall' (60 x 60)] position:{30, 768} size:{60, 60} rotation:0.00'
*** First throw call stack:
(
0 CoreFoundation 0x00000001073c33f5 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001092eabb7 objc_exception_throw + 45
2 CoreFoundation 0x00000001073c332d +[NSException raise:format:] + 205
3 SpriteKit 0x0000000107ebfaf6 -[SKNode addChild:] + 111
4 WalkRun 0x00000001071c8c44 _TFC7WalkRun9PlayScene10leftObjectfS0_FT_T_ + 2868
5 WalkRun 0x00000001071c7ddc _TFC7WalkRun9PlayScene10randObjectfS0_FT_T_ + 236
6 WalkRun 0x00000001071c8102 _TToFC7WalkRun9PlayScene10randObjectfS0_FT_T_ + 34
7 Foundation 0x0000000107a39fd4 __NSFireTimer + 83
8 CoreFoundation 0x000000010732b4e4 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
9 CoreFoundation 0x000000010732b0a5 __CFRunLoopDoTimer + 1045
10 CoreFoundation 0x00000001072ee3dd __CFRunLoopRun + 1901
11 CoreFoundation 0x00000001072eda06 CFRunLoopRunSpecific + 470
12 GraphicsServices 0x000000010e7569f0 GSEventRunModal + 161
13 UIKit 0x0000000108046550 UIApplicationMain + 1282
14 WalkRun 0x00000001071d54ce top_level_code + 78
15 WalkRun 0x00000001071d550a main + 42
16 libdyld.dylib 0x0000000109ad9145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
and this is my code:
//
// PlayScene.swift
// WalkRun
//
// Created by naeim on 7/10/15.
// Copyright (c) 2015 naeim. All rights reserved.
//
import Foundation
import SpriteKit
class PlayScene: SKScene, SKPhysicsContactDelegate{
var ball = SKSpriteNode(imageNamed: "ball")
var wall = SKNode()
var wallRight = SKNode()
var wallMiddle = SKNode()
var ballSpeed = CGFloat()
var bigWall = SKSpriteNode(imageNamed: "shortwall")
var tallWall = SKSpriteNode(imageNamed: "tallwall")
var ballGroup:UInt32 = 1
var objectGroup:UInt32 = 2
var gapGroup:UInt32 = 3
var gameOver = 0
var movingObjects = SKNode()
var score = 0
var scoreLabel = SKLabelNode()
override func didMoveToView(view: SKView) {
self.physicsWorld.contactDelegate = self
backgroundColor = UIColor(hex: 0x80d9ff)
self.physicsWorld.gravity = CGVectorMake(-9,0)
self.addChild(movingObjects)
//creating the ball
ball.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame) + self.ball.size.height * 2)
ball.physicsBody = SKPhysicsBody(circleOfRadius: self.ball.size.width / 2)
ball.zPosition = 10
//let the ball rotate forever
ballSpeed = 3
let rotateAction = SKAction.rotateByAngle(ballSpeed, duration: 1)
let repeatAction = SKAction.repeatActionForever(rotateAction)
ball.runAction(repeatAction)
ball.physicsBody?.categoryBitMask = ballGroup
ball.physicsBody?.collisionBitMask = objectGroup
ball.physicsBody?.contactTestBitMask = objectGroup
self.addChild(ball)
//creating the wall of the left
wall.position = CGPointMake(CGRectGetMinX(self.frame),CGRectGetMinY(self.frame))
wall.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(2, self.frame.size.height * 2.0))
wall.physicsBody?.dynamic = false
wall.physicsBody?.categoryBitMask = objectGroup
self.addChild(wall)
//creating the wall of the right
wallRight.position = CGPointMake(CGRectGetMaxX(self.frame), CGRectGetMinY(self.frame))
wallRight.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(2, self.frame.size.height * 2.0))
wallRight.physicsBody?.dynamic = false
wallRight.physicsBody?.categoryBitMask = objectGroup
self.addChild(wallRight)
//creating the middle wall that objects pass by
wallMiddle.position = CGPointMake(CGRectGetMinX(self.frame), CGRectGetMinY(self.frame))
wallMiddle.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, 1))
wallMiddle.physicsBody?.dynamic = false
wallMiddle.physicsBody?.categoryBitMask = gapGroup
wallMiddle.physicsBody?.collisionBitMask = gapGroup
wallMiddle.physicsBody?.contactTestBitMask = objectGroup
self.addChild(wallMiddle)
//creating the label
scoreLabel.fontName = "Helvetica"
scoreLabel.fontSize = 60
scoreLabel.text = "0"
scoreLabel.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) + 70 )
self.addChild(scoreLabel)
var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("randObject"), userInfo: nil, repeats: true)
var timerObjects = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("checkObjectPlace"), userInfo: nil, repeats: true)
}
func checkObjectPlace(){
}
//function to randomly choose which object
func randObject(){
if gameOver == 0{
var rand = arc4random_uniform(6)+1
switch(rand){
case 1:
leftObject()
case 2:
middleObject()
case 3:
rightObject()
case 4:
LeftAndMiddleObject()
case 5:
rightAndLeftObject()
case 6:
rightAndMiddleObject()
default:
println("error !! non a number other than 0, 1, 2 has been choosen .")
}
}
}
//function to create the left objects
func leftObject(){
var rand = arc4random_uniform(2) + 1
if rand == 1
{
bigWall.position = CGPointMake(CGRectGetMinX(self.frame) + bigWall.size.width / 2, CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
bigWall.runAction(moveAndRemoveObjects)
bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: bigWall.size)
bigWall.physicsBody?.dynamic = false
bigWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(bigWall)
}
else
{
tallWall.position = CGPointMake(CGRectGetMinX(self.frame) + tallWall.size.width / 2, CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
tallWall.runAction(moveAndRemoveObjects)
tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: tallWall.size)
tallWall.physicsBody?.dynamic = false
tallWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(tallWall)
}
}
//function to create the middle objects
func middleObject(){
var rand = arc4random_uniform(2) + 1
if rand == 1
{
var bigWall = SKSpriteNode(imageNamed: "shortwall")
bigWall.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
bigWall.runAction(moveAndRemoveObjects)
bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: bigWall.size)
bigWall.physicsBody?.dynamic = false
bigWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(bigWall)
}
else
{
var tallWall = SKSpriteNode(imageNamed: "tallwall")
tallWall.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
tallWall.runAction(moveAndRemoveObjects)
tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: tallWall.size)
tallWall.physicsBody?.dynamic = false
tallWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(tallWall)
}
}
//function to create the right objects
func rightObject(){
var rand = arc4random_uniform(2) + 1
if rand == 1
{
var bigWall = SKSpriteNode(imageNamed: "shortwall")
bigWall.position = CGPointMake(CGRectGetMaxX(self.frame) - bigWall.size.width / 2, CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
bigWall.runAction(moveAndRemoveObjects)
bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: bigWall.size)
bigWall.physicsBody?.dynamic = false
bigWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(bigWall)
}
else
{
var tallWall = SKSpriteNode(imageNamed: "tallwall")
tallWall.position = CGPointMake(CGRectGetMaxX(self.frame) - tallWall.size.width / 2, CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
tallWall.runAction(moveAndRemoveObjects)
tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: tallWall.size)
tallWall.physicsBody?.dynamic = false
tallWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(tallWall)
if ball.position.x == tallWall.position.x{
scoreIncrement()
}
}
}
//function to create a right and left object
func rightAndLeftObject(){
var rand = arc4random_uniform(2) + 1
if rand == 1
{
var bigWall = SKSpriteNode(imageNamed: "shortwall")
var tallWall = SKSpriteNode(imageNamed: "tallwall")
tallWall.position = CGPointMake(CGRectGetMinX(self.frame) + tallWall.size.width / 2, CGRectGetMaxY(self.frame))
bigWall.position = CGPointMake(CGRectGetMaxX(self.frame) - bigWall.size.width / 2, CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
bigWall.runAction(moveAndRemoveObjects)
tallWall.runAction(moveAndRemoveObjects)
tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: tallWall.size)
tallWall.physicsBody?.dynamic = false
bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: bigWall.size)
bigWall.physicsBody?.dynamic = false
bigWall.physicsBody?.categoryBitMask = objectGroup
tallWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(tallWall)
movingObjects.addChild(bigWall)
bigWall.position = CGPointMake(CGRectGetMaxX(self.frame) - bigWall.size.width / 2, CGRectGetMaxY(self.frame))
}
else
{
var bigWall = SKSpriteNode(imageNamed: "shortwall")
var tallWall = SKSpriteNode(imageNamed: "tallwall")
bigWall.position = CGPointMake(CGRectGetMaxX(self.frame) - bigWall.size.width / 2, CGRectGetMaxY(self.frame))
tallWall.position = CGPointMake(CGRectGetMaxX(self.frame) - tallWall.size.width / 2, CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: tallWall.size)
tallWall.physicsBody?.dynamic = false
bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: bigWall.size)
bigWall.physicsBody?.dynamic = false
tallWall.runAction(moveAndRemoveObjects)
bigWall.runAction(moveAndRemoveObjects)
bigWall.physicsBody?.categoryBitMask = objectGroup
tallWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(tallWall)
movingObjects.addChild(bigWall)
}
}
func rightAndMiddleObject(){
var rand = arc4random_uniform(2) + 1
if rand == 1
{
var bigWall = SKSpriteNode(imageNamed: "shortwall")
var tallWall = SKSpriteNode(imageNamed: "tallwall")
tallWall.position = CGPointMake(CGRectGetMaxX(self.frame) - tallWall.size.width / 2, CGRectGetMaxY(self.frame))
bigWall.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
tallWall.runAction(moveAndRemoveObjects)
bigWall.runAction(moveAndRemoveObjects)
tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: tallWall.size)
tallWall.physicsBody?.dynamic = false
bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: bigWall.size)
bigWall.physicsBody?.dynamic = false
bigWall.physicsBody?.categoryBitMask = objectGroup
tallWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(tallWall)
movingObjects.addChild(bigWall)
}
else
{
var bigWall = SKSpriteNode(imageNamed: "shortwall")
var tallWall = SKSpriteNode(imageNamed: "tallwall")
bigWall.position = CGPointMake(CGRectGetMidX(self.frame) , CGRectGetMaxY(self.frame))
tallWall.position = CGPointMake(CGRectGetMaxX(self.frame) - tallWall.size.width / 2, CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
tallWall.runAction(moveAndRemoveObjects)
bigWall.runAction(moveAndRemoveObjects)
tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: tallWall.size)
tallWall.physicsBody?.dynamic = false
bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: bigWall.size)
bigWall.physicsBody?.dynamic = false
bigWall.physicsBody?.categoryBitMask = objectGroup
tallWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(tallWall)
movingObjects.addChild(bigWall)
}
}
func LeftAndMiddleObject(){
var rand = arc4random_uniform(2) + 1
if rand == 1
{
var bigWall = SKSpriteNode(imageNamed: "shortwall")
var tallWall = SKSpriteNode(imageNamed: "tallwall")
tallWall.position = CGPointMake(CGRectGetMinX(self.frame) + tallWall.size.width / 2, CGRectGetMaxY(self.frame))
bigWall.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
tallWall.runAction(moveAndRemoveObjects)
bigWall.runAction(moveAndRemoveObjects)
tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: tallWall.size)
tallWall.physicsBody?.dynamic = false
bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: bigWall.size)
bigWall.physicsBody?.dynamic = false
bigWall.physicsBody?.categoryBitMask = objectGroup
tallWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(tallWall)
movingObjects.addChild(bigWall)
}
else
{
var bigWall = SKSpriteNode(imageNamed: "shortwall")
var tallWall = SKSpriteNode(imageNamed: "tallwall")
bigWall.position = CGPointMake(CGRectGetMidX(self.frame) , CGRectGetMaxY(self.frame))
tallWall.position = CGPointMake(CGRectGetMinX(self.frame) + tallWall.size.width / 2, CGRectGetMaxY(self.frame))
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
tallWall.runAction(moveAndRemoveObjects)
bigWall.runAction(moveAndRemoveObjects)
tallWall.physicsBody = SKPhysicsBody(rectangleOfSize: tallWall.size)
tallWall.physicsBody?.dynamic = false
bigWall.physicsBody = SKPhysicsBody(rectangleOfSize: bigWall.size)
bigWall.physicsBody?.dynamic = false
bigWall.physicsBody?.categoryBitMask = objectGroup
tallWall.physicsBody?.categoryBitMask = objectGroup
movingObjects.addChild(tallWall)
movingObjects.addChild(bigWall)
}
}
func scoreIncrement(){
score = score + 1
scoreLabel.text = "\(score)"
}
func didBeginContact(contact: SKPhysicsContact) {
println("contact")
if contact.bodyA.categoryBitMask == gapGroup || contact.bodyB.categoryBitMask == gapGroup {
println("gap contact")
} else {
gameOver = 1
movingObjects.speed = 0
}
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
if gameOver == 0 {
ball.physicsBody?.velocity = CGVectorMake(0, 0)
ball.physicsBody?.applyImpulse(CGVectorMake(70,0))
}
}
override func update(currentTime: NSTimeInterval) {
}
}
The error suggests you are trying to add a child to a node while it already has a parent. The stack trace points you to leftObject method. In here you have an SKAction setup to move over a time interval and then remove from parent.
var moveObjects = SKAction.moveByX(0, y: -self.frame.size.height * 2, duration: NSTimeInterval(self.frame.size.height / 100))
var removeObjects = SKAction.removeFromParent()
var moveAndRemoveObjects = SKAction.sequence([moveObjects,removeObjects])
bigWall.runAction(moveAndRemoveObjects)
This adds the action to the node and it runs but your code path will continue down to
movingObjects.addChild(bigWall)
almost instantly. Looks like a race condition where you think the code will wait until the action has finished running before continuing on.
You have a instance property called bigWall and in most of your methods you create a local object called bigWall and add it to the scene. Since it is a new object each time the methods are call that works fine. However in the method leftObject you do not have a local object bigWall so it is referencing the instance property. The first time you call leftObject it will work fine adding your instance property bigWall to the scene. The second time you call the method it will try to add the bigWall instance property to the scene when it is already in the scene and that is where you will get the error.

Resources