Sprite Kit set Min. and Max. for Jump - ios

I want to move a SKSpriteNode on the Y-Axis. The SKSpriteNode called Player has no Velocity.The Player can only jump if a Platform is in contact.
Everytime the Screen is touched, I want to give the Player an impulse with a minimum impulse or a maximum impulse
If the Screen is tapped shortly, the Minimum impulse should be e.g. y = 50.
If the Screen is hold, that means the finger is on the Screen long, the Maximum should be e.g. y = 100.
But the Player should be also able to jump between the Minimum and Maximum height, if for e.g. the Screen is not long but also not shortly pressed, the Player should only get an impulse of y = 70.
If the Screen is hold, the Player should jump to his max height, fall down, and if it is in contact with the Platform again, it should jump, because you still hold the Screen.
I have already tried this with the suggested answer in this Thread:StackOverFlow
But this does not give the Minimum jump, also no Press jump.
For clarity: The impulse should not be after the tap is done, but while it is tapped. The longer you hold, the longer the jump is.
import SpriteKit
import GameKit
struct Constants {
static let minimumJumpForce:CGFloat = 40.0
static let maximumJumpForce:CGFloat = 60.0
static let characterSideSpeed:CGFloat = 18.0
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var Player: SKSpriteNode!
var Platform0: SKSpriteNode!
var World: SKNode!
var Camera: SKNode!
var force: CGFloat = 40.0
var pressed = false
var isCharacterOnGround = false
.....
func SpawnPlatforms() {
Platform0 = SKSpriteNode (color: SKColor.greenColor(), size: CGSize(width: self.frame.size.width , height: 25))
Platform0.position = CGPoint(x: self.frame.size.width / 2, y: -36)
Platform0.zPosition = 1
Platform0.physicsBody = SKPhysicsBody(rectangleOfSize:Platform0.size)
Platform0.physicsBody?.dynamic = false
Platform0.physicsBody?.allowsRotation = false
Platform0.physicsBody?.restitution = 0
Platform0.physicsBody?.usesPreciseCollisionDetection = true
Platform0.physicsBody?.categoryBitMask = Platform0Category
Platform0.physicsBody?.collisionBitMask = PlayerCategory
Platform0.physicsBody?.contactTestBitMask = PlayerCategory
World.addChild(Platform0)
}
func SpawnPlayer(){
Player = SKSpriteNode (imageNamed: "Image.png")
Player.size = CGSize(width: 64, height: 64)
Player.position = CGPoint(x: self.frame.size.width / 2, y: 0)
Player.zPosition = 2
Player.physicsBody = SKPhysicsBody(rectangleOfSize:CGSize(width: 35, height: 50))
Player.physicsBody?.dynamic = true
Player.physicsBody?.allowsRotation = false
Player.physicsBody?.restitution = 0.1
Player.physicsBody?.usesPreciseCollisionDetection = true
Player.physicsBody?.categoryBitMask = PlayerCategory
Player.physicsBody?.collisionBitMask = Platform0Category
Player.physicsBody?.contactTestBitMask = Platform0Category | Platform1Category | Platform2Category | Platform3Category | Platform4Category | Platform5Category
World.addChild(Player)
}
func jump(force : CGFloat){
if(self.isCharacterOnGround){
self.Player.physicsBody?.applyImpulse(CGVectorMake(0, force))
self.isCharacterOnGround = false
}
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
self.pressed = true
let timerAction = SKAction.waitForDuration(0.0)
let update = SKAction.runBlock({
if(self.force < Constants.maximumJumpForce){
self.force += 2.0
}else{
self.jump(Constants.maximumJumpForce)
self.force = Constants.maximumJumpForce
}
})
let sequence = SKAction.sequence([timerAction, update])
let repeat = SKAction.repeatActionForever(sequence)
self.runAction(repeat, withKey:"repeatAction")
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
self.removeActionForKey("repeatAction")
self.jump(self.force)
self.force = Constants.minimumJumpForce
self.pressed = false
}
}
func didBeginContact(contact: SKPhysicsContact) {
//this gets called automatically when two objects begin contact with each other
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch(contactMask) {
case PlayerCategory | Platform0Category:
//either the contactMask was the bro type or the ground type
println("Contact Made0")
Green = true
self.isCharacterOnGround = true
default:
return
}
}

