didBeginContact not being called - ios

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!")
}
}

Related

Node not moving

I'm trying to throw a node around the screen, I've taken the below code but nothing actually happens.
When the scene loads the node spawns in the middle of the screen then drops to the bottom.
The code was taken from elsewhere in the site and granted it was a bit old so I'm assuming I'm missing something?
var sprite: SKSpriteNode!
var touchPoint: CGPoint = CGPoint()
var touching: Bool = false
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
sprite = SKSpriteNode(color: UIColor.red, size: CGSize(width: 50, height: 50))
sprite.physicsBody = SKPhysicsBody(rectangleOf: sprite.size)
sprite.position = CGPoint(x: 50.0, y: 50.0)
self.addChild(sprite)
}
func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
if sprite.frame.contains(location) {
touchPoint = location
touching = true
}
}
}
func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
touchPoint = location
}
}
func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
touching = false
}
func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
touching = false
}
func update(currentTime: TimeInterval) {
if touching {
let dt:CGFloat = 1.0/60.0
let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
sprite.physicsBody!.velocity = velocity
}
}
}

How can I stop moving object when I touch to object?

My game app has randomly moving object. I want to stop that and print some words on the screen when I touch/catch that. But I don't know what can I do this in gamescene.swift page. What should I write in touchesBegan? Here is my code :
import SpriteKit
let BallCategoryName = "ball"
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
physicsWorld.gravity = CGVectorMake(15, 15)
let ball = childNodeWithName(BallCategoryName) as! SKSpriteNode
ball.physicsBody!.applyImpulse(CGVectorMake(10, -10))
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first as! UITouch
}
}
First you need to put the variable ball outside didMoveToView:
class GameScene: SKScene {
let ball = childNodeWithName(BallCategoryName) as! SKSpriteNode
override func didMoveToView(view: SKView) {
[...]
}
}
touchesBegan:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch:AnyObject in touches{
let location = (touch as! UITouch).locationInNode(self)
let nodeTouched = nodeAtPoint(location)
//Detect if the ball is touched
if(nodeTouched == ball){
//Do something
}
}
}

Sprite Kit stop Impulse

I want to increase a CGFloat every time while the Screen is tapped.
The float has a set maximum and minimum value.
I tried to go through this suggestion: StackOverflow
However, this only increases the CGFloat after the touch is made, or the maximum is reached. I want to increase the CGFloat during the touch, meaning the longer you touch the higher the Jump/CGFloat.
The problem probably lies within the impulse, that you cant change it after it was applied. That means, after the 'Player' gets an impulse of 20, and the screen is longer touched, the Float may increase, but the impulse won't.
If you look at my current code, the impulse is set at maximum while the screen is touched, but if released the action should be removed. However, it doesn't work, the impulse does not stop.
I know that you can set the velocity of the body at a value after the press is made, and if the press has ended the velocity back to 0 so it stops it 'jump', but that doesn't look quite smooth as it would be with an impulse.
Has anybody a solution?
struct Constants {
static let minimumJumpForce:CGFloat = 20.0
static let maximumJumpForce:CGFloat = 60.0
}
class GameScene: SKScene, SKPhysicsContactDelegate {
var force: CGFloat = 20.0
func longPressed(longPress: UIGestureRecognizer) {
if (longPress.state == UIGestureRecognizerState.Began) {
println("Began")
self.pressed = true
let HigherJump = SKAction.runBlock({Player.physicsBody?.applyImpulse(CGVectorMake(0, Constants.maximumJumpForce))})
self.runAction(HigherJump , withKey:"HighJump")
}else if (longPress.state == UIGestureRecognizerState.Ended) {
println("Ended")
self.pressed = false
self.removeActionForKey("HighJump")
}
}
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)
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
1.Create ‘Game’ from Xcode template based on SpriteKit
2.Copy paste listed code to GameScene class
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var location = CGPoint()
var floorSize = CGSize()
var floorColor = UIColor()
var player = SKSpriteNode()
override func didMoveToView(view: SKView) {
view.showsFPS = true;
view.showsNodeCount = true;
view.showsDrawCount = true;
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody?.categoryBitMask = 1
self.physicsBody?.contactTestBitMask = 1
self.physicsWorld.gravity = CGVectorMake(0, 0)
self.physicsWorld.contactDelegate = self;
location = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
player = SKSpriteNode(imageNamed:"Spaceship")
player.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: 320, height: 320))
player.physicsBody?.categoryBitMask = 1
player.physicsBody?.collisionBitMask = 1
player.physicsBody?.contactTestBitMask = 1
player.physicsBody?.linearDamping = 0;
player.xScale = 1
player.yScale = 1
player.position = location
self.addChild(player)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.physicsWorld.gravity = CGVectorMake(0, 0)
let direction = Float(1.5708)//Float(player.zRotation) + Float(M_PI_2)
player.physicsBody?.applyForce(CGVector(dx: 150000*CGFloat(cosf(direction)), dy: 150000*CGFloat(sinf(direction))))
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.physicsWorld.gravity = CGVectorMake(0, -7.9)
}
}
3.Run the app
This should give you start point for you 'Jump' game :)
Try changing this:
if(self.pressed){
let HigherJump = SKAction.runBlock({if(self.force < Constants.maximumJumpForce){
self.force += 2.0
}else{
self.force = Constants.maximumJumpForce
}})
self.runAction(HigherJump)
}
to this:
if(self.pressed){
if(self.force < Constants.maximumJumpForce) {
self.force += 2.0
}
else {
self.force = Constants.maximumJumpForce
}
}
Theres no need to use a runBlock SKAction here.

