How to Detect When Two Objects Touch in Spritekit

How to detect when two objects touch in SpriteKit

Not to be a stickler but you shouldn't start of a question with "I couldn't find anything on the internet" when thats blatantly not true. There is a million tutorials on collision detection around as its one of the basics in SpriteKit.

Now to your question. You did not give your sprites an actual physics body and your physics categories are set up weird. Change your code to this

 struct PhysicsCategory {
static let cat:UInt32 = 0x1 << 0
static let ground:UInt32 = 0x1 << 1
}

class GameScene: SKScene, SKPhysicsContactDelegate {

override func didMoveToView(view: SKView) {
/* Setup your scene here */

physicsWorld.contactDelegate = self

cat.physicsBody = SKPhysicsBody(rectangleOfSize: cat.size) // FORGOT THIS
cat.physicsBody?.categoryBitMask = PhysicsCategory.cat
cat.physicsBody?.contactTestBitMask = PhysicsCategory.ground

ground.physicsBody = SKPhysicsBody(rectangleOfSize: ground.size) // FORGOT THIS
ground.physicsBody?.categoryBitMask = PhysicsCategory.ground
ground.physicsBody?.contactTestBitMask = PhysicsCategory.cat // You dont really need this line as long as you have set it on the other body.
}

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.cat && secondBody.categoryBitMask == PhysicsCategory.ground {
print("contact")
}
}
}

If you dont want your objects to fall you have to turn gravity off, which is on by default.

 cat.physicsBody?.affectedByGravity = false
ground.physicsBody?.affectedByGravity = false

Hope this helps

Detect touch on child node of object in SpriteKit

override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {

let touch = touches.anyObject() as UITouch

let touchLocation = touch.locationInNode(self)

if([yourSprite containsPoint: touchLocation])
{
//sprite contains touch
}
}

Source: http://www.raywenderlich.com/84434/sprite-kit-swift-tutorial-beginners

How to Detect collision in Swift, Sprite kit

  1. Define unique categories, ensure your class is a SKPhysicsContactDelegate and make yourself the physics contact delegate:

//Physics categories

let enemyCategory:    UInt32 = 1 << 1
let bulletCategory: UInt32 = 1 << 2

class GameScene: SKScene, SKPhysicsContactDelegate {
physicsWorld.contactDelegate = self