Here is an working example on how to make something like:
long pressed jump based on duration of press
short (one tap jump)
restrict character to jump while in the air
keep character jumping while finger is on screen
Code (Swift 4.x)
import SpriteKit
struct Constants {
static let minimumJumpForce:CGFloat = 15.0
static let maximumJumpForce:CGFloat = 30.0
static let characterSideSpeed:CGFloat = 18.0
}
class GameScene: SKScene,SKPhysicsContactDelegate
{
let CharacterCategory : UInt32 = 0x1 << 1
let PlatformCategory : UInt32 = 0x1 << 2
let WallCategory : UInt32 = 0x1 << 3
var force: CGFloat = 16.0 //Initial force
var pressed = false
var isCharacterOnGround = false // Use this to prevent jumping while in the air
let character = SKSpriteNode(color: .green, size: CGSize(width: 30, height:30))
let debugLabel = SKLabelNode(fontNamed: "Geneva")
override func didMove(to view: SKView)
{
//Setup contact delegate so we can use didBeginContact and didEndContact methods
physicsWorld.contactDelegate = self
physicsWorld.speed = 0.5
//Setup borders so character can't escape from us :-)
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
self.physicsBody?.categoryBitMask = WallCategory
self.physicsBody?.collisionBitMask = CharacterCategory
//Setup character
character.position = CGPoint(x: 150, y: 150)
character.physicsBody = SKPhysicsBody(rectangleOf: character.size)
character.physicsBody?.categoryBitMask = CharacterCategory
character.physicsBody?.contactTestBitMask = PlatformCategory
character.physicsBody?.collisionBitMask = PlatformCategory | WallCategory
character.physicsBody?.allowsRotation = false
character.physicsBody?.isDynamic = true
character.physicsBody?.restitution = 0.1
self.addChild(character)
generatePlatforms()
debugLabel.text = " DEBUG: "
debugLabel.fontColor = .white
debugLabel.fontSize = 12.0
debugLabel.position = CGPoint(x: frame.midX, y: frame.midY+100)
self.addChild(debugLabel)
}
func generatePlatforms(){
for i in 1...4
{
let position = CGPoint(x: frame.midX, y: CGFloat(i)*140.0 - 100)
let platform = createPlatformAtPosition(position: position)
self.addChild(platform)
}
}
func createPlatformAtPosition(position : CGPoint)->SKSpriteNode{
let platform = SKSpriteNode(color: .green, size: CGSize(width: frame.size.width, height:20))
platform.position = position
platform.physicsBody = SKPhysicsBody(
edgeFrom: CGPoint(x: -platform.size.width/2.0, y:platform.size.height/2.0),
to:CGPoint(x: platform.size.width/2.0, y: platform.size.height/2.0))
platform.physicsBody?.categoryBitMask = PlatformCategory
platform.physicsBody?.contactTestBitMask = CharacterCategory
platform.physicsBody?.collisionBitMask = CharacterCategory
platform.physicsBody?.allowsRotation = false
platform.name = "platform"
platform.physicsBody?.isDynamic = false
platform.physicsBody?.restitution = 0.0
return platform
}
func jump(force : CGFloat){
if(self.isCharacterOnGround){
self.character.physicsBody?.applyImpulse(CGVector(dx: 0, dy: force))
self.character.physicsBody?.collisionBitMask = WallCategory
self.isCharacterOnGround = false
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.pressed = true
let timerAction = SKAction.wait(forDuration: 0.05)
let update = SKAction.run({
if(self.force < Constants.maximumJumpForce){
self.force += 2.0
}else{
self.jump(force: Constants.maximumJumpForce)
self.force = Constants.maximumJumpForce
}
})
let sequence = SKAction.sequence([timerAction, update])
let repeat_seq = SKAction.repeatForever(sequence)
self.run(repeat_seq, withKey:"repeatAction")
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.removeAction(forKey: "repeatAction")
self.jump(force: self.force)
self.force = Constants.minimumJumpForce
self.pressed = false
}
override func update(_ currentTime: TimeInterval) {
debugLabel.text = "DEBUG: onTheGround : \(isCharacterOnGround), force \(force)"
if(character.position.x <= character.size.width/2.0 + 5.0 && character.physicsBody!.velocity.dx < 0.0 ){
character.physicsBody?.applyForce(CGVector(dx: Constants.characterSideSpeed, dy: 0.0))
}else if((character.position.x >= self.frame.size.width - character.size.width/2.0 - 5.0) && character.physicsBody!.velocity.dx >= 0.0){
character.physicsBody?.applyForce(CGVector(dx: -Constants.characterSideSpeed, dy: 0.0))
}else if(character.physicsBody!.velocity.dx > 0.0){
character.physicsBody!.applyForce(CGVector(dx: Constants.characterSideSpeed, dy: 0.0))
}else{
character.physicsBody!.applyForce(CGVector(dx: -Constants.characterSideSpeed, dy: 0.0))
}
}
func didBegin(_ contact: SKPhysicsContact) {
var firstBody, 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 & CharacterCategory) != 0 &&
(secondBody.categoryBitMask & PlatformCategory != 0)) {
let platform = secondBody.node! as! SKSpriteNode
// platform.color = UIColor.redColor()
let platformSurfaceYPos = platform.position.y + platform.size.height/2.0
let player = contact.bodyB.node! as! SKSpriteNode
let playerLegsYPos = player.position.y - player.size.height/2.0
if((platformSurfaceYPos <= playerLegsYPos)){
character.physicsBody?.collisionBitMask = PlatformCategory | WallCategory
self.isCharacterOnGround = true
if(self.pressed){
let characterDx = character.physicsBody?.velocity.dx
character.physicsBody?.velocity = CGVector(dx: characterDx!, dy: 0.0)
self.jump(force: Constants.maximumJumpForce)
}
}
}
}
func didEnd(_ contact: SKPhysicsContact) {
var firstBody, 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 & CharacterCategory) != 0 &&
(secondBody.categoryBitMask & PlatformCategory != 0)) {
let platform = secondBody.node as! SKSpriteNode
let platformSurfaceYPos = platform.position.y + platform.size.height/2.0
let player = contact.bodyB.node as! SKSpriteNode
let playerLegsYPos = player.position.y - player.size.height/2.0
if((platformSurfaceYPos <= playerLegsYPos) && ((character.physicsBody?.velocity.dy)! > CGFloat(0.0))){
character.physicsBody?.collisionBitMask = WallCategory
self.isCharacterOnGround = false
}
}
}
}
Note that this is simple example, and in real application you will probably have to handle states like isOnTheGround in a different way. Right now, to determine if character is on the ground you just set isOnTheGround = true when character make a contact with platform, and set it to false in didEndContact...But there are situations when character can be in contact with platform while in the air (eg. side contact)...
EDIT:
I changed the code to let the player jump while pressed. Here is the result:
Important:
Actual platform implementation and contact handling is up to you and this is not tested. The only purpose of this example is to show you how to jump while pressed. Currently, physicsWorld.speed is set to 0.5 to make animation slower because its easier to debug like that, but you can change this to default value (1.0).
So, as you can see from the image, while player is on the first platform some small jumps are presented (by simple tapping, or short pressing). Then (player is still on first platform) long press has been made, and player has jumped on second platform. After that, another long press is done, but this time without releasing, and player starts jumping from one platform to another using maximum force.
This needs a lot of tweaking and proper platform & contact detection, but it can give you an idea about how to implement jumping you asked about.