sprite kit : contact not working

I am trying to make one simple game and this problem happen first my paddle can touch the ball but now it cant do that and
this code also should give me message or in simulator but it is not showing any idea?
import SpriteKit
class GameScene: SKScene , SKPhysicsContactDelegate{
var istouchingpaddle = false
let ballcatagery:UInt32 = 0 * 1 << 0
let paddlecategary :UInt32 = 0 * 1 << 1
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let border = SKPhysicsBody(edgeLoopFromRect: self.frame)
border.friction = 0
self.physicsBody = border
self.physicsWorld.gravity = CGVectorMake(0,-9.8)
self.physicsWorld.contactDelegate = self
let ball = childNodeWithName ("ball") as SKSpriteNode
ball.physicsBody?.applyImpulse(CGVectorMake(30, -30))
ball.physicsBody?.allowsRotation = false
ball.physicsBody?.restitution = 1
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.angularDamping = 0
ball.physicsBody!.categoryBitMask = ballcatagery
let paddle = childNodeWithName("paddle") as SKSpriteNode
paddle.physicsBody!.categoryBitMask = paddlecategary
ball.physicsBody?.contactTestBitMask = paddlecategary
}
func didBeginContact(contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == ballcatagery && contact.bodyB.categoryBitMask == paddlecategary{
println("working ")
}
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
var touch = touches.anyObject() as UITouch
var location = touch.locationInNode(self)
if let body = self.physicsWorld.bodyAtPoint(location){
if body.node!.name == "paddle" {
istouchingpaddle = true
}
}
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
if istouchingpaddle{
var touch = touches.anyObject() as UITouch
var location = touch.locationInNode(self)
var prevlocation = touch.previousLocationInNode(self)
var paddle = childNodeWithName("paddle") as SKSpriteNode
var position = paddle.position.x + (location.x - prevlocation.x)
position = max(position,paddle.size.width/2)
position = min(position, size.width - paddle.size.width/2)
paddle.position = CGPoint(x: position, y: paddle.position.y)
}
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
istouchingpaddle = false
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
} }
I can produce good results with your code if I change the way of defining categories. Try setting categories like this :
let ballcatagery: UInt32 = 0x1 << 0 // Not that you have misspelled word "category", which can lead to errors if you expect somewhere a word "category" instead of your actual "categary".
let paddlecategary : UInt32 = 0x1 << 1
I can post you the whole code , but you should be good with this.

Throwing an object with SpriteKit

