Learn iOS SpriteKit with Examples, Code Snippets and Video Tutorials

Day 5 – Learn Sprite Kit and Swift – Contacts and Collisions

Day 5 – Learn Sprite Kit and Swift – Contacts and Collisions
October 10, 2014 Justin

Day 5: Today, we look at Contact Listeners and Collision Detection in Swift. Highlights include:

  • Setting the GameScene class to be the contact delegate
  • Create an enum for our physics body types
  • Assigning those types to our character and platform’s physics bodies
  • Testing when instances of those make and end contact with each other
  • We’ll also look at bodies that don’t collide with each other but do trigger the contact function. Meditate on that one.
  • Update: In Xcode 6 the code seen in the video is .toRaw() but in Xcode 6.1 it is .rawValue
Download the Xcode Project (Updated for Swift 1.2)

 


Well today was another pain free one with Swift. Crazy, right? At the beginning of the week I was ready to take a beating with the learning curve of this new language, and its not turning out that way (knock on wood).

I decided we needed to end the week with something that can be a little tricky for new users, which is getting some feedback when collisions occur in the app. Setting up a physics world is very with Sprite Kit, but monitoring the world is the next step. So what we’ll end up with at the end of the day is a GameScene that tells us when a body has initially contacted another body, and when those two bodies have stopped contacting each other. From a gamer developer’s perspective, imagine how often games detect events like this. All the time right?  Don’t limit your thinking to just collision detection though, because knowing when an object has lost the connection with something else can be just as important. Also too, Swift and Sprite Kit can make it so objects pass through each other, but still give us feedback on when those initial contact and ending-contact moments occur.

Before I forget, let me define two concepts in Sprite Kit a little better. And hopefully as I write this article, I’ll remember to use the terms appropriately as well.

  • Collision – Will refer to when two bodies collide, e.g. ram into each other because they can’t occupy the same space. By default, all physics bodies will collide with each other, so we don’t need to specifically say “You, the platform, can collide with you, the character”. If we do nothing, they still collide.
  • Contact – Will refer to when two bodies generate an intersection notification because either they collided OR passed through each other’s space in the world. Both are possible.  By default physics bodies don’t post a notification that they’ve contacted each other, so in our Swift project we will need to define which bodies notify the GameScene that a contact has occurred.

The first thing we need to do is set a categoryBitMask on each physics body we care to check a collision or contact on. Even though our bodies belong to different classes, from a physics body perspective they are just bodies bumping around without a specific type.  So our first snippet comes from the GameScene class, where we setup an enumeration named BodyType.

The members are all of type UInt32 (in our previous enum we used Int). Because these are a smaller range of integers they are faster to work with (at most the value can be from 0 to 65535).  We only need to work with bro and ground in this project, but I put in some other ones so you get the idea of how you should define them.


 

Meanwhile in our Bro class

Our Bro which is just a subclass of SKSpriteNode, needs a bit more to it’s init function (highlighted below). Previously, we gave it a physics body, but I’m going to go a slightly different route this time just for the heck of it. I’ll create the body as a variable, and then apply it to self.physicsBody in the last line. This is simply to show you that an SKPhysicsBody can be a variable, with properties like .dynamic, .affectedByGravity, etc.

But you’re here to learn about collision detection, so lets get to it.  Take this line…

The body variable has it’s .categoryBitMask property set to BodyType.bro.toRaw() . One neat thing we shouldn’t overlook is that our Bro class had no problem determining what BodyType was referring to, even though that enum was written in the GameScene class. Cool right?   And .rawValue is in there to convert the member type of bro to a UInt32 value. Note, in Xcode 6.1 the correct code is .rawValue. In Xcode 6 it was .toRaw(). Yes, Apple already changed this.

Now examine this commented out line (I’ll uncomment it to talk about it)…

I mentioned earlier that by default every physics body was set to collide with everyone else. We can set this value to 0 if we don’t want the body to collide with any thing!  Or we could do this…

…Which would make it so the body would only collide with either ground types or other bro types.

In this example, we don’t need this line, which is why I commented it out, but it’s an essential one to know.

Finally we have this to talk about it….

I mentioned before that by default the contact delegate won’t care to listen for contacts unless we tell it to. So this line is explicitly saying “hey, I want to know when this body contacts the ground”.  If you want to listen for multiple types, separate them with a Bitwise OR Operator, aka, the single pipe. For example…

 


 

Meanwhile in our Object class

We have even less work to do here. The Bro class has already told the contact delegate to check for a contact or intersection between a bro and ground type, so all we need to do here is set the categoryBitMask value (highlighted below)….

 


 

Back in the GameScene class

We need to make the physicsWorld be a contact delegate, and essentially listen out for contacts between physics bodies. So we have two things to add…

If you try to simply write that last line without adding SKPhysicsContactDelegate  to the class definition, you’ll see an error like this…

Type ‘GameScene’ does not conform to protocol ‘SKPhysicsContactDelegate’ 

Simple fix though. Add SKPhysicsContactDelegate after a comma, after SKScene.

Now that the class is a delegate, it carries with it certain responsibilities. At least I would have assumed so. I didn’t get any errors by excluding the following functions:  didBeginContact and didEndContact, but I thought I would. Often with delegation your class needs to do some work or else you see an error. I can’t remember if this was the case with Objective C or not, but I guess we can get away without adding those functions.

But we want them anyway, so let’s add both functions now.

The code in the didBeginContact and didEndContact functions is almost identical except for a slightly different println function, so we really just need to discuss one of them.  As noted above, we are not responsible for calling these functions. The GameScene is listening for contacts now and will call these as needed.

This line…

… will store a comparison of the categoryBitMask value of the first body contacted (bodyA) and the second body contacted (bodyB). You can *kinda* think of this like an addition between the two UInt32 values, but its a little different. Block it from your mind for now.

I should note that when objects contact each other you won’t know for sure who is who, without some testing, but in some cases, we don’t really care. For example, in this next snippet….

…we write a switch statement, that checks the value of the contactMask with cases matching the combined value. What’s actually happening with the bitwise OR operator, I’ll admit is a little above my head. I get it, but I don’t get it. If I understand it right, it ultimately returns a unique number representing the combo of the two. For fun, just look up Bitwise OR Operator in the official Swift Programming Guide.

One way or another, the case is true when those particular two bodies have contacted each other, and we can then execute code based on that happening. Granted all we are doing is either outputting “contact made” or “contact ended”, but the sky’s the limit from here! The video above ends here, but I’ll show you a bit more…


 

Alternatively, there’s plenty more you could do in either function. For example, this would also work…

That’s obviously less concise but it lets you know exactly which body was bodyA and which was bodyB. So you could do some casting at that point and make the node do something during the contact event. And what would that casting look like you ask? Here goes…

 

 

 

Justin Dike is the owner and lead developer at CartoonSmart.com. He's taught hundreds of hours of game development video tutorials, covering everything from coding to art. These days he's working mostly on Swift and Sprite Kit tutorials, which often lead into highly polished iOS / tvOS Starter Kits, which require no programming at all, but are capable of making nearly any type game! Yeah, you read that write. You can also find Justin at the official CartoonSmart Podcast

0 Comments

Leave a reply

Check out our premium Swift and Sprite Kit Tutorial content!

Visit CartoonSmart.com