Related

SKSpriteNode disappear in GameScene

I'm facing some problem with spritekit in swift.
I was following closely to online tutorials (combining different tutorials into 1 project), trying out the code when I realised my SKSpriteNodes (my "player" and "enemy") sometimes go missing when I try it out on simulator or my iphone.
My situation is kinda similar to this user's problem here, but I don't think my problem lies with the size.
Can anyone enlighten me? Thank you!
Here's my code.
var player : SKSpriteNode!
var backdrop : SKSpriteNode!
var gameTimer : Timer!
var possibleEnemies = ["enemy01", "enemy02", "enemy03"]
let bulletsCategory : UInt32 = 0x1 << 0
let enemyCategory : UInt32 = 0x1 << 1
override func didMove(to view: SKView) {
player = SKSpriteNode(imageNamed: "bird.png")
player.position = CGPoint(x: 0, y: (player.size.height / 2) )
self.addChild(player)
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
self.physicsWorld.contactDelegate = self
self.anchorPoint = CGPoint (x: 0.5 , y: 0)
createBackdrop()
scoreLabel = SKLabelNode(text: "Score: 0")
scoreLabel.position = CGPoint(x: 260, y: self.frame.size.height - 90)
scoreLabel.fontName = "Avenir Book"
scoreLabel.fontSize = 35
scoreLabel.fontColor = UIColor.gray
score = 0
self.addChild(scoreLabel)
gameTimer = Timer.scheduledTimer(timeInterval: 0.75, target: self, selector: #selector(addEnemies), userInfo: nil, repeats: true)
}
#objc func addEnemies() {
possibleEnemies = GKRandomSource.sharedRandom().arrayByShufflingObjects(in: possibleEnemies) as! [String]
let enemy = SKSpriteNode(imageNamed: possibleEnemies[0])
let randomEnemyPosition = GKRandomDistribution(lowestValue: -360, highestValue: 360)
let position = CGFloat(randomEnemyPosition.nextInt())
enemy.position = CGPoint(x: position, y: self.frame.size.height + enemy.size.height)
enemy.physicsBody = SKPhysicsBody(rectangleOf: enemy.size)
enemy.physicsBody?.isDynamic = true
enemy.physicsBody?.categoryBitMask = enemyCategory
enemy.physicsBody?.contactTestBitMask = bulletsCategory
enemy.physicsBody?.collisionBitMask = 0
self.addChild(enemy)
let animationDuration : TimeInterval = 6
var actionArray = [SKAction]()
actionArray.append(SKAction.move(to: CGPoint(x: position, y: -enemy.size.height), duration: animationDuration))
actionArray.append(SKAction.removeFromParent())
enemy.run(SKAction.sequence(actionArray))
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
fireBullets()
}
func fireBullets() {
self.run(SKAction.playSoundFileNamed("shoot.wav", waitForCompletion: false))
let bullets = SKSpriteNode(imageNamed: "bullet.png")
bullets.position = player.position
bullets.position.y += 5
bullets.physicsBody = SKPhysicsBody(rectangleOf: bullets.size)
bullets.physicsBody?.isDynamic = true
bullets.physicsBody?.categoryBitMask = bulletsCategory
bullets.physicsBody?.contactTestBitMask = enemyCategory
bullets.physicsBody?.collisionBitMask = 0
bullets.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(bullets)
let animationDuration : TimeInterval = 0.3
var actionArray = [SKAction]()
actionArray.append(SKAction.move(to: CGPoint(x: player.position.x, y: self.frame.size.height + 10), duration: animationDuration))
actionArray.append(SKAction.removeFromParent())
bullets.run(SKAction.sequence(actionArray))
}
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 & bulletsCategory) != 0 && (secondBody.categoryBitMask & enemyCategory) != 0 {
hitByBullets(bulletNode: firstBody.node as! SKSpriteNode, enemyNode: secondBody.node as! SKSpriteNode)
}
}
func hitByBullets (bulletNode: SKSpriteNode, enemyNode: SKSpriteNode) {
let shot = SKEmitterNode(fileNamed: "Magic01")!
shot.position = enemyNode.position
self.addChild(shot)
self.run(SKAction.playSoundFileNamed("shot.mp3", waitForCompletion: false))
bulletNode.removeFromParent()
enemyNode.removeFromParent()
self.run(SKAction.wait(forDuration: 2)) {
shot.removeFromParent()
}
score += 1
}
func touchDown(atPoint pos : CGPoint) {
player.position = pos
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
moveBackdrop()
}
the issue for you sprites not showing up is that none of your objects have a zPosition set on them. You need to layer the objects as you expect them to show in the scene.
for example...
background.zPosition = 1
player.zPosition = 1
enemy.zPosition = 1
bullet.zPosition = 2
scoreLabel.zPosition = 100
In my opinion you shouldn't be using timers to generate your enemies. Spritekit has it's own timing functionality built into the update function. Which you are already using to control the timing of the backgrounds.
You had waaaaay to much code in your question, you need to look at how I've tailored the code down to only relevant code to your question. Including all of your code in your question actually makes it more unlikely that you will get the help or answers you need because it is harder to go through all the code to figure out what is happening. Also don't include so many spaces in your code in your question scrolling through hundreds of lines even if a lot of them are spaces is very tedious.
Didn't realised the importance of zPosition since my items show up perfectly on screen some of the times. Added the following in their respective place and they stop disappearing intermittently.
player.zPosition = 3
scoreLabel.zPosition = 100
enemy.zPosition = 3
bullets.zPosition = 2
backdrop.zPosition = 1
shot.zPosition = 3