  1. Assign the categories (usually in didMove(to view:) :

    enemy.physicsBody.catgeoryBitMask = enemyCategory
    bullet.physicsBody.catgeoryBitMask = bulletCategory

(Make sure you've created physics bodies for each node)


  1. Set up collisions:

enemy.physicsBody?.collisionBitMask = 0 // enemy collides with nothing
bullet.physicsBody?.collisionBitMask = 0 // bullet collides with nothing

or even:

for node in [enemy, bullet] {
node.physicsBody?.collisionBitMask = 0 // collides with nothing
}

  1. Set up contacts

    bullet.physicsBody?.collisionBitMask = enemyCategory // bullet contacts enemy

Make sure that at least one of the objects involved in each potential contact has the isDynamic property on its physics body set to true, or no contact will be generated. It is not necessary for both of the objects to be dynamic.

You should now get didBegin called when the bullet and the enemy make contact. You could code didBegin like this:

  func didBegin(_ contact: SKPhysicsContact) {
print("didBeginContact entered for \(String(describing: contact.bodyA.node!.name)) and \(String(describing: contact.bodyB.node!.name))")

let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

switch contactMask {
case bulletCategory | enemyCategory:
print("bullet and enemy have contacted.")
let bulletNode = contact.bodyA.categoryBitMask == bulletCategory ? contact.bodyA.node : contact.bodyB.node
enemyHealth -= 10
bulletNode.removeFromParent
default:
print("Some other contact occurred")
}

}

Detect collision between two objects in Swift

Here are a few items missing from your checklist:

  1. One of the physics bodies must be dynamic
  2. The physics bodies must be moved by a force/impulse or by setting their velocities
  3. The positions of the physics bodies should match their corresponding sprite/shape nodes

For (2), you are moving each bullet by changing its position over time with an SKAction.

For (3), the position of each bullet starts at (0, 0), while the shape is drawn at the top-center of the scene. Since the physics body is centered at the shape node's position, there is a mismatch between the locations of the shape and the physics body; the bullet's physics body never makes contact with the soldier. To resolve this, try

    var bullet = SKShapeNode(rectOfSize: CGSizeMake(10, 40))
bullet.position = CGPointMake(self.size.width/2.0, self.size.height)

Also, the physics body of the soldier is half the radius of its shape.

SpriteKit collisions issue between two objects controlled by screen touch

Based on what I am seeing, you never assign "enemy2" to the name of your enemy, so enumerateChildNodes(withName: "enemy2") { node, _ in
let enemy2 = node as! SKSpriteNode
if enemy2.frame.intersects(
self.spaceship.frame) {
hitEnemies2.append(enemy2)
}
}

should be empty, meaning no node is hit.

How do i detect a touch location in SpriteKit?

When you create a new project and choose Game (SpriteKit game) if you look inside you will see that there is already shown how you handle touches:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */

for touch in touches {
let location = touch.locationInNode(self)

let sprite = SKSpriteNode(imageNamed:"Spaceship")

sprite.xScale = 0.5
sprite.yScale = 0.5
sprite.position = location

let action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)

sprite.runAction(SKAction.repeatActionForever(action))

self.addChild(sprite)
}
}

As you can see, there is a variable location which represent the touch location in the scene's coordinate system.

how to detect touch on node

every time you touch the screen you are cycling through all balls to see if you're touching one of them. if you have 50 balls on the screen it goes through them all to see if you are touching 1. that's not an efficient way of figuring out if you are touching 1.

There are many ways you can do this but what I would do is handle the touches inside of the Ball class. That way you don't have to figure out if you are touching a ball and which one it might be.

Explanation of protocol (to the best of my ability) this may seem a little much right now, but the faster you learn and understand protocols that better off you will be (IMO).

In this example we will use a protocol to setup a delegate of the
BallNode class. A protocol is a set user defined "rules" that must be
followed by any class that you designate compliant to that protocol.
In my example I state that for a class to be compliant to the
BallNodeDelegate protocol it must contain the didClick func. When you
add the BallNodeDelegate after GameScene you are stating that this
class will be compliant to that protocol. So if in GameScene you did
not have the didClick func it will cause an error. All this is put in
place so that you have an easy way to communicate between your
BallNode instances and your GameScene class (without having to pass
around references to your GameScene to each BallNode). Each BallNode
then has a delegate (GameScene) which you can pass back the
information to.

inside your BallNode class make sure you have isUserInteraction = true

outside of your BallNode class create a protocol that will send the touch info back to the GameScene

protocol BallNodeDelegate: class {
func didClick(ball: BallNode)
}

create a delegate variable in your BallNode class

weak var delegate: BallNodeDelegate!

move the touches began to you BallNode class

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

self.delegate?.didClick(ball: self)
}

in GameScene add the compliance to the BallNode protocol

class GameScene: SKScene, BallNodeDelegate

in GameScene when you create a Ball make sure you set it's delegate

let ball = BallNode()
ball.delegate = self

in GameScene add the nest. func to handle the clicks

func didClick(ball: BallNode) {
print("clicked ball")
}

How to check if two objects collided Objective C

You’ll first need to set the player’s and the enemy’s physic bodies categoryBitMask property.

If you really mean ‘collide’ i.e. for the objects to bounce off each other, then this should happen automatically as this is controlled by the physics body’s collisionBitMask but initially this is UInt32.Max, so everything collides with everything.

If you actually mean ‘contact’, so that your didBegin code gets called when the objects touch, you’ll need to set up the contactTestBitMask as this is initially 0 i.e. nothing contacts anything.

Edit:

As Maria said - set the delegate and also make sure your class is an SKPhysicsContactDelegate. Your code won’t be notified of any contacts if you don’t. (These steps are only required if you want contact detection - collisions dont need them.

class GameScene: SKScene, SKPhysicsContactDelegate {
physicsWorld.contactDelegate = self

I suspect that you want something to happen when the player and the enemy touch, so I think you really want contact detection, not collisions.



Related Topics



Leave a reply



Submit