Detect both falling and jumping in sprite kit game - ios

I am working on a sprite kit/swift game. I want the ball to do different things when it falls and jumps. Now if it falls it also uses the code at the bottom (the code for jumping)
Here is the code I am using:
override func collisionWithBall(ball: SKNode) -> Bool {
if ball.physicsBody?.velocity.dy < 0 {
ball.physicsBody?.velocity = CGVector(dx: ball.physicsBody!.velocity.dx, dy: 500.0)
if platformType == .Normal {
self.removeFromParent()
}
if platformType == .Break {
self.removeFromParent()
ball.physicsBody?.velocity = CGVector(dx: ball.physicsBody!.velocity.dx, dy: 800.0)
}
}
if ball.physicsBody?.velocity.dy > 0 {
if platformType == .Break {
NSUserDefaults.standardUserDefaults().setInteger(1, forKey: "nextValue")
self.removeFromParent()
ball.physicsBody?.velocity = CGVector(dx: ball.physicsBody!.velocity.dx, dy: -800.0)
}
}
return false
}
If it jumps I want it to only use this if ball.physicsBody?.velocity.dy > 0 And when it falls I want to only use this if ball.physicsBody?.velocity.dy < 0.
What can I do to make it working?

You'll have do change the if statements to use an else if for the second condition. Like this:
if ball.physicsBody?.velocity.dy < 0 {
// Handle falling here...
} else if if ball.physicsBody?.velocity.dy > 0 {
// Handle jumping here...
}

Related

SpriteKit keep moving player in current direction while falling after touchesEnded

