Sprite Kit more than 1 time collision - ios

my game is not this but like this:
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var sprite = SKSpriteNode()
override func didMoveToView(view: SKView)
{
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody?.categoryBitMask = 1
self.physicsBody?.contactTestBitMask = 1
self.physicsWorld.gravity = CGVectorMake(0, -10)
self.physicsWorld.contactDelegate = self
}
func didBeginContact(contact: SKPhysicsContact) {
print("contact")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
let spriteTexture = SKTexture(imageNamed: "Spaceship")
sprite = SKSpriteNode(texture: spriteTexture)
sprite.position = CGPoint(x: CGRectGetMidX(self.frame) , y: CGRectGetMidY(self.frame))
sprite.size = CGSizeMake(80, 80)
sprite.physicsBody = SKPhysicsBody(texture: spriteTexture, size: CGSizeMake(80, 80))
sprite.physicsBody?.categoryBitMask = 1
sprite.physicsBody?.collisionBitMask = 1
sprite.physicsBody?.contactTestBitMask = 1
sprite.physicsBody?.linearDamping = 0;
self.addChild(sprite)
}
}
if you paste this code and run you see a lot of "contact" string. I want only 1 contact this:
so i want when contact only 1 time collision
I edited my question can anyone help?

1.Create ‘Base Game’ from Xcode template based on SpriteKit
2.Paste code below to GameScene class
class GameScene: SKScene, SKPhysicsContactDelegate {
var sprite = SKSpriteNode()
override func didMoveToView(view: SKView)
{
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody?.categoryBitMask = 1
self.physicsBody?.collisionBitMask = 1
self.physicsWorld.gravity = CGVectorMake(0, -10)
self.physicsWorld.contactDelegate = self
self.physicsBody?.restitution = 0.0
}
func didEndContact(contact: SKPhysicsContact) {
print("End contact")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?)
{
let spriteTexture = SKTexture(imageNamed: "Spaceship")
sprite = SKSpriteNode(texture: spriteTexture)
sprite.physicsBody = SKPhysicsBody(texture: spriteTexture, size: CGSizeMake(80, 80))
sprite.size = CGSizeMake(80, 80)
sprite.position = CGPoint(x: CGRectGetMidX(self.frame) , y: CGRectGetMidY(self.frame))
sprite.physicsBody?.categoryBitMask = 1
sprite.physicsBody?.collisionBitMask = 1
sprite.physicsBody?.contactTestBitMask = 1
sprite.physicsBody?.fieldBitMask = 1
sprite.physicsBody?.restitution = 0
self.addChild(sprite)
}
}
IMPORTANT NOTE Try to use didEndContact delegate method instead of didBeginContact. In this case you'll get only one invoke while didBeginContact invokes several times.

Related

Moving the player freely all over the screen

