2.7 Detect Collisions
In the previous lesson, we noticed that it is possible for the bombs to come into contact with our spaceship. But so far, nothing really happens. In this lesson, we're going to add some logic to detect collisions between the spaceship and bombs and then make the spaceship disappear.
1.Introduction2 lessons, 03:23
2.Code the Game8 lessons, 55:53
3.Conclusion1 lesson, 02:04
2.7 Detect Collisions
All right, so now it's time to start to talk a little bit about collision detection. Now collision detection can be a rather complicated topic. But we're gonna try to boil it down to its absolute basics here. So as far as collisions are concerned within our game, what we wanna be looking at here is taking the two different categories of nodes that we have. We have the ships and we have the bombs. And we wanna set this up so that when one category detects that it has collided with another one, we want to tie into that somehow within the code, within our scene, to then determine what has collided with what, and then go ahead and take some sort of action. And we're gonna make this is as simple as possible and then you can obviously enhance it a little bit more as you go. But for the most part this is how it's going to work. We're gonna begin by creating a couple of different categories. And when it comes to categories within SpriteKit and doing this type of work as far as collision detection, everything is pretty much handled using bit masks and bit shifting. Now don't get too bogged down in some of the granularity of this. It's not that important, but it's important enough to understand the basics here. So we're gonna have two different categories. We're gonna have a shipCategory, which is gonna be equal to 1 and it's gonna be shifted 0. So it's actually going to be the value of 1 and then we're also going to have a bombCategory. And that's going to be 1. And it's gonna be shifted one position. So don't get too bogged down in this. And if you were going to have another one you would shift it two and three and so on and so forth. So depending on the number of different categories of nodes you had. So let's say maybe you had planets in there, that could be another category. Maybe you had maybe clouds that you put out there randomly were another category and a bunch of different things like that. But for the most part we're dealing with two categories here. But before we can start actually dealing with the collisions of things, we have to be able to deal with this concept of contact. And another thing that we're gonna have to do here is in two parts. We're gonna to have to also have our GameScene inherit from SKPhysicsContactDelegate. Which means if there is a collision detected, if there's a contact detected between two or more physics bodies within our physicsWorld, then there is going to be a delegate that can handle these events properly. And we want to make sure that our GameScene can do that. So that's step one. Step two is defining this as a delegate within our physicsWorld to say the physicsWorld.contactDelegate is gonna be equal to self. So that simply means that whenever multiple bodies collide within this physicsWorld, who is going to handle that via a method, via a contact method. We're specifying that our GameScene can do it because it's gonna implement the SKPhysicsContacDelegate. So now that we've done all this kind of setup, how do we get our ship and our bomb to kind of speak all of this language. Well it's actually pretty easy. We're just gonna set a couple of additional properties on our physics bodies for each of those two sprite nodes. So the first thing that we wanna do is we want to assign those categories. So we're gonna say our physicsBody.categoryBitMask is gonna be equal to, in this case this needs to be a UInt32. So I'm gonna say that this is going to be a Uint32. And this is going to be our shipCategory like that. Now that we've defined what category our ship is in, we want to specify what it is we want to test for contact with. So what collisions do we want to know about? Well we want to know when this ship's physicsBody has a contactTestBitMask equal to another UInt32. On this time this is gonna be of the bombCategory so we wanna know when this particular physicsBody comes in contact with a bomb. And then we're gonna set our collisionBitMask to 0. So let's go ahead and save that. So we're gonna do basically the same thing that we just did here for our bomb now. So we're going to say bomb.physicsBody.CategoryBitMask = UInt32 of our bombCategory. Then we wanna know when this collides or comes into contact with once again another UInt32, this time of our shipCategory. And then we're going to set the collisionBitMask = 0. And then we can also use another property here on the physicsBody for this bomb to say that it usesPrecisionCollisionDetection to get a little bit more fine-grained support on knowing when these collisions actually happen. So now that we've got all this set up, we're gonna be notified or there's gonna be events raised when our bomb comes in contact with the ship and when when our ship comes in contact with the bomb. But how do we actually tie into that when it comes to code? Well I'm gonna drop another function in here and then we're gonna talk about it for a second. So we're gonna tie into this didBegin contact function which is going to take in a PhysicsContact. Now this is gonna be a little bit overkill for probably what we need for this but it's important for us to understand what's going on here. So when it comes to a contact, a contact is always made up of multiple physics bodies and typically they're handled sequentially. So this is going to deal, each physics contact is going to deal with two physics bodies. You're gonna get a body A and you're gonna get a body B. So the first thing that we're doing here is we're going to check to see if the body A has a category bit mask that is less than the second one and we're just going to grab each of those in that order. And because we have set these category bit masks up before, we know that the lesser one is going to be a ship and the greater one is going to be a bomb. So we've set those up appropriately here. And then we do a little bit of checking. We check to see if that firstBody, the .categoryBitMask with the logical & operator combined with the shipCategory, if this was a shipCategory. And we logically & it together with the UInt32 shipCategory. If those two things match then we're gonna get a value here that's nonzero. So this would mean that this is a ship. And we're gonna do the same thing for the second body. We're gonna check to see if the second body is a bomb. And if that is true then we simply want to remove the ship from the parent. We're gonna do a little bit more as far as maybe presenting a second game over a replay type screen in the next lesson. But for now we're just gonna remove it from the scene. Now, I say this is a little bit overkill, because we're only handling collisions from two different types of categories. So obviously, if we get a collision, and that happens, then it's probably more than likely gonna be a ship and a bomb. Although it is possible because we are randomly generating the y values, but although we're spacing them out a little bit for the bombs. I guess it could be possible for a bomb to collide with a bomb. But we're really only testing here for bombs and ships, so just to be complete we're gonna do it this way. So let's go ahead and save that. Now we're going to run our game again and everything should start out. We should see our ship and a couple of bombs start to come at it. And this time we're going to try to get hit this time. So if I come down here and it detects a collision then my ship goes away. So as you can see there, we have detected that collision. We noticed that the first physics body was a ship, the second one was a bomb. And because those two things came together that way, then we remove the ship from the parent, from the scene. But now we have a problem. Now this game just continues to go and we definitely don't want that. So the next lesson, we're going to introduce a game over kind of replay scene so we can start the game over.