I'm making my own Mario Bros. replica for the first level to learn how to make games with iOS, with my own assets. So far I've managed to place three SKSpriteNodes for the controls (left, right, up), and my player node can move in those three directions, but if I make my player jump while running in either direction, as soon as I remove my finger from the "left control", the player loses all its momentum and falls right there (as if it hit a wall) instead of following the parabola.
I don't know what might be needed in this case to be an MRE, so this is basically the whole thing that can reproduce the issue, along with some attempts I've made to make it work.
Basically I tried to apply an impulse / set the velocity / change the position directly and this last one was the one with better results (yet it still makes the player node to fall as soon as I remove the finger from the direction controls).
Here's a video demonstrating the issue.
This is the GameScene
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var player = SKSpriteNode()
private var bg = SKSpriteNode()
private var leftArrow = SKSpriteNode()
private var rightArrow = SKSpriteNode()
private var upArrow = SKSpriteNode()
private var floor = [SKSpriteNode]()
private var isLeftTouched = false
private var isRightTouched = false
private var selectedNodes: [UITouch:SKSpriteNode] = [:]
override func didMove(to view: SKView) {
addBackground()
addFloor()
addPlayer(xOffset: 0, yOffset: 0)
addControls()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
let touch = touches.first! as UITouch
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
for touch in touches {
let location = touch.location(in:self)
if let node = self.atPoint(location) as? SKSpriteNode {
if let name = touchedNode.name {
selectedNodes[touch] = node
if name == "up" {
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 60))
} else if name == "left" {
isLeftTouched = true
} else if name == "right" {
isRightTouched = true
}
}
}
}
if let name = touchedNode.name {
if name == "up" {
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 60))
} else if name == "left" {
isLeftTouched = true
} else if name == "right" {
isRightTouched = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
//let direction = ((touches.first?.location(in: self).x)! < (touches.first?.previousLocation(in: self).x)!) ? Direction.LEFT : Direction.RIGHT
//runIn(direction: direction)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
if selectedNodes[touch] != nil {
if selectedNodes[touch]?.name == "left" {
isLeftTouched = false
} else if selectedNodes[touch]?.name == "right" {
isRightTouched = false
}
selectedNodes[touch] = nil
}
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
if isLeftTouched {
runIn(direction: Direction.LEFT)
}
if isRightTouched {
runIn(direction: Direction.RIGHT)
}
}
// MARK: INTERACTION METHODS
func runIn(direction: Direction) {
let x = player.position.x + (direction == Direction.RIGHT ? 5 : -5)
let position = CGPoint(x: x, y: player.position.y)
if position.x >= self.frame.maxX || position.x <= self.frame.minX {
return
}
player.position = position
//player.physicsBody?.velocity = CGVector(dx: direction == Direction.RIGHT ? 50 : -50, dy: 0)
//player.physicsBody?.applyImpulse(CGVector(dx: direction == Direction.RIGHT ? 5 : -5 , dy: 0))
}
// MARK: UI METHODS
func addBackground() {
let bgTexture = SKTexture(imageNamed: "bg")
bg = SKSpriteNode(texture: bgTexture)
bg.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
bg.size.height = self.frame.height
bg.zPosition = -10
self.addChild(bg)
}
func addPlayer(xOffset: CGFloat, yOffset: CGFloat) {
let playerTexture = SKTexture(imageNamed: "player")
player = SKSpriteNode(texture: playerTexture)
//let xPos = calculateXOffset(for: player, from: self.frame.midX, offset: xOffset)
//let yPos = calculateXOffset(for: player, from: self.frame.midY, offset: yOffset)
player.position = CGPoint(x: self.frame.midX,
y: self.frame.midY)
player.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: player.frame.width, height: player.frame.height))
player.physicsBody?.isDynamic = true
self.addChild(player)
}
func addFloor() {
let blockTexture = SKTexture(imageNamed: "block")
for i in 0 ... (Int) (self.frame.width / blockTexture.size().width) {
let blockNode = SKSpriteNode(texture: blockTexture)
blockNode.position = CGPoint(x: self.frame.minX + (blockNode.frame.width * CGFloat(i)),
y: self.frame.minY + blockNode.frame.height / 2)
blockNode.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: blockNode.frame.width, height: blockNode.frame.height))
blockNode.physicsBody?.isDynamic = false
floor.append(blockNode)
self.addChild(blockNode)
}
}
func addControls() {
addLeftArrow()
addRightArrow()
addUpArrow()
}
func addLeftArrow() {
let leftTexture = SKTexture(imageNamed: "left")
leftArrow = SKSpriteNode(texture: leftTexture)
leftArrow.name = "left"
leftArrow.position = CGPoint(x: calculateXOffset(for: leftArrow, from: self.frame.minX, offset: 50),
y: calculateXOffset(for: leftArrow, from: self.frame.minY, offset: 50))
self.addChild(leftArrow)
}
func addRightArrow() {
let rightTexture = SKTexture(imageNamed: "right")
rightArrow = SKSpriteNode(texture: rightTexture)
rightArrow.name = "right"
rightArrow.position = CGPoint(x: calculateXOffset(for: rightArrow, from: self.frame.minX, offset: 150),
y: calculateXOffset(for: rightArrow, from: self.frame.minY, offset: 50))
self.addChild(rightArrow)
}
func addUpArrow() {
let upTexture = SKTexture(imageNamed: "up")
upArrow = SKSpriteNode(texture: upTexture)
upArrow.name = "up"
upArrow.position = CGPoint(x: calculateXOffset(for: upArrow, from: self.frame.maxX, offset: -(125 + upTexture.size().width)),
y: calculateXOffset(for: upArrow, from: self.frame.minY, offset: 50))
self.addChild(upArrow)
}
// MARK: UTILITY FUNCTIONS
func calculateXOffset(for asset: SKSpriteNode, from coord: CGFloat, offset: CGFloat) -> CGFloat {
let width = asset.frame.width
return coord + offset + width;
}
func calculateYOffset(for asset: SKSpriteNode, from coord: CGFloat, offset: CGFloat) -> CGFloat {
let height = asset.frame.height
return coord + offset + height;
}
}
My Direction enum:
enum Direction {
case LEFT
case RIGHT
case UP
case DOWN
}
And the only change I made in GameViewController was this:
scene.scaleMode = .resizeFill
My GameScene.sks is 926 x 428, only supporting landscape. I also set the LaunchScreen to Main due to a bug in Xcode 12: Background is not filling the whole view SpriteKit
And these are all my assets:
Edit
I tried applying an impulse in my runIn method like this:
player.physicsBody?.applyImpulse(CGVector(dx: direction == Direction.RIGHT ? 2 : -2 , dy: 0))
This makes the player node move in the parabola but now from time to time it gets stuck and the only way to make it move is to make it jump until it happens again.
Here's a video demonstrating the issue again.
If I try to set the velocity instead, then I'm not able to jump while moving and it seems to glide when jumping and moving after.
I ended up following #JohnL suggestion in the comments above, to use an impulse as well to move my player node:
player.physicsBody?.applyImpulse(CGVector(dx: direction == Direction.RIGHT ? 2 : -2 , dy: 0))
The issue where the player node was stuck while moving was removed when changing the floor for a single asset rather than multiple blocks one next to each other.