Not detecting Collisions properly in Swift

I'm making a game that spawns cubes from the top of the screen, when they are touched they disappear. I'm setting an objects position to the point touched by the user. It runs the function DidBeginContact , but it doesn't seem to detect my two views:
func didBeginContact(contact: SKPhysicsContact) {
var firstBody : SKPhysicsBody = contact.bodyA
var secondBody : SKPhysicsBody = contact.bodyB
print("didbegincontact")
if ((firstBody.categoryBitMask == PhysicsCategory.RedSquare) && (secondBody.categoryBitMask == PhysicsCategory.touchlocation)) || ((firstBody.categoryBitMask == PhysicsCategory.touchlocation) && (secondBody.categoryBitMask == PhysicsCategory.RedSquare)) {
collisionwithredsquare(firstBody.node as! SKSpriteNode)
print("Done")
}
}
It's printing "didBegincontact" so I know that the function is working but the if statement is not.
Here's all the code:
import SpriteKit
struct PhysicsCategory {
static let RedSquare : UInt32 = 1
static let touchlocation : UInt32 = 2
static let BlueSquare : UInt32 = 3
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var animator : UIDynamicAnimator?
let blueSquare = SKSpriteNode()
let redSquare = SKSpriteNode()
var scorenumber = 0
var ground = SKSpriteNode()
var touchpoint = SKSpriteNode()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
physicsWorld.contactDelegate = self
physicsWorld.gravity = CGVector(dx: 1.0, dy: -9.0)
/* let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
// 2. Set the friction of that physicsBody to 0
borderBody.friction = 0
// 3. Set physicsBody of scene to borderBody
self.physicsBody = borderBody */
touchpoint = SKSpriteNode(imageNamed:"Spaceship")
touchpoint.physicsBody?.categoryBitMask = PhysicsCategory.touchlocation
touchpoint.physicsBody?.contactTestBitMask = PhysicsCategory.RedSquare
touchpoint.physicsBody?.affectedByGravity = false
touchpoint.xScale = 0.5
touchpoint.yScale = 0.5
self.addChild(touchpoint)
let width = UInt32(self.frame.size.width)
let X = arc4random() % width
ground = SKSpriteNode(imageNamed: "Ground")
ground.setScale(1.0)
ground.position = CGPoint(x: self.frame.width / 2, y: 5)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: ground.size)
ground.physicsBody?.affectedByGravity = false
ground.physicsBody?.dynamic = false
ground.zPosition = 3
self.addChild(ground)
//INizialize
animator = UIDynamicAnimator(referenceView: self.view!)
//Add Gravity
//animator?.addBehavior(gravity, sprite)
var test = arc4random() % 90
blueSquare.size = CGSize(width: 100, height: 100)
blueSquare.position = CGPoint(x: CGFloat(X), y: 1000)
blueSquare.zRotation = 34
blueSquare.name = "bluecube"
blueSquare.physicsBody = SKPhysicsBody(circleOfRadius: 20)
blueSquare.physicsBody?.affectedByGravity = true
blueSquare.physicsBody?.dynamic = false
blueSquare.color = SKColor.blueColor()
// BlueSquare.physicsBody?.velocity = CGVectorMake(0, 0)
//BlueSquare.physicsBody?.applyImpulse(CGVectorMake(0, -90))
self.addChild(blueSquare)
let X2 = arc4random() % width
redSquare.size = CGSize(width: 100, height: 100)
redSquare.position = CGPoint(x: CGFloat(X2), y: 1000)
redSquare.name = "redcube"
redSquare.physicsBody = SKPhysicsBody(circleOfRadius: 20)
redSquare.physicsBody?.affectedByGravity = true
redSquare.physicsBody?.dynamic = true
redSquare.hidden = false
redSquare.physicsBody?.categoryBitMask = PhysicsCategory.RedSquare
redSquare.physicsBody?.contactTestBitMask = PhysicsCategory.touchlocation
redSquare.color = SKColor.redColor()
self.addChild(redSquare)
let timerAction1 = SKAction.waitForDuration(0.5)
let timerAction2 = SKAction.runBlock(spawning1)
let timerSequence = SKAction.sequence([timerAction1, timerAction2])
runAction(SKAction.repeatActionForever(timerSequence))
}
func didBeginContact(contact: SKPhysicsContact) {
var firstBody : SKPhysicsBody = contact.bodyA
var secondBody : SKPhysicsBody = contact.bodyB
print("didbegincontact")
if ((firstBody.categoryBitMask == PhysicsCategory.RedSquare) && (secondBody.categoryBitMask == PhysicsCategory.touchlocation)) || ((firstBody.categoryBitMask == PhysicsCategory.touchlocation) && (secondBody.categoryBitMask == PhysicsCategory.RedSquare)) {
collisionwithredsquare(firstBody.node as! SKSpriteNode)
print("Done")
}
}
func collisionwithredsquare(redsquare: SKSpriteNode) {
print("Hello")
}
func spawning1() {
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in touches {
let location = touch.locationInNode(self)
touchpoint.position = location
}
}
func score () {
scorenumber++
print(scorenumber)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if CGRectIntersectsRect(redSquare.frame, ground.frame) {
redSquare.position = CGPoint(x: redSquare.position.x, y: redSquare.position.y + 10)
}
}
}
Thanks in advance, Niall
You collision categories are wrong. It should be this because you are dealing with 32 bit integers.
struct PhysicsCategory {
static let RedSquare: UInt32 = 0x1 << 1
static let touchlocation : UInt32 = 0x1 << 2
static let BlueSquare : UInt32 = 0x1 << 3
}
If you use your way you would have to write it like this
struct PhysicsCategory {
static let RedSquare: UInt32 = 1
static let touchlocation : UInt32 = 2
static let BlueSquare : UInt32 = 4
static let somethingElse : UInt32 = 8
}
which is more confusing because you cannot just increment the last number by 1.
Than change your collision code to this. This way you dont have to check for both bodies in the if statement.
/// Did Begin Contact
func didBeginContact(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 == PhysicsCategory.RedSquare) && (secondBody.categoryBitMask == PhysicsCategory.touchlocation) {
collisionwithredsquare(firstBody.node) // I aim pretty sure you dont need to cast as SKSpriteNod, because the body its already a SKNode.
print("Done")
}
}
Also on the touchLocaiton sprite you forgot to give it a physics body.
touchpoint.pysicsBody = SKPhysicsBody(..) // FORGOT THIS LINE
touchpoint.physicsBody?.categoryBitMask = PhysicsCategory.touchlocation
touchpoint.physicsBody?.contactTestBitMask = PhysicsCategory.RedSquare
touchpoint.physicsBody?.affectedByGravity = false
This should work now if you are already getting the contact method to be called. Let me know how it goes.