I'm making a game where the ball(the player) is suppose to avoid other balls passing by the screen. Basically I want the ball always to follow the location of the touch. So wherever I'm moving my finger on the screen, the ball follows.
This is the player Class:
import SpriteKit
struct ColliderType {
static let Player: UInt32 = 1
static let Blue: UInt32 = 2
static let Green: UInt32 = 3
static let Yellow: UInt32 = 4
static let Red: UInt32 = 5
}
class Player: SKSpriteNode {
func initialize() {
self.name = "Player"
self.zPosition = 1
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.physicsBody = SKPhysicsBody(circleOfRadius: self.size.height /
2)
self.physicsBody?.affectedByGravity = false
self.physicsBody?.categoryBitMask = ColliderType.Player
self.physicsBody?.collisionBitMask = ColliderType.Blue |
ColliderType.Green | ColliderType.Red | ColliderType.Yellow
self.physicsBody?.contactTestBitMask = ColliderType.Blue |
ColliderType.Green | ColliderType.Red | ColliderType.Yellow
}
}
This is the GameplayScene:
import SpriteKit
class GameplayScene: SKScene, SKPhysicsContactDelegate {
var player = Player()
var ball = SKSpriteNode()
var scoreLabel = SKLabelNode()
var score = 0
var counter = Timer()
override func didMove(to view: SKView) {
initialize()
}
override func update(_ currentTime: TimeInterval) {
}
override func touchesBegan(_ touches: Set<UITouch>, with event:
UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if atPoint(location).name == "Retry" {
self.removeAllActions()
self.removeAllChildren()
initialize()
}
if atPoint(location).name == "Quit" {
let mainmenu = MainMenuScene(fileNamed: "MainMenuScene")
mainmenu!.scaleMode = .aspectFill
self.view?.presentScene(mainmenu!, transition:
SKTransition.fade(withDuration: TimeInterval(1)))
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event:
UIEvent?) {
}
override func touchesMoved(_ touches: Set<UITouch>, with event:
UIEvent?) {
}
func didBegin(_ contact: SKPhysicsContact) {
var firstBody = SKPhysicsBody()
var secondBody = SKPhysicsBody()
if contact.bodyA.node?.name == "Player" {
firstBody = contact.bodyA
secondBody = contact.bodyB
} else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if firstBody.node?.name == "Player" && secondBody.node?.name ==
"Red" {
playerDied()
firstBody.node?.removeFromParent()
}
if firstBody.node?.name == "Player" && secondBody.node?.name ==
"Blue" {
playerDied()
firstBody.node?.removeFromParent()
}
if firstBody.node?.name == "Player" && secondBody.node?.name ==
"Green" {
playerDied()
firstBody.node?.removeFromParent()
}
if firstBody.node?.name == "Player" && secondBody.node?.name ==
"Yellow" {
playerDied()
firstBody.node?.removeFromParent()
}
}
func initialize() {
score = 0
physicsWorld.contactDelegate = self
createPlayer()
createBackground()
spawnRedBall()
spawnBlueBall()
spawnGreenBall()
spawnYellowBall()
createLabel()
counter = Timer.scheduledTimer(timeInterval: TimeInterval(0.7),
target: self, selector: "incrementScore", userInfo: nil, repeats: true)
}
func createPlayer() {
player = Player(imageNamed: "Player")
player.initialize()
player.position = CGPoint(x: 0, y: 0)
self.addChild(player)
}
func createBackground() {
let bg = SKSpriteNode(imageNamed: "BG")
bg.name = "BG"
bg.anchorPoint = CGPoint(x: 0.5, y: 0.5)
bg.position = CGPoint(x: 0, y: 0)
self.addChild(bg)
}
func createRedBall() {
let ball = SKSpriteNode(imageNamed: "Red")
ball.name = "Red"
ball.anchorPoint = CGPoint(x: 0.5, y: 0.5)
ball.zPosition = 1
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height /
2)
ball.physicsBody?.categoryBitMask = ColliderType.Red
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.isDynamic = false
ball.position.y = self.size.height + 100
ball.position.x = CGFloat.randomBetweenNumbers(firstNum: -345,
secondNum: 345)
self.addChild(ball)
let destination = self.frame.height * 2
let move = SKAction.moveTo(y: -destination, duration:
TimeInterval(10))
let remove = SKAction.removeFromParent()
ball.run(SKAction.sequence([move, remove]), withKey: "MoveRed")
}
func spawnRedBall() {
let spawn = SKAction.run({ () -> Void in
self.createRedBall()
})
let delay = SKAction.wait(forDuration: TimeInterval(0.5))
let sequence = SKAction.sequence([spawn, delay])
self.run(SKAction.repeatForever(sequence), withKey: "SpawnRed")
}
func createBlueBall() {
let ball = SKSpriteNode(imageNamed: "Blue")
ball.name = "Blue"
ball.anchorPoint = CGPoint(x: 0.5, y: 0.5)
ball.zPosition = 1
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height /
2)
ball.physicsBody?.categoryBitMask = ColliderType.Blue
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.isDynamic = false
ball.position.y = -self.size.height + 100
ball.position.x = CGFloat.randomBetweenNumbers(firstNum: -345,
secondNum: 345)
self.addChild(ball)
let destination = self.frame.height * 2
let move = SKAction.moveTo(y: destination, duration:
TimeInterval(10))
let remove = SKAction.removeFromParent()
ball.run(SKAction.sequence([move, remove]), withKey: "MoveBlue")
}
func spawnBlueBall() {
let spawn = SKAction.run({ () -> Void in
self.createBlueBall()
})
let delay = SKAction.wait(forDuration: TimeInterval(0.5))
let sequence = SKAction.sequence([spawn, delay])
self.run(SKAction.repeatForever(sequence), withKey: "SpawnBlue")
}
func createGreenBall() {
let ball = SKSpriteNode(imageNamed: "Green")
ball.name = "Green"
ball.anchorPoint = CGPoint(x: 0.5, y: 0.5)
ball.zPosition = 1
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height /
2)
ball.physicsBody?.categoryBitMask = ColliderType.Green
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.isDynamic = false
ball.position.x = -self.size.width + 200
ball.position.y = CGFloat.randomBetweenNumbers(firstNum: -637,
secondNum: 637)
self.addChild(ball)
let destination = self.frame.height * 2
let move = SKAction.moveTo(x: destination, duration:
TimeInterval(10))
let remove = SKAction.removeFromParent()
ball.run(SKAction.sequence([move, remove]), withKey: "MoveGreen")
}
func spawnGreenBall() {
let spawn = SKAction.run({ () -> Void in
self.createGreenBall()
})
let delay = SKAction.wait(forDuration: TimeInterval(0.5))
let sequence = SKAction.sequence([spawn, delay])
self.run(SKAction.repeatForever(sequence), withKey: "SpawnGreen")
}
func createYellowBall() {
let ball = SKSpriteNode(imageNamed: "Yellow")
ball.name = "Yellow"
ball.anchorPoint = CGPoint(x: 0.5, y: 0.5)
ball.zPosition = 1
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.height /
2)
ball.physicsBody?.categoryBitMask = ColliderType.Green
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.isDynamic = false
ball.position.x = self.size.width + 200
ball.position.y = CGFloat.randomBetweenNumbers(firstNum: -637,
secondNum: 637)
self.addChild(ball)
let destination = self.frame.height * 2
let move = SKAction.moveTo(x: -destination, duration:
TimeInterval(10))
let remove = SKAction.removeFromParent()
ball.run(SKAction.sequence([move, remove]), withKey: "MoveYellow")
}
func spawnYellowBall() {
let spawn = SKAction.run({ () -> Void in
self.createYellowBall()
})
let delay = SKAction.wait(forDuration: TimeInterval(0.5))
let sequence = SKAction.sequence([spawn, delay])
self.run(SKAction.repeatForever(sequence), withKey: "SpawnYellow")
}
func createLabel() {
scoreLabel.zPosition = 3
scoreLabel.position = CGPoint(x: -320, y: 600)
scoreLabel.fontName = "Verdana"
scoreLabel.fontSize = 70
scoreLabel.text = "0"
self.addChild(scoreLabel)
}
func incrementScore() {
score += 1
scoreLabel.text = String(score)
}
func playerDied() {
counter.invalidate()
let highscore = GameManager.instance.getHighscore()
if highscore < score {
GameManager.instance.setHighscore(highscore: score)
}
let retry = SKSpriteNode(imageNamed: "Retry")
let quit = SKSpriteNode(imageNamed: "Quit")
retry.name = "Retry"
retry.anchorPoint = CGPoint(x: 0.5, y: 0.5)
retry.position = CGPoint(x: -150, y: -50)
retry.zPosition = 2
retry.setScale(0)
quit.name = "Quit"
quit.anchorPoint = CGPoint(x: 0.5, y: 0.5)
quit.position = CGPoint(x: 150, y: -50)
quit.zPosition = 2
quit.setScale(0)
let scaleUp = SKAction.scale(to: 1, duration: TimeInterval(0.5))
retry.run(scaleUp)
quit.run(scaleUp)
self.addChild(retry)
self.addChild(quit)
}
}
Add the following property:
var ballIsTouched = false
and then implement the touch methods:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let location = touches.first.location(in: self) {
if ball.containsPoint(location) {
ballIsTouched = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if (ballIsTouched == true) {
ball.position = (touches.first?.location(in: self))!
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
ballIsTouched = false
}
I think it is more natural when implementing a dragging, to drag a sprite from the touch location rather than from the center of the sprite. To do this, you should calculate the offset and add it the new sprite's position, like this:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let current = touch.location(in: self)
let previous = touch.previousLocation(in: self)
if ball.contains(current) {
let offset = CGPoint(x: current.x - previous.x , y: current.y - previous.y)
ball.position = CGPoint(x: ball.position.x + offset.x , y: ball.position.y + offset.y)
}
}
}
Here is a sample project to show how to implement a draggable sprite.:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ballIsTouched = false
var ball = SKSpriteNode()
override func didMove(to view: SKView) {
ball = SKSpriteNode(color: .blue, size: CGSize(width:100, height:100))
ball.position = CGPoint(x: 0, y: 0)
addChild(ball)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
if ball.contains(touch.location(in: self)) {
ballIsTouched = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if (ballIsTouched == true) {
ball.position = (touches.first?.location(in: self))!
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
ballIsTouched = false
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
This only allows for the single specified sprite to be dragged. Here is an example with multiple sprites that can be dragged:
import SpriteKit
import GameplayKit
extension SKColor {
static func random() -> SKColor {
let colours = [SKColor.lightGray, SKColor.white, SKColor.gray, SKColor.red, SKColor.green, SKColor.blue, SKColor.cyan, SKColor.yellow, SKColor.magenta, SKColor.orange, SKColor.purple, SKColor.brown]
return colours[Int(arc4random_uniform(UInt32(colours.count)))]
}
}
class GameScene: SKScene {
var touchedSprite : SKSpriteNode?
override func didMove(to view: SKView) {
for i in -1...1 {
let ball = SKSpriteNode(color: SKColor.random(), size: CGSize(width:100, height:100))
ball.position = CGPoint(x: 0, y: i * 200)
addChild(ball)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
touchedSprite = self.atPoint(touch.location(in: self)) as? SKSpriteNode
touchedSprite?.setScale(1.25)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if (touchedSprite != nil) {
touchedSprite?.position = (touches.first?.location(in: self))!
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touchedSprite?.setScale(1)
touchedSprite = nil
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
You could also implement a draggable protocol or something to limit which sprites can be dragged.

Sprites not contacting properly

There's a ball and a paddle, the ball should be on the paddle and touching it but the ball never touches the paddle and stops before reaching the paddle, can anyone help me out?
import SpriteKit
class GameScene: SKScene ,SKPhysicsContactDelegate {
let ballCategory:UInt32 = 0x1 << 0
let bottomCategory:UInt32 = 0x1 << 1
let paddleCategory:UInt32 = 0x1 << 2
override init(size: CGSize){
super.init(size: size)
physicsWorld.contactDelegate = self
let ball = SKSpriteNode(imageNamed: "ball")
ball.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
addChild(ball)
ball.physicsBody = SKPhysicsBody(circleOfRadius: self.frame.size.width / 2)
ball.physicsBody?.dynamic = true
ball.physicsBody?.allowsRotation = false
ball.physicsBody?.friction = 0
// ball.physicsBody?.applyImpulse(CGVectorMake(2,-2))
ball.physicsBody?.categoryBitMask = ballCategory
ball.physicsBody?.contactTestBitMask = paddleCategory
ball.physicsBody?.collisionBitMask = paddleCategory
ball.physicsBody?.affectedByGravity = true
let paddle = SKSpriteNode(imageNamed: "paddle")
paddle.position = CGPointMake(CGRectGetMidX(self.frame), paddle.frame.size.height * 2)
addChild(paddle)
paddle.physicsBody = SKPhysicsBody(rectangleOfSize: paddle.frame.size)
paddle.physicsBody?.affectedByGravity = false
paddle.physicsBody?.dynamic = false
paddle.physicsBody?.categoryBitMask = paddleCategory
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
}
func didBeginContact(contact: SKPhysicsContact) {
print("touched")
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
The best way to determine where your nodes are making contact is to turn on Physics.
Open GameViewController.swift and enter the following code:
skView.showsPhysics = true
You are experiencing this issue because of this line:
ball.physicsBody = SKPhysicsBody(circleOfRadius: self.frame.size.width / 2)
self is a scene here.
You need this:
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.frame.size.width / 2)
Turn on physics visual representation in your GameViewController like this:
skView.showsPhysics = true
and you will see what is going on.

Collision between two objects

I have created a simple project but I have a problem in the collisions.
It's simple (ball moving and vertical line) but didn't figure out how to stop the ball if it is touched the line.
import SpriteKit
class GameScene: SKScene,SKPhysicsContactDelegate {
var rPipe = SKSpriteNode() // Left Pipe
var ball1 = SKSpriteNode() // Ball
enum ColliderType:UInt32 {
case Ball1 = 1
case Pipe = 2
}
override func didMoveToView(view: SKView) {
self.physicsWorld.contactDelegate = self
// Pipe
let rPipeTexture = SKTexture(imageNamed: "pipe_r.png")
rPipe = SKSpriteNode(texture: rPipeTexture)
rPipe.position = CGPoint(x: CGRectGetMaxX(self.frame)-50, y: CGRectGetMidY(self.frame)-30)
rPipe.physicsBody = SKPhysicsBody(rectangleOfSize: rPipeTexture.size())
rPipe.physicsBody?.dynamic = false
rPipe.physicsBody?.categoryBitMask = ColliderType.Pipe.rawValue
rPipe.physicsBody?.contactTestBitMask = ColliderType.Pipe.rawValue
rPipe.physicsBody?.collisionBitMask = ColliderType.Pipe.rawValue
self.addChild(rPipe)
// Ball
let ballTexture = SKTexture(imageNamed: "gBall.png")
ball1 = SKSpriteNode(texture: ballTexture)
ball1.position = CGPoint(x: CGRectGetMinX(self.frame)+675, y: CGRectGetMaxY(self.frame)-220)
ball1.physicsBody = SKPhysicsBody(circleOfRadius: ballTexture.size().height/2)
ball1.physicsBody?.dynamic = false
ball1.physicsBody?.categoryBitMask = ColliderType.Ball1.rawValue
ball1.physicsBody?.contactTestBitMask = ColliderType.Pipe.rawValue
ball1.physicsBody?.collisionBitMask = ColliderType.Pipe.rawValue
self.addChild(ball1)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
if ball1.containsPoint(location) {
ball1.position.x = location.x
}
}
}
func didBeginContact(contact: SKPhysicsContact) {
print("Contact")
}
One of your collided objects's dynamic property should be set to true. Otherwise the collision will be ignored. After setting dynamic, you also need to set affectedByGravity to false because the ball should not be affected by the gravity.
ball1.physicsBody?.dynamic = true
ball1.physicsBody?.affectedByGravity = false

How do I make a simple character controller in SpriteKit?

I'm making a game in sprite kit and in order to move my character I am applying an impulse but that is a problem because that moves him every 50 pixels or so. My question is, could someone please show me how to make a simple character controller so my character can move continuously until the user lets go from holding down the screen?
My GameScene.swift file:
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let character = SKSpriteNode(texture: SKTexture(imageNamed: "character"))
var move = false
override func didMoveToView(view: SKView) {
/* Setup your scene here */
//world
self.physicsWorld.contactDelegate = self
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
//character
character.position = CGPointMake(self.frame.size.width * 0.6, self.frame.size.height * 0.6)
character.setScale(0.2)
character.physicsBody = SKPhysicsBody(rectangleOfSize: character.size)
character.physicsBody?.dynamic = true
character.physicsBody?.allowsRotation = false
self.addChild(character)
character.physicsBody?.affectedByGravity = true
//platform 1
var platform = SKSpriteNode(texture: SKTexture(imageNamed: "platform"))
platform.position = CGPointMake(self.frame.size.width * 0.6, CGRectGetMidY(self.frame))
platform.physicsBody = SKPhysicsBody(rectangleOfSize: platform.size)
platform.physicsBody?.dynamic = false
platform.setScale(0.25)
platform.physicsBody?.friction = 1
platform.physicsBody?.restitution = 0
platform.physicsBody?.linearDamping = 0
self.addChild(platform)
//platform 2
var platformTexture2 = SKTexture(imageNamed: "platform")
var platform2 = SKSpriteNode(texture: platformTexture2)
platform2.position = CGPointMake(self.frame.size.width * 0.4, self.frame.size.height * 0.3)
platform2.physicsBody = SKPhysicsBody(rectangleOfSize: platform2.size)
platform2.physicsBody?.dynamic = false
platform2.setScale(0.25)
platform2.physicsBody?.friction = 1
platform2.physicsBody?.restitution = 0
platform2.physicsBody?.linearDamping = 0
self.addChild(platform2)
//platform main
var platformTexture3 = SKTexture(imageNamed: "platform")
var platform3 = SKSpriteNode(texture: platformTexture2)
platform3.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame) + platform3.size.height / 3)
platform3.physicsBody = SKPhysicsBody(rectangleOfSize: platform3.size)
platform3.physicsBody?.dynamic = false
platform3.setScale(1)
platform3.size.width = platform3.size.width * CGFloat(2.0)
platform3.physicsBody?.friction = 1
platform3.physicsBody?.restitution = 0
platform3.physicsBody?.linearDamping = 0
self.addChild(platform3)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if location.x < CGRectGetMidX(self.frame){
character.physicsBody?.applyImpulse(CGVector(dx: -50, dy: 0))
} else if location.x > CGRectGetMidX(self.frame){
character.physicsBody?.applyImpulse(CGVector(dx: 50, dy: 0))
}
}
func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
character.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
}
func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
};
}
One way to accomplish this is to maintain a variable to keep track of the state of the touch events (left, right, or none). Here are the basic steps:
In touchesBegan, set touch state variable to left or right
In update, apply impulse continuously while user is touching the screen
In touchesEnded, reset the touch state variable
Here's an example of how to implement this...
Above GameScene class definition, add the following
enum TouchState {
case Left
case Right
case None
}
In GameScene, add the following variable
var touchLocation:TouchState = .None
In GameScene, add or replace the following methods
override func update(currentTime: CFTimeInterval) {
// Apply impulse to physics body while users is touching the screen
switch (touchState) {
case .Left:
character.physicsBody?.applyImpulse(CGVector(dx: -1, dy: 0))
case .Right:
character.physicsBody?.applyImpulse(CGVector(dx: 1, dy: 0))
case .None:
break
}
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch:AnyObject in touches {
let location = touch.locationInNode(self)
if location.x < CGRectGetMidX(self.frame) {
touchState = .Left
} else if location.x > CGRectGetMidX(self.frame) {
touchState = .Right
}
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
// Update touch status
touchState = .None
}
Here's the GameScene.swift...
import SpriteKit
enum TouchLocation {
case Left
case Right
case None
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var character = SKSpriteNode(imageNamed: "character")
var touchLocation:TouchLocation = .None
override func didMoveToView(view: SKView) {
/* Setup your scene here */
scaleMode = .ResizeFill
//character
character.position = CGPointMake(view.frame.size.width * 0.5, view.frame.size.height * 0.5)
character.setScale(0.1)
character.physicsBody = SKPhysicsBody(rectangleOfSize: character.size)
character.physicsBody?.dynamic = true
character.physicsBody?.allowsRotation = false
self.addChild(character)
character.physicsBody?.affectedByGravity = true
//platform 1
var platform = SKSpriteNode(texture: SKTexture(imageNamed: "platform"))
platform.position = CGPointMake(view.frame.size.width * 0.6, CGRectGetMidY(view.frame))
platform.physicsBody = SKPhysicsBody(rectangleOfSize: platform.size)
platform.physicsBody?.dynamic = false
platform.setScale(0.25)
platform.physicsBody?.friction = 1
platform.physicsBody?.restitution = 0
platform.physicsBody?.linearDamping = 0
self.addChild(platform)
//platform 2
var platformTexture2 = SKTexture(imageNamed: "platform")
var platform2 = SKSpriteNode(texture: platformTexture2)
platform2.position = CGPointMake(view.frame.size.width * 0.4, view.frame.size.height * 0.3)
platform2.physicsBody = SKPhysicsBody(rectangleOfSize: platform2.size)
platform2.physicsBody?.dynamic = false
platform2.setScale(0.25)
platform2.physicsBody?.friction = 1
platform2.physicsBody?.restitution = 0
platform2.physicsBody?.linearDamping = 0
self.addChild(platform2)
//platform main
var platformTexture3 = SKTexture(imageNamed: "platform")
var platform3 = SKSpriteNode(texture: platformTexture2)
platform3.position = CGPointMake(CGRectGetMidX(view.frame), CGRectGetMinY(view.frame) + platform3.size.height / 3)
platform3.physicsBody = SKPhysicsBody(rectangleOfSize: platform3.size)
platform3.physicsBody?.dynamic = false
platform3.setScale(1)
platform3.size.width = platform3.size.width * CGFloat(2.0)
platform3.physicsBody?.friction = 1
platform3.physicsBody?.restitution = 0
platform3.physicsBody?.linearDamping = 0
self.addChild(platform3)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
switch (touchLocation) {
case .Left:
character.physicsBody?.applyImpulse(CGVector(dx: -1, dy: 0))
case .Right:
character.physicsBody?.applyImpulse(CGVector(dx: 1, dy: 0))
case .None:
break
}
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch:AnyObject in touches {
let location = touch.locationInNode(self)
if location.x < CGRectGetMidX(self.frame) {
touchLocation = .Left
} else if location.x > CGRectGetMidX(self.frame) {
touchLocation = .Right
}
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
touchLocation = .None
}
}

didBeginContact not being called

I'm trying to create a program that prints out something whoever my spaceship goes over a circle, but it's not printing anything when I put the spaceship over the circle. Did I build my didBeginContact method wrong? Did I set up the BitMasks wrong?
import SpriteKit
class GameScene: SKScene {
var spaceship: SKNode!
var circ: SKNode!
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
spaceship = SKSpriteNode(imageNamed: "Spaceship")
spaceship.setScale(0.4)
spaceship.position.x = self.frame.width/2
spaceship.position.y = spaceship.frame.height/2
spaceship.physicsBody = SKPhysicsBody(circleOfRadius: spaceship.frame.height/2)
spaceship.physicsBody?.categoryBitMask = 1
spaceship.physicsBody?.contactTestBitMask = 2
spaceship.physicsBody?.collisionBitMask = 0
spaceship.physicsBody?.dynamic = true
circ = SKShapeNode(circleOfRadius: 50)
circ.position.y = self.frame.height/2
circ.position.x = self.frame.width/2
circ.physicsBody = SKPhysicsBody(circleOfRadius: 50)
circ.physicsBody?.categoryBitMask = 2
circ.physicsBody?.contactTestBitMask = 1
circ.physicsBody?.collisionBitMask = 0
circ.physicsBody?.dynamic = true
self.addChild(circ)
self.addChild(spaceship)
}
func didBeginContact(contact: SKPhysicsContact){
println("colliding!")
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
spaceship.position = location
}
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
spaceship.position = location
}
}
}
You need to declare yourself as the contact delegate of your physics world:
// add conformance to SKPhysicsContactDelegate:
class GameScene: SKScene, SKPhysicsContactDelegate {
// ...
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
// set as delegate:
self.physicsWorld.contactDelegate = self
// ..
}
// should be called now
func didBeginContact(contact: SKPhysicsContact){
println("colliding!")
}
}

Resources