Why are there multiple SKSpriteNode and SKAudioNode objects when I only created one of each?

I created an SKSpriteNode object, but multiple objects are created, appearing as strings of them. The sound coming from the SKAudioNode object is also duplicated many times to give a reverberating effect.
Here is the code below. I noticed it doing this when I added the code to set the pinned properties of the physicsBody objects to true in the didBegin callback method.
Here is a screenshot. Notice there are multiple explosion SKSpriteNode objects. I only created one SKSpriteNode object for the explosion.
I suspect there is a setting somewhere that I can change to disable this effect.
import UIKit
import SpriteKit
class GameScene: SKScene {
let player = SKSpriteNode(imageNamed: "player")
var moveRate: CGFloat!
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
if UIDevice.current.userInterfaceIdiom == .phone {
moveRate = 5
} else {
moveRate = 15
}
player.physicsBody = SKPhysicsBody(rectangleOf: player.size)
player.physicsBody?.isDynamic = true
player.physicsBody?.affectedByGravity = false
player.physicsBody?.categoryBitMask = 0b00001
// player.physicsBody?.collisionBitMask = 0b00001
player.physicsBody?.contactTestBitMask = 0b00001
player.position = CGPoint(x: 20 + player.size.width/2, y: view.frame.height / 2)
addChild(player)
let carEngineStart = SKAudioNode(fileNamed: "car_engine_running")
addChild(carEngineStart)
run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run(addCompetitor),
SKAction.wait(forDuration: 4)
])
))
}
override func update(_ currentTime: TimeInterval) {
let internalRollSign = TrialSpriteKit.sign(internalRoll)
switch internalRollSign {
case .zero:
break
case .positive:
if player.position.y < self.size.height {
player.position.y += moveRate
}
case .negative:
if player.position.y > 0 {
player.position.y -= moveRate
}
}
}
enum Car: String, CaseIterable {
case blue = "blue"
case green = "green"
case orange = "orange"
case purple = "purple"
case utili = "utili"
case white = "white"
case yellow = "yellow"
static func random<G: RandomNumberGenerator>(using generator: inout G) -> Car {
return Car.allCases.randomElement(using: &generator)!
}
static func random() -> Car {
var g = SystemRandomNumberGenerator()
return Car.random(using: &g)
}
}
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / /* 0xFFFFFFFF */ 4294967296)
}
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return random() * (max - min) + min
}
func addCompetitor() {
// Create sprite
let carString = Car.random().rawValue
let car = SKSpriteNode(imageNamed: carString)
car.physicsBody = SKPhysicsBody(rectangleOf: car.size) // 1
car.physicsBody?.isDynamic = true
car.physicsBody?.affectedByGravity = false
// car.physicsBody?.categoryBitMask = 0b00001
car.physicsBody?.collisionBitMask = 0b00001
car.physicsBody?.contactTestBitMask = 0b00001
// Determine where to spawn the car along the Y axis
let actualY = random(min: car.size.height/2, max: size.height - car.size.height/2)
// Position the car slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
car.position = CGPoint(x: size.width + car.size.width/2, y: actualY)
// Add the car to the scene
addChild(car)
// Determine speed of the car
let actualDuration = random(min: CGFloat(2.0), max: CGFloat(4.0))
// Create the actions
let actionMove = SKAction.move(to: CGPoint(x: -car.size.width/2, y: actualY), duration: TimeInterval(actualDuration))
let actionMoveDone = SKAction.removeFromParent()
car.run(SKAction.sequence([actionMove, actionMoveDone]))
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
contact.bodyA.pinned = true
player.physicsBody?.pinned = true
let explosion = SKSpriteNode(imageNamed: "explosion")
explosion.position = contact.contactPoint
addChild(explosion)
run(
SKAction.sequence(
[
SKAction.playSoundFileNamed("car_explosion", waitForCompletion: true),
SKAction.run({
explosion.removeFromParent()
contact.bodyB.node?.removeFromParent()
}),
SKAction.wait(forDuration: 1),
SKAction.run({
self.player.zRotation = 0
self.player.position = CGPoint(x: 20 + self.player.size.width/2, y: self.view!.frame.height / 2)
self.player.physicsBody?.pinned = false
})
]
)
)
}
}
You have the reason for the multiple nodes in your question.
I noticed it doing this when I added the code to set the pinned
properties of the physicsBody objects to true in the didBegin callback
method.
According to the SpriteKit documentation, when you set the pinned property to true and the parent node has a physics body, the two bodies are treated as if they are connected with a pin joint.
Because the two bodies are connected, contact is being made repeatedly, even if there isn't a collision, resulting in repeated calls to the didBegin function. Each call to didBegin creates a new sprite node. Your game is calling didBegin many more times than you expect so you end up with more sprite nodes than you expect.
The general solution is to create the explosion sprite node only when there is a collision and only create the sprite node once per collision.