I have the following code at the moment. Even though the code build is successful, i cannot seem to get it to work. I am trying to make it so when you flick the object, it moves at the velocity of your begin and end touch.
import SpriteKit
class GameScene: SKScene {
var sprite: SKSpriteNode!
var touchPoint: CGPoint = CGPoint()
var touching: Bool = false
override func didMoveToView(view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 50, height: 50))
sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size)
sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
self.addChild(sprite)
}
//for touch: AnyObject in touches {
//let location = touch.locationInNode(self)
//let touchedNode = self.nodeAtPoint(location)
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if sprite.frame.contains(location) {
touchPoint = location
touching = true
}
}
func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
touchPoint = location
}
func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
touching = false
}
func update(currentTime: CFTimeInterval) {
if touching {
let dt:CGFloat = 1.0/60.0
let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
sprite.physicsBody!.velocity = velocity
}
}
}}}
You accidentally placed touchesMoved, touchesEnded and update inside touchesBegan. Besides that your code works. A hint that there were problems was the fact you didn't need to prefix touchesMoved, touchesEnded or update with override.
In the future, I would recommend using breakpoints and print statements to check the methods you expect to execute, are in fact running. Doing that you'd see that your versions of touchesMoved, touchesEnded and update weren't being called.
Anyway, here's it corrected it and now it works perfectly:
import SpriteKit
class GameScene: SKScene {
var sprite: SKSpriteNode!
var touchPoint: CGPoint = CGPoint()
var touching: Bool = false
override func didMoveToView(view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
sprite = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 50, height: 50))
sprite.physicsBody = SKPhysicsBody(rectangleOfSize: sprite.size)
sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
self.addChild(sprite)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if sprite.frame.contains(location) {
touchPoint = location
touching = true
}
}
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
touchPoint = location
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
touching = false
}
override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {
touching = false
}
override func update(currentTime: NSTimeInterval) {
if touching {
let dt:CGFloat = 1.0/60.0
let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
sprite.physicsBody!.velocity = velocity
}
}
}
ABakerSmith's solutions updated for Swift 4:
import SpriteKit
class GameScene: SKScene {
var sprite: SKSpriteNode!
var touchPoint: CGPoint = CGPoint()
var touching: Bool = false
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody.init(edgeLoopFrom: self.frame)
sprite = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
sprite.physicsBody = SKPhysicsBody.init(rectangleOf: sprite.size)
sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
self.addChild(sprite)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first?.location(in: self) {
if sprite.frame.contains(touch) {
touchPoint = touch
touching = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
let location = t.location(in: self)
touchPoint = location
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touching = false
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
touching = false
}
override func update(_ currentTime: TimeInterval) {
if touching {
let dt:CGFloat = 1.0/60.0
let distance = CGVector(dx: touchPoint.x-sprite.position.x, dy: touchPoint.y-sprite.position.y)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
sprite.physicsBody!.velocity = velocity
}
}
}
Solution updated to not have the touch/drag snap to the middle of the sprite. If you're dragging/throwing an object you're going to want that throw to come from where the user touched the object and not snap to the middle of the object. This will make it look a lot smoother
import SpriteKit
class GameScene: SKScene {
var sprite: SKSpriteNode!
var touchPoint: CGPoint = CGPoint()
var touching: Bool = false
var xDif = CGFloat()
var yDif = CGFloat()
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody.init(edgeLoopFrom: self.frame)
sprite = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
sprite.physicsBody = SKPhysicsBody.init(rectangleOf: sprite.size)
sprite.position = CGPoint(x: self.size.width/2.0, y: self.size.height/2.0)
self.addChild(sprite)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first?.location(in: self) {
xDif = sprite.position.x - touch.x
yDif = sprite.position.y - touch.y
if sprite.frame.contains(touch) {
touchPoint = touch
touching = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
let location = t.location(in: self)
touchPoint = location
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touching = false
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
touching = false
}
override func update(_ currentTime: TimeInterval) {
if touching {
let dt:CGFloat = 1.0/60.0
let distance = CGVector(dx: touchPoint.x-sprite.position.x + xDif, dy: touchPoint.y-sprite.position.y + yDif)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
sprite.physicsBody!.velocity = velocity
}
}
}

Resources