Swift Physics-fatal error: unexpectedly found nil while unwrapping an Optional value when two characters collide

Background on game: Basically you control a character that moves right and left and try to dodge falling blocks. There are three players spawned. One in the middle of the screen, and two exactly size.width away from the middle player on either sides.
This error only happens once in around 10 collisions with the playerRight or playerLeft or Player and falling blocks. As you can see by the screenshot below, the player does not seem to be touching the falling block when it crashes.
Error Code and Screenshots:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_l386_INVOP, subcode=0x0)
How the game scene stopped
I'm thinking it has something to do with how I built the "infinitely" horizontal scrolling player. Basically I have three separate characters and once the middle character goes past size.width or below 0 his position on the screen is changed to the opposite side of the screen essentially making it infinite. Maybe the Player is teleported inside of a block and it gives a nil error. Not really sure but it looks like it has something to do with that. Anyway, heres the relevant code from GameScene.
import SpriteKit
import Foundation
import UIKit
//Collisions
struct PhysicsCategory {
static let Enemy : UInt32 = 1
static let Player : UInt32 = 2
static let PlayerRight : UInt32 = 3
static let PlayerLeft : UInt32 = 4
static let EnemyRight : UInt32 = 5
}
var transition:SKTransition = SKTransition.fadeWithDuration(0.5)
class GameScene: SKScene, SKPhysicsContactDelegate {
//Highscore Variable
var Highscore = Int()
//Score
var Score : Int = 0
var ScoreLabel = UILabel()
//Main Character
var Player = SKSpriteNode(imageNamed: "mainPlayer.png")
//Right-far character
var PlayerRight = SKSpriteNode(imageNamed: "mainPlayer.png")
//Left-far character
var PlayerLeft = SKSpriteNode(imageNamed: "mainPlayer.png")
//Holding vs Tapping Movement of Player
var isTouching = false
var touchXPosition:CGFloat = 0
override func didMoveToView(view: SKView) {
/* Setup your scene here */
//Highscore
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
if (HighscoreDefault.valueForKey("Highscore") != nil) {
Highscore = HighscoreDefault.valueForKey("Highscore") as! NSInteger
}
else {
Highscore = 0
}
//Collisions/Physics
physicsWorld.contactDelegate = self
//Background Color
scene?.backgroundColor = UIColor.blackColor()
//Spawn timer for enemy blocks
var timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: Selector("spawnEnemies"), userInfo: nil, repeats: true)
//Timer for keeping score
var scoretimer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("scoreCounter"), userInfo: nil, repeats: true)
//Player coordinates
Player.position.x = size.width * 0.5
Player.position.y = size.width * 0.11 / 2
//Setting Player Sizes
Player.size.width = size.width * 0.11
Player.size.height = size.width * 0.11
PlayerRight.size.width = size.width * 0.11
PlayerRight.size.height = size.width * 0.11
PlayerLeft.size.width = size.width * 0.11
PlayerLeft.size.height = size.width * 0.11
//Initial position of player
Player.position = CGPoint(x: Player.position.x, y: Player.position.y)
//Initial position of far-right player
PlayerRight.position = CGPoint(x: Player.position.x + size.width, y: Player.position.y)
//Initial position of far-left player
PlayerLeft.position = CGPoint(x: Player.position.x - size.width, y: Player.position.y)
//Adding Physics/Collisions to Player
Player.physicsBody = SKPhysicsBody (rectangleOfSize: Player.size)
Player.physicsBody?.affectedByGravity = false
Player.physicsBody?.categoryBitMask = PhysicsCategory.Player
Player.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy
Player.physicsBody?.dynamic = false
//Adding Physics/Collisions to PlayerRight
PlayerRight.physicsBody = SKPhysicsBody (rectangleOfSize: PlayerRight.size)
PlayerRight.physicsBody?.affectedByGravity = false
PlayerRight.physicsBody?.categoryBitMask = PhysicsCategory.PlayerRight
PlayerRight.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy
PlayerRight.physicsBody?.dynamic = false
//Adding Physics/Collisions to PlayerLeft
PlayerLeft.physicsBody = SKPhysicsBody (rectangleOfSize: PlayerRight.size)
PlayerLeft.physicsBody?.affectedByGravity = false
PlayerLeft.physicsBody?.categoryBitMask = PhysicsCategory.PlayerLeft
PlayerLeft.physicsBody?.contactTestBitMask = PhysicsCategory.Enemy
PlayerLeft.physicsBody?.dynamic = false
//Making Players visible
self.addChild(Player)
self.addChild(PlayerRight)
self.addChild(PlayerLeft)
//Making Score Visible
ScoreLabel.text = "\(Score)"
ScoreLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height: 20))
ScoreLabel.font = UIFont(name: ScoreLabel.font.fontName, size:20)
ScoreLabel.textColor = UIColor.whiteColor()
self.view?.addSubview(ScoreLabel)
}
func scoreCounter() {
//Setting score
Score += 1
ScoreLabel.text = "\(Score)"
}
func didBeginContact(contact: SKPhysicsContact) {
var firstBody : SKPhysicsBody = contact.bodyA
var secondBody : SKPhysicsBody = contact.bodyB
//Checking for Player to enemy collisions
if ((firstBody.categoryBitMask == PhysicsCategory.Enemy) && (secondBody.categoryBitMask == PhysicsCategory.Player)){
CollisionWithEnemy(firstBody.node as! SKShapeNode, Player: secondBody.node as! SKSpriteNode)
}
else if (firstBody.categoryBitMask == PhysicsCategory.Player) && (secondBody.categoryBitMask == PhysicsCategory.Enemy) {
CollisionWithEnemy2(firstBody.node as! SKSpriteNode, Enemy: secondBody.node as! SKShapeNode)
}
//Checking for PlayerRight to enemy collisions
if ((firstBody.categoryBitMask == PhysicsCategory.Enemy) && (secondBody.categoryBitMask == PhysicsCategory.PlayerRight)){
CollisionWithEnemy(firstBody.node as! SKShapeNode, Player: secondBody.node as! SKSpriteNode)
}
else if (firstBody.categoryBitMask == PhysicsCategory.PlayerRight) && (secondBody.categoryBitMask == PhysicsCategory.Enemy) {
CollisionWithEnemy2(firstBody.node as! SKSpriteNode, Enemy: secondBody.node as! SKShapeNode)
}
//Checking for PlayerLeft to enemy collisions
if ((firstBody.categoryBitMask == PhysicsCategory.Enemy) && (secondBody.categoryBitMask == PhysicsCategory.PlayerLeft)){
CollisionWithEnemy(firstBody.node as! SKShapeNode, Player: secondBody.node as! SKSpriteNode)
}
else if (firstBody.categoryBitMask == PhysicsCategory.PlayerLeft) && (secondBody.categoryBitMask == PhysicsCategory.Enemy) {
CollisionWithEnemy2(firstBody.node as! SKSpriteNode, Enemy: secondBody.node as! SKShapeNode)
}
}
func CollisionWithEnemy(Enemy: SKShapeNode, Player: SKSpriteNode) {
//Highscore
var ScoreDefault = NSUserDefaults.standardUserDefaults()
ScoreDefault.setValue(Score, forKey: "Score")
ScoreDefault.synchronize()
if (Score > Highscore) {
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
HighscoreDefault.setValue(Score, forKey: "Highscore")
}
//var gameOver:SKScene = GameOverScene(size: self.size)
//ScoreLabel.removeFromSuperview()
Enemy.removeFromParent()
//Player.removeFromParent()
//self.view?.presentScene(gameOver, transition: transition)
}
func CollisionWithEnemy2(Player: SKSpriteNode, Enemy: SKShapeNode) {
//Highscore
var ScoreDefault = NSUserDefaults.standardUserDefaults()
ScoreDefault.setValue(Score, forKey: "Score")
ScoreDefault.synchronize()
if (Score > Highscore) {
var HighscoreDefault = NSUserDefaults.standardUserDefaults()
HighscoreDefault.setValue(Score, forKey: "Highscore")
}
//var gameOver:SKScene = GameOverScene(size: self.size)
//ScoreLabel.removeFromSuperview()
Enemy.removeFromParent()
//Player.removeFromParent()
//self.view?.presentScene(gameOver, transition: transition)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
isTouching = true
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
touchXPosition = location.x
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
isTouching = false
}
func spawnEnemies() {
//Randomizing width of blocks
var blockWidth = Int(arc4random_uniform(UInt32(size.width / 3)) + UInt32(size.width / 5))
//Min and Max position of blocks
var minPosition : UInt32 = UInt32(blockWidth / 2)
var maxPosition : UInt32 = UInt32(size.width - CGFloat(blockWidth / 2))
//Randomizing Block Position
var blockXPosition = arc4random_uniform(maxPosition - minPosition) + minPosition
//Making Blocks
var Enemy = SKShapeNode(rectOfSize: CGSize(width: blockWidth, height: 5))
Enemy.position = CGPointMake (CGFloat(blockXPosition), CGFloat(size.height+50))
//Coloring Blocks
Enemy.fillColor = SKColor.whiteColor()
//Moving Blocks
let action = SKAction.moveToY(-50, duration: 2.5)
//Removing blocks once off screen
let actionDone = SKAction.removeFromParent()
//Running the above actions
Enemy.runAction(SKAction.sequence([action, actionDone]))
//Physics/Collisions
Enemy.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize (width: blockWidth, height: 1))
Enemy.physicsBody?.categoryBitMask = PhysicsCategory.Enemy
Enemy.physicsBody?.affectedByGravity = false
Enemy.physicsBody?.dynamic = true
//Adding enemy to scene
self.addChild(Enemy)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
var offsetLeft = 0 - (Player.position.x - 25)
Player.position = CGPoint(x: Player.position.x, y: Player.position.y)
PlayerRight.position = CGPoint(x: Player.position.x + size.width, y: Player.position.y)
PlayerLeft.position = CGPoint(x: Player.position.x - size.width, y: Player.position.y)
if isTouching {
if touchXPosition > self.size.width / 2 {
// move character to the right.
Player.position.x += 10
}
if touchXPosition < self.size.width / 2 {
// move character to the left.
Player.position.x -= 10
}
}
if Player.position.x < 0 {
Player.position.x = size.width
}
if Player.position.x > size.width {
Player.position.x = 0
}
}
}
Everything is commented fairly well but if you have any questions about whats what let me know. Any help with this would be greatly appreciated!
static let PlayerRight : UInt32 = 3 //00000000000000000000000000000100
static let PlayerLeft : UInt32 = 4 //00000000000000000000000000001000
static let EnemyRight : UInt32 = 5 //00000000000000000000000000010000
Do you really believe that 3 is binary 100 and that 4 is binary 1000 (and so on)? Because if you do, and if you need that to be true, you are going to be in huge trouble later if you try to use these values as actual bitmasks.