How do I register a tap to the screen to restart the game

Everything I need are commented down below, I have a function that when I tap it, the game should restart. The restart function works by its self, but I only want it to restart after the user taps the screen. If you need some clearing up on what certain parts of the code do, just comment down below please Could you please let me know what I've done wrong, thanks!
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKSpriteNode()
var enemy = SKSpriteNode()
var main = SKSpriteNode()
var topLbl = SKLabelNode()
var btmLbl = SKLabelNode()
var score = [Int]()
func pauseGame() { // PAUSE GAME FUCTION
self.isPaused = true
self.physicsWorld.speed = 0
self.speed = 0.0
self.scene?.view?.isPaused = true
}
func test(gestureRecognizer: UITapGestureRecognizer) { // MY FUNC TO RESTART THE GAME
let skView = self.view!
skView.presentScene(scene)
}
override func didMove(to view: SKView) {
topLbl = self.childNode(withName: "topLabel") as! SKLabelNode
btmLbl = self.childNode(withName: "btmLabel") as! SKLabelNode
ball = self.childNode(withName: "ball") as! SKSpriteNode
print(self.view?.bounds.height)
enemy = self.childNode(withName: "enemy") as! SKSpriteNode
enemy.position.y = (self.frame.height / 2) - 50
main = self.childNode(withName: "main") as! SKSpriteNode
main.position.y = (-self.frame.height / 2) + 50
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 1
self.physicsBody = border
startGame()
}
func startGame() {
score = [0,0]
topLbl.text = "\(score[1])"
btmLbl.text = "\(score[0])"
ball.physicsBody?.applyImpulse(CGVector(dx: 10 , dy: 10))
}
func addScore(playerWhoWon : SKSpriteNode){
ball.position = CGPoint(x: 0, y: 0)
ball.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
if playerWhoWon == main {
score[0] += 1
ball.physicsBody?.applyImpulse(CGVector(dx: 10, dy: 10))
}
else if playerWhoWon == enemy {
score[1] += 1
ball.physicsBody?.applyImpulse(CGVector(dx: -10, dy: -10))
}
if score[0] >= 10 {
pauseGame()
test() // HERE'S WHERE I TRY AND CALL THE FUNCTION, BUT IT's NOT WORKING
}
else if
score [1] >= 10 {
pauseGame()
test() // HERE'S WHERE I TRY AND CALL THE FUNCTION, BUT IT's NOT WORKING AGAIN
}
topLbl.text = "\(score[1])"
btmLbl.text = "\(score[0])"
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if currentGameType == .player2 {
if location.y > 0 {
enemy.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
if location.y < 0 {
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
else {
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if currentGameType == .player2 {
if location.y > 0 {
enemy.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
if location.y < 0 {
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
else{
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
switch currentGameType {
case .easy:
enemy.run(SKAction.moveTo(x: ball.position.x, duration: 1.3))
break
case .medium:
enemy.run(SKAction.moveTo(x: ball.position.x, duration: 1.0))
break
case .hard:
enemy.run(SKAction.moveTo(x: ball.position.x, duration: 0.7))
break
case .player2:
break
}
if ball.position.y <= main.position.y - 30 {
addScore(playerWhoWon: enemy)
}
else if ball.position.y >= enemy.position.y + 30 {
addScore(playerWhoWon: main)
}
}
}
As far as I understand, SKScene conforms to UIResponder protocol since you're using touchesBegan and touchesMoved methods. The protocol also has touchesEnded(Set<UITouch>, with: UIEvent?) method.
Basucally you need to add something like:
override func touchesEnded(Set<UITouch>, with: UIEvent?)
{
let skView = self.view!
skView.presentScene(scene)
}
This method is invoked when user removes his finger from the screen after tapping the GameScene object.
You can use UITapGestureRecognizer as well. To do so however, you need to create an instance of it, declare your class as its delegate, add the view you want to tap into its collection and attach a method to it. I've never done this programmatically, only in the IB. The setup looks like so:
To add a tap gesture via code:
In your GameScene class:
weak var tapGesture : UITapGestureRecognizer!
override func didMoveToView(view: SKView) {
tapGesture = UITapGestureRecognizer(target:self,action:#selector(self.handleTap:)
view.addGestureRecognizer(tapGesture )
}
func handleTap(sender:UITapGestureRecognizer){
//restartLogic here
}
deinit{
view.removeGestureRecognizer(tapGesture)
}
Skip the gesture recognizer.
Simply call the restart code from touchesEnded if the game is not in progress.

Swift SpriteKit: Creating a realistic driving experience 2D

How would I go by creating a realistic driving experience?
I'm using iOS Swift 3 with SpriteKit using the functions applyForce to accelerate when I click the gas button and when braking I add friction to the physicsBody, also I can't seem to turn right, no idea on how to do it.
Right now for turning I'm splitting the screen using the left and right to turn but I'm using applyForce but its very bad because it turns when the car is stopped and in a very unrealistic way.
When I apply force its only to go up so if I do create a turning mechanism and I do a uturn the car will still go up.
Also side note: Multitouch doesn't work?
Any help? Thanks
override func didMove(to view: SKView) {
// Multi Touch
self.view?.isMultipleTouchEnabled = true
car.carNode.position = CGPoint(x: 0, y: 0)
car.carNode.physicsBody = SKPhysicsBody(rectangleOf: car.carNode.size)
car.carNode.physicsBody?.affectedByGravity = false
car.carNode.physicsBody?.angularDamping = 0.1
car.carNode.physicsBody?.linearDamping = 0.1
car.carNode.physicsBody?.friction = 0.1
car.carNode.physicsBody?.mass = 1
self.addChild(car.carNode)
// HUD Display
gas.gasButton.position = CGPoint(x: 300, y: -500)
self.addChild(gas.gasButton)
brake.brakeButton.position = CGPoint(x: 150, y: -500)
self.addChild(brake.brakeButton)
}
override func update(_ currentTime: TimeInterval) {
if touching {
car.carNode.physicsBody?.applyForce(CGVector(dx: 0, dy: 180))
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if location.x < self.frame.size.width / 2 {
// Left side of the screen
car.carNode.physicsBody?.applyForce(CGVector(dx: -100, dy: 0))
} else {
// Right side of the screen
car.carNode.physicsBody?.applyForce(CGVector(dx: 100, dy: 0))
}
// Gas Button
if (gas.gasButton.contains(location)) {
touching = true
}
// Brake Button
else if (brake.brakeButton.contains(location)) {
car.carNode.physicsBody?.friction = 1
}
}
}
Integration of the comment
for touch in touches {
let location = touch.location(in: self)
let velY = car.carNode.physicsBody?.velocity.dy
let factor:CGFloat = 100
let maxFactor:CGFloat = 300
//limit
let dxCalc = factor * velY > maxFactor ? maxFactor : factor * velY
if location.x < self.frame.size.width / 2 {
// Left side of the screen
car.carNode.physicsBody?.applyForce(CGVector(dx: -dxCalc, dy: 0))
} else {
// Right side of the screen
car.carNode.physicsBody?.applyForce(CGVector(dx: dxCalc, dy: 0))
}
// Gas Button
//etc
}
}

Implementing collision detections

Basically the game consists of a basket that the player moves across the screen, the aim of the game is for the player to catch balls falling from the top of the screen. I am currently trying to add collision detection between the balls and the basket, but am facing difficulties namely, implementing this collision detection. I am new to swift, sprite kit and app development, so please help. Any help would be appreciated. Another problem I am facing is that all the balls are falling in the centre of the screen. A line of code is supposed to execute when, the ball hits the basket and following that the ball should disappear, please help as I am new to Spritekit.
import SpriteKit
class GameScene: SKScene {
var basket = SKSpriteNode()
let actionMoveRight = SKAction.moveByX(50, y: 0, duration: 0.2)
let actionMoveLeft = SKAction.moveByX(-50, y: 0, duration: 0.2)
//let physicsBody = SKPhysicsBody(texture: , size: 3500)
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.physicsWorld.gravity = CGVectorMake(0.0, -0.5)
self.backgroundColor = SKColor.whiteColor()
basket = SKSpriteNode(imageNamed: "basket")
basket.setScale(0.5)
basket.position = CGPointMake(self.size.width/2, self.size.height/8)
basket.size.height = 50
basket.size.width = 75
self.addChild(basket)
let updateAction = SKAction.runBlock {
var choice = arc4random_uniform(3)
switch choice {
case 1 :
var ball1 = SKSpriteNode(imageNamed: "redBall")
ball1.position = CGPointMake(self.size.width/3, self.size.height)
ball1.setScale(0.5)
ball1.size.height = 20
ball1.size.width = 30
ball1.physicsBody = SKPhysicsBody(circleOfRadius: ball1.size.height / 2.75)
ball1.physicsBody!.dynamic = true
self.addChild(ball1)
println("0")
case 0 :
var ball2 = SKSpriteNode(imageNamed: "redBall")
ball2.position = CGPointMake(self.size.width/5, self.size.height)
ball2.setScale(0.5)
ball2.size.height = 20
ball2.size.width = 30
ball2.physicsBody = SKPhysicsBody(circleOfRadius: ball2.size.height / 2.75)
ball2.physicsBody!.dynamic = true
self.addChild(ball2)
println("1")
case 2 :
var ball3 = SKSpriteNode(imageNamed: "redBall")
ball3.position = CGPointMake(self.size.width*4/5, self.size.height)
ball3.setScale(0.5)
ball3.size.height = 20
ball3.size.width = 30
ball3.physicsBody = SKPhysicsBody(circleOfRadius: ball3.size.height / 2.75)
ball3.physicsBody!.dynamic = true
self.addChild(ball3)
println("2")
default :
println("Problem")
}
}
let waitDuration : NSTimeInterval = 1.0
let updateAndWaitAction = SKAction.sequence([updateAction,SKAction.waitForDuration(waitDuration)])
let repeatForeverAction = SKAction.repeatActionForever(updateAndWaitAction)
self.runAction(repeatForeverAction)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if location.x > basket.position.x {
if basket.position.x < self.frame.maxX {
basket.runAction(actionMoveRight)
}
}
else {
if basket.position.x > self.frame.minX {
basket.runAction(actionMoveLeft)
}
}
}
}
override func update(currentTime: CFTimeInterval) {
}
}
For now you have a code that typically used in situations where user is taping something. You need to use BodyA & BodyB and assign a bitmasks to your nodes.
self.basket.physicsBody?.categoryBitMask = ColliderType.basket.rawValue
self.basket.physicsBody?.contactTestBitMask = ColliderType.ball1.rawValue
self.basket.physicsBody?.collisionBitMask = ColliderType.ball1.rawValue
self.basket.physicsBody?.contactTestBitMask = ColliderType.ball2.rawValue
self.basket.physicsBody?.collisionBitMask = ColliderType.ball2.rawValue
self.basket.physicsBody?.contactTestBitMask = ColliderType.ball3.rawValue
self.basket.physicsBody?.collisionBitMask = ColliderType.ball3.rawValue
And do that for every ball too. And then in func didBeginContact you should say to Xcode what to do, if you have an animation or something:
if (contact.bodyA.categoryBitMask == ColliderType.ball1.rawValue || contact.bodyB.categoryBitMask == ColliderType.ball1.rawValue) {
yourGameOverFunc()
}
if (contact.bodyA.categoryBitMask == ColliderType.ball2.rawValue || contact.bodyB.categoryBitMask == ColliderType.ball2.rawValue) {
yourGameOverFunc()
}
if (contact.bodyA.categoryBitMask == ColliderType.ball3.rawValue || contact.bodyB.categoryBitMask == ColliderType.ball3.rawValue) {
yourGameOverFunc()
}

Resources