Problems with contact/collision in spritekit

I am developing an app where contact plays a big role. I'm my game the "shoe" rest on the ground. I need to be able to know when the shoe is on the ground so it doesn't multi-jump. I also need to know when the shoe hits a hurdle so the game will end. My problem is that it thinks that the ground is a hurdle along with the actual hurdles.
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var shoeGround = SKSpriteNode()
var hurdleTexture = SKTexture()
var hurdlesMoveAndRemove = SKAction()
var hurdlesStopAndRemove = SKAction()
var jump = false
//collision bitmask
let shoeGroundCategory:UInt32 = 0x1 << 0
let hurdleCategory:UInt32 = 0x1 << 28
let groundSensorCategory: UInt32 = 0x1 << 3
override func didMoveToView(view: SKView) {
//Physics
self.physicsWorld.gravity = CGVectorMake(0.0, -8.0)
self.physicsWorld.contactDelegate = self
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//ground
var groundTexture = SKTexture(imageNamed:"ground")
var sprite = SKSpriteNode(texture: groundTexture)
//scale it
sprite.setScale(2.1)
//position it
sprite.position = CGPointMake(self.size.width / 2, sprite.size.height / 2)
//add it to the scene
self.addChild(sprite)
//ground variable for the node
var ground = SKSpriteNode()
//set the position of the node
ground.position = CGPointMake(0, groundTexture.size().height)
ground.zPosition = 1000
//set the physics body to equal the size of the image.
ground.physicsBody = SKPhysicsBody(rectangleOfSize:CGSizeMake(self.frame.size.width, groundTexture.size().height * 1.85))
//physics bodies
ground.physicsBody?.dynamic = false
ground.physicsBody?.restitution = CGFloat(0.0)
//add the object to the scene
self.addChild(ground)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//ground
var groundSensorTexture = SKTexture(imageNamed:"ground")
var spriteSensor = SKSpriteNode(texture: groundSensorTexture)
//scale it
spriteSensor.setScale(2.1)
//position it
spriteSensor.position = CGPointMake(self.size.width / 2, spriteSensor.size.height / 2)
//add it to the scene
self.addChild(sprite)
//ground variable for the node
var groundSensor = SKSpriteNode()
//set the position of the node
groundSensor.position = CGPointMake(0, groundSensorTexture.size().height)
groundSensor.zPosition = 1000
//set the physics body to equal the size of the image.
groundSensor.physicsBody = SKPhysicsBody(rectangleOfSize:CGSizeMake(self.frame.size.width, groundSensorTexture.size().height * 1.85))
//physics bodies
groundSensor.physicsBody?.dynamic = false
groundSensor.physicsBody?.restitution = CGFloat(0.0)
groundSensor.physicsBody?.categoryBitMask = groundSensorCategory
groundSensor.physicsBody?.contactTestBitMask = shoeGroundCategory | hurdleCategory
//add the object to the scene
self.addChild(ground)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//shoe
var shoeGroundTexture = SKTexture(imageNamed:"default_shoe")
//change texture filtering mode.
shoeGroundTexture.filteringMode = SKTextureFilteringMode.Nearest
//Make the object.
shoeGround = SKSpriteNode(texture: shoeGroundTexture)
//set scale
shoeGround.setScale(0.35)
//position it.
shoeGround.position = CGPointMake(self.frame.size.width * 0.35, ((groundSensorTexture.size().height * 2.0) + (shoeGround.frame.size.height/2)))
shoeGround.zPosition = 100
//give it the collision collider of a circle.
shoeGround.physicsBody = SKPhysicsBody(circleOfRadius: shoeGround.size.height / 2)
shoeGround.physicsBody?.dynamic = true
shoeGround.physicsBody?.allowsRotation = false
shoeGround.physicsBody?.restitution = CGFloat(0.0)
shoeGround.physicsBody?.categoryBitMask = shoeGroundCategory
shoeGround.physicsBody?.contactTestBitMask = groundSensorCategory | hurdleCategory
//add it to the scene
self.addChild(shoeGround)
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Hurdles
//Create the Hurdles.
hurdleTexture = SKTexture(imageNamed:"hurdle")
//Spawn the Hurdles.
let spawn = SKAction.runBlock({() in self.spawnHurdles()})
var time = arc4random() % 3
time += 2
let delay = SKAction.waitForDuration(2.0, withRange: 2.0)
let spawnThenDelay = SKAction.sequence([spawn, delay])
let spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay)
self.runAction(spawnThenDelayForever)
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func didBeginContact(contact: SKPhysicsContact) {
var firstBody, secondBody, thirdBody: SKPhysicsBody
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if ((firstBody.categoryBitMask & shoeGroundCategory) != 0 && (secondBody.categoryBitMask & hurdleCategory != 0)) {
//secondBody.node?.removeFromParent()
println("Hurdle")
}
if ((firstBody.categoryBitMask & shoeGroundCategory != 0) && (secondBody.categoryBitMask & groundSensorCategory != 0)) {
//secondBody.node?.removeFromParent()
jump = true
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func didEndContact(contact: SKPhysicsContact) {
var firstBody, 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 & shoeGroundCategory != 0) &&
(secondBody.categoryBitMask & groundSensorCategory != 0)) {
//secondBody.node?.removeFromParent()
jump = false
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
moveHurdles()
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if jump == true {
shoeGround.physicsBody?.velocity = CGVectorMake(0, 0)
shoeGround.physicsBody?.applyImpulse(CGVectorMake(0, 82))
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func spawnHurdles() {
let hurdle = SKSpriteNode(texture: hurdleTexture)
hurdle.setScale(2.0)
hurdle.position = CGPointMake(0, 175)
hurdle.physicsBody = SKPhysicsBody(rectangleOfSize:hurdle.size)
hurdle.physicsBody?.dynamic = false
hurdle.physicsBody?.categoryBitMask = hurdleCategory
hurdle.physicsBody?.contactTestBitMask = shoeGroundCategory | groundSensorCategory
hurdle.runAction(hurdlesMoveAndRemove)
self.addChild(hurdle)
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//movement of Hurdles.
func moveHurdles() {
let distanceToMove = CGFloat(self.frame.size.width + 10.0 * hurdleTexture.size().width)
let moveHurdles = SKAction.moveByX(-distanceToMove, y: 0, duration: NSTimeInterval(0.00185 * distanceToMove))
let removeHurdles = SKAction.removeFromParent()
hurdlesMoveAndRemove = SKAction.sequence([moveHurdles, removeHurdles])
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func stopHurdles() {
let distanceToMove = CGFloat(self.frame.size.width + 10.0 * hurdleTexture.size().width)
let stopHurdles = SKAction.moveByX(0, y: 0, duration: NSTimeInterval(0.00185 * distanceToMove))
let removeHurdles = SKAction.removeFromParent()
hurdlesStopAndRemove = SKAction.sequence([stopHurdles, removeHurdles])
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
One way to check if your shoe is on the ground is to implement a condition at the Update function.
The condition would be to check the shoe's y coordinate and if it's below a certain threshold depending on your hurdles and ground.
The second method would be to check the sprite's velocity if it's close to zero.

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