 Now what I've done in the scene is I've added to the floor a new script component collision test And if you go look at that script, it has three methods on collision enter on collision stay and on collision exit And these special methods are called in physics updates when a collision is detected on a collider of that same game object So in this case it's attached to the floor. So when a collision occurs with this floor We're gonna get a so-called collision event that triggers these methods on collision enter is called in just that first update Where there's the collision with that other collider on collision stay is also called at the same time But it's called for every subsequent physics update where those two colliders are still intersecting And then on collision exit is called in that first physics update where the two colliders are no longer touching and Notice all these methods have a parameter of type collision that has information about the collision including which other collider we're colliding with And so what I'm doing here in on collision enter is I'm printing out enter and then the name of the collider and on collision exit I'm printing out exit and then the name of the collider To see all these methods in action on the cube. I removed all the code that was manipulating this velocity and all that So now it's just simply going to be under the force of gravity and fall straight onto the floor But then to see the on collision exit We need it to then stop touching the floor and so I added some code where when I hit space It's gonna have a force apply then jump a little bit. So if I now play the game Fall so the floor we see enter cube and I'm gonna hit space jumps and we see the exit cube and then hits again It's enter cube again Now if I come back in here and Uncommon with this line and save then when on collision stay when a stay event happens We'll see print out stay plus the collider name come back play And we get the enter cube and then stay cube stay cube stay cube stay cube that keeps triggering But it doesn't keep going on forever. We don't get just a definite number of stay cubes As long as these two things are touching because what's happened is our red cube It's rigid body has gone to sleep and once that happens. It's no longer triggering collision events Something would have to happen to wake this object up some other rigid body would have to come along with the collider and hit it Or force would have to be applied to this thing directly Something would have to wake it up before we'd get collision events again So in fact now if I hit space the cube will jump and then it'll do some more events But eventually quite shortly. It'll then go back to sleep once it's that rest Now a collision of course is always happening between two colliders and those colliders are components of game objects and Both of those game objects can have any number of script components And if any one of those script components has on collision methods Each of those on collision methods are called So if say a single game object has multiple script components each with on collision methods Then all of those collision methods get called when there's a collision for that game object And when the game objects of both colliders in a collision have On collision methods in scripts attached to the game objects, then all of those methods get called In those calls this collision parameter the other collider the collider we're colliding with That depends on which object we're attached to so in this case because the script is Attached to the floor when we have a collision with the cube The other collider is the cube if we had a similar script attached to the cube In its on collision events the other object the other collider would be the floor collider And in fact we can see this in action if I simply on the cube attach a Script collision test component and now hit play And we get our collision events. Well We get collisions on both the floor and the cube It's a little confusing because this is the call inside the script attached to the cube It's printing out the name of the other collider the thing we're colliding with and so it says enter floor And vice versa when it says enter cube, that's the floor script saying what we're colliding with on the enter event And then for all subsequent on collision stay events, they're happening in both the cube and the floor So we see printed both stay floor and stay cube And just to make this even more clear we can give the same game object multiple Scripts of the same type. So I'll give the floor here another collision test script. And now when I play And we get the collision notice we get enter cube twice Because for every collision event on the floor, it's actually calling those methods twice One for each of the two instances of the script In addition to collision events, we also have trigger events And these are very similar. They occur when two colliders are intersecting But they occur when one or both of those colliders is marked as a trigger If we look at a collider like the floor here, there's this checkbox is trigger, which is off by default It's false by default but I'm going to make it true And now this floor collider is a trigger collider rather than just a regular collider And so when the cube collides with the floor that causes trigger events not collision events And that has two significances number one It means that these methods are not going to get called when we have a trigger event They only happen when we have a collision event Instead these methods will be called And these methods don't have a collision parameter. They have a collider parameter So they get less information the collision not just tells you what you're colliding with It also tells you what the points of intersection are and a few other things So it's less information that we get in the trigger but usually for triggers we don't care about those details And then the other significance is that rigid bodies don't care about trigger events. They only care about collisions And so when this cube hits the floor The rigid body doesn't hear about it and it doesn't update its velocity accordingly And so the cube will just fall straight through the floor So now here before hitting play understand that on the floor I removed one of the copies of collision tests We just have the one component and I removed the collision test component of the cube So we just have the one collision test component on the floor Come here hit play And our cube just falls straight through the floor And in our log we have trigger enter cube gets called once then stay cube say cube say cube And then down at the end we get an exit because it fell through and stopped the collision So if you want your collider to be hit by rigid bodies like a solid object You can't make it a trigger Rigid bodies will simply just pass through triggers So what triggers are meant to be used for is that we place trigger colliders in our world and then hook up to their methods here and do some sort of logical operation in response till they say like The player entering the trigger. So typically in one of these methods you'll like test Well, what is the other collider? Is it the player's collider? If so, then this other door should open or unlock or something like that Just be clear though that as soon as one or both of the colliders as a trigger, you're not going to get collision events So actually here, let's make the floor. Let's make it a non trigger again and make the cube this time a trigger We should see the same behavior. We're not going to have the box hit the floor. It's going to fall right through So we can do this and in this setup the behavior is the same But it almost never makes sense really to make your colliders with rigid bodies Make them triggers because if you do so, then they're not going to send collision events to their rigid bodies So this would be an odd thing to do Now finally, let's look at using these colliders and rigid bodies in a fairly realistic application Here we have our environment geometry the floors and obstacles. These are all static colliders They don't have rigid bodies and then we have our player object, which is just this cube But it's a rigid body and we've set up logic in the script attached to this cube Such that our input is translated into force on the cube When I push left and right or a and d on the keyboard when I do horizontal input That's translated into force going left and right on the cube and when I hit space That's a jump force. It's an impulse force upwards. So let's see this in action. I hit play Our box falls under gravity, but I can move it left and right by hitting a and d on my keyboard And I can space to jump And as you can see we can't penetrate into these Obstacles. So let's pause and look at the logic First be clear that the cube object itself is where the script is attached And so we come into here into the code and we have a rigid body private field Which is being initialized and start to be the rigid body of the component Again, this is implicitly this dot get component where this is the script component And it knows well if you try and get a component on the script component You're really asking for the component on the game object. It's attached to so that gets us the rigid body Of the same game object assign it to rb and then We in our update Well, we get the input from the so-called virtual axis called horizontal Which by default again is is bound to the keys a and d and left and right on the keyboard And this is going to be a value between negative one and one Where negative means left and positive values mean right And so we're going to take that value and add force to the rigid body to our cube And we do so there's an overload of ad force We didn't mention where instead of passing a vector three you just pass x y z values separately And so this is the x value of the of the force and then zero for y and z And we're multiplying by four here just to amplify the amounts of force In fact, I can make that even bigger because it's kind of slow as it is So this will then effectively apply force every frame And by default again ad force uses the force mode called force Which takes into account both elapsed time and mass So if we came in here and we increased the mass of our rigid body That would effectively diminish how much Acceleration we're applying when we move left and right Anyway, so that's the horizontal movement and then for the jumping code Well, we test whether the user hits the space key in that frame We don't want them to jump Additionally as they hold down the key just when they initially press the key so it's get key down not get key But we don't want to let the player jump when they're not actually touching the ground Well in some games you do some games you want to let them just like double jump or infinitely jump But in our game, assume we don't So the logic for this actually done properly would get quite complicated But we do a simple little hack here Uh, we keep track of this in value touching what starts out at zero It's just a count of how many other colliders our player cube is touching And so every on collision enter event we increment it and every on collision exit We decrement it and so when touching is greater than zero that means our cube is touching something And so we'll allow it to jump that does though mean that we get some kind of not quite correct behavior where like here Right now I can jump even though I'm not on the ground But because I'm touching that collider right there, it's allowing me to jump So we're doing a quick hack. It's not really proper logic, but for our purposes, it's close enough We also have some other problems with the logic as we've currently implemented it We did like the simplest possible thing But like right now it's Well, because we have I increased the force and so now we have enough force to get up the slope But before when I had the lower force value No matter how much you pushed right you couldn't get up the slope Whereas I assume over here this slope is too great. I mean, yeah, we can't go up at all I can have it sit there. In fact, if I let go left It'll slide down the slope So I mean we could overcome that just by increasing the force, but the point is that Actually properly counting for all the possible scenarios the player could end up with and making the controls feel good for all scenarios and and seem responsive That would take a lot more work But as you can see using the built-in physics system, we can get some basic functionality going with very little code The question though is do we want our player controlled character to necessarily be governed by Physical simulation It's perhaps not the case that you even want to use the built-in physics system for your character movement If you go back and look at older side scrollers like classic platformers in the 8 bit and 16 era None of them had physics of this style They didn't really think in terms of forces and mass and velocity Well, they didn't have velocity to take that back But the way they handle collisions is very different and the way they handle player movement is also very different So if you want that classic platforming feel you really wouldn't use the built-in physics system At least for controlling the motion of your character Maybe some things would be physically simulated with the physics system But then the movement of your character itself would be custom logic largely handwritten Because while you can Play around with the physics system and add in special case logic of like how the forces get applied and all that You're kind of in the end. You're still just fighting with the physics system to get exactly the kind of movement you want Which may not necessarily be a realistic feel. You may want like a cartoony physics feel, right? So in those cases, you probably don't want to use the built-in physics system For certain kinds of controls like say for vehicle controls Maybe you do want a physicsy feel a realistic physicsy feel and so maybe in those cases you do use the built-in physics system But particularly for like classic style platformers you probably don't Also one more detail here. I didn't mention You may have noticed like wait this box is I'm like shoving it up against these slopes and everything But it's never rotating no matter what the forces are like you would expect With me shoving up against this slope the the box should start tumbling But what I've done is I've constrained on the rigid body. I've constrained its movements So first off here, you notice that we have the z-axis constrained. We probably don't really need that because Given the forces applied Nothing should move the box in the z Direction at all either positive or negative So that really shouldn't be necessary given the forces we're applying But just to be safe, I've constrained its movement in the z-axis and now no matter what the velocity It'll never move along its z-axis But then also we don't want the box to rotate at all. So I've constrained rotations of x y and z if I disable these Let's see What axis are they rotating around? I have to think we're right rotating around the x-axis. No the z-axis So let me uncheck z and we'll start seeing some strange behavior here in a second. I think wait me Yep, there. Yep. Now we're tilted Maybe that's actually what we want. It's kind of fun, but I don't think we'd see rotations in other axes. I'll Get rid of those Yeah, given the forces and the collisions involved here I don't think we'd ever see collision on the other axes Regardless of whether they're frozen or not, but just to be safe. I'm going to freeze them As I was saying just a moment ago quite often in games We don't necessarily want a realistic physics feel for the player controlled character or other player controlled things and other things in the scene Like for example, perhaps you want your character when there's user input to move You just want them to instantly start going at full speed Rather than accelerate and and so forth and you don't want to apply force or take into mass or anything. You just want to have Directly controlled movements from the logic of the code And so in such cases it generally doesn't really make sense to use a rigid body because you'd just be fighting with the Rigid body physics when you did that So then what you might do in unity is you would just have a game object that is rendered But then you mainly are keeping track of its position and updating its position According to your own collision logic that doesn't use colliders or rigid bodies at all You can do that It would be nice though if we could just use colliders and all their built-in collusion detection logic that we can take advantage of But not have necessarily an associated rigid body The problem with that though is that like say if we gave our player controlled cube here A collider, but no rigid body is that as I mentioned every time you move a static collider collider with no rigid body That triggers an expensive recomputation, which we don't want to pay the cost of So what can we do? We want to have a collider that isn't really simulated under physics, but we can still move it Well, what you do is a little weird you add a rigid body to it, but you mark that rigid body as kinematic So here on this cube, we do have a rigid body, but it's marked as kinematic And a kinematic rigid body is a body with no concept of velocity The properties are still there and you can access them, but generally they're just going to be zero So effectively the velocities are just ignored the directional angular velocities are simply ignored And so these are rigid bodies that when the physics update is performed, they're not automatically moved These are things that only move when you explicitly and directly set in your code their position and rotation The reason we want these things to still be rigid bodies is because they have to have a concept of mass Because we may want these things to still collide with other non kinematic rigid bodies The primary use case here is you have some player controlled character Which is a kinematic rigid body, but then it runs into say like boxes and debris on the ground And those are non kinematic rigid bodies that respond to the collisions The kinematic rigid body for those collisions doesn't actually receive the the collision event and it doesn't respond to them It doesn't update its velocity and its velocity is ignored regardless So the collision doesn't affect the kinematic rigid body itself, but it affects the other rigid body if it's not kinematic So in fact, there's a special rule for collision events If one of the colliders has a rigid body that's kinematic You only get a collision event if the other collider has a rigid body that is non kinematic If the other collider doesn't have a rigid body at all if it's a static collider Or if it's another kinematic there's no collision event And so you can't automatically detect when kinematics hit other kinematics or when kinematics hit statics But again, you still get a collision between a kinematic and a non kinematic And so those non kinematics can respond to the collisions Even though the kinematic itself doesn't automatically respond to those collisions So let me repeat that again to be clear when a collider with a kinematic rigid body hits a collider with a non kinematic rigid body There's a collision event the kinematic doesn't respond to that collision, but the non kinematic does In effect collisions between kinematics and non kinematics affect only the non kinematics So now putting this into action. We have this kinematic rigid body, which is our player controlled cube It does have gravity checked But that doesn't matter actually because now as soon as this kinematic the gravity is just being ignored It's just another force being applied Same with drag drag doesn't affect kinematics all the force stuff is just totally ignored The only thing that moves our kinematic is when in code we explicitly change its position and rotation So now let's go look at the code Which is significantly more complicated because now we're responsible for all the movements of the box And also detecting when it hits the static colliders There's no automatic detection of when this thing is intersecting with a static collider So we have to check for itself and move the box accordingly So first off the part that's the same is we're just getting the rigid body assigned to this field up here And then we have to explicitly keep track of its velocity because the rigid body's velocity Even if we explicitly set it, it'll still just be zero. It'll just be ignored So we need to keep track of velocity for our cube We do so as a vector two rather than a vector three because we we don't care about Velocity in the z direction We're not moving along the z-axis and then we have a field representing the rate of gravity Which this is just to be constant. I could just make this constant. I guess Same deal, which is negative 9.8. That's about earth gravity And then in the update we're getting input from the horizontal axis This value then is used to modify the x of our velocity and we're we're multiplying by 10 Just to amplify it because by default it's in the range of negative one to one So we just want to amplify it to make it more Consequential But we do want to still factor in time. So we multiply by delta time And we want to constrain how fast the player can move horizontally So we have a max horizontal velocity and we clamp velocity x within that range And then next we're manually simulating drag. So in the case where our velocity is greater than x We diminish it by the horizontal drag value, which we just initialized to one But the amount we're diminishing x by should be proportional to the time elapsed so we factor in delta time But then wait, what if we've diminished it too much and now we've reduced the velocity from positive to negative? That's not how drag's supposed to work. It's supposed to stop at zero So we do this final check. Oh wait, are we less than zero then we set it to zero And then we have to handle separately the opposite case of where velocity was negative going leftwards So in that case to get closer to zero we add in horizontal drag But then if we go too far if we added too much now our value went from negative to positive So it really should just be zero. So that's what all this logic is. It's just about drag And then here we check if the user hits space and if we want to allow them to jump Then well, they're just going to set the upward velocity to 10 But we want to make sure that the box is on top of something rather than just in midair And to do so the pause that's the the vector representing the center of the box and extents That's the well, it's actually the half extents. It's the dimensions of the box along x y z The the half the length width and and height And so we're doing a checkbox But we're being sure to do so with a position that's not where the center of the box is Is actually something just a little bit below that so we're effectively checking for collision Not with the box itself, but with a box that's slightly lower than wherever the box currently is Because we want to know here if there's anything just below the box So that's what this check is all about. Hey, is there something just a little bit below the box? And if so, then we're allowed to jump but when we do this check, we don't want to get back true If it overlaps with the box itself The logic of this test is ruined if it collides with the cube itself So we want this test to only return true if we got a collision with something other than the player So we use a layer mask layers in unity every game objects can be added to a layer And what I've done is there are these eight default layers that come stock with any new project But you can define your own layers and I define this layer called player And then I added the cube to that player layer And this layer mask it's it's a bit field mask, which I won't explain them right now if you're not familiar But in short, it's an integer where the individual bits represent a yes no value So it's it's an int value here But in this case we want all the bits to be one except for the bit that represents layer eight or player layer So this gets us back this call here layer mask dot get mask with the name player gets us back A bit mask where only the bit representing the player layer Is one and all the other bits are zero But then we do the bitwise not operation and that flips all the bits So we get a layer effectively where everything but the player layer is enabled And so we pass it into checkbox here and it's doing a test checking for collisions with all layers except the player layer the the one that includes the cube Anyway, so if this test is true, then we're going to jump we'll set the velocity to positive 10 And then we want to factor in gravity, which is just being applied every frame But proportional to the amount of actual lapse time delta time So we factor that into velocity dot y So now we have our movement vector, which is our current velocity With time factored in multiplied by delta time The problem though is that what if where we want to move for that frame? What if there's another collider in the way? What if we're going to hit the floor or a wall? We don't want to move our cube so that it's overlapping the floor or the walls or anything So what we're going to do is use the method sweep test of rigid body Which is analogous to raycast a raycast is an individual ray That tests for collisions along the ray sweep test takes all the colliders to which this rigid body is attached And moves them along a specified vector and tells us if we hit anything So here we're sweeping all of the colliders of a rigid body along this velocity vector Could have been movement vector would have been the same deals just they point in the same direction They just have different magnitudes and then we're saying how far we want to to sweep them We want to sweep them the magnitude of movement And if there's a hit that is then stored in this out hit parameter, which is a raycast hit And the method itself will return true if there was a hit and so if there's a hit That effectively means that if we were to move our cube By this movement we would then be intersecting with other colliders and we don't want that So what we're going to do is we want to move in the same direction But we want to stop before we actually hit anything And it turns out that the raycast hit we get back Tells us exactly what that distance is along that Along that vector And so now what we want the movement to be is we want to take the movement and and clamp it So that it's the same vector pointing in the same direction But its length has been clamped to the hit distance And here actually it shouldn't matter if it's velocity or movement because they're both vectors pointing in the same direction Velocity has greater magnitude, but they're both longer than hit distance which we're clamping to so It really shouldn't matter. In fact, let me do that And in fact, I think I have a bug here. I don't think I should be multiplying by delta time. That doesn't make any sense We've already factored in time for the movement here. So yeah, I'm pretty sure I've made a mistake there. Let's see now. I'm going to save Just for debug purposes, I'm printing out that movement how much we're moving and then Setting the new velocity to zero because well, we've hit something and when we hit something we should stop moving This is not exactly correct because what if we just like hit a wall? Well, we don't want to constrain our movement in all directions. We still want to fall down As you'll see this logic is not exactly what we want But uh, we'll live with it for now Anyway, so having computed what the movement should be We then update the position of the rigid body By movement and rb position is always a vector three So we have to convert from a vector two to a vector three. That's why we have the cast here This conversion simply just takes the vector two and creates a vector three where the z value is zero as you would expect So let's see this in action and I can tell you ahead of time. I know it doesn't work properly We got collision with the ground there. That's good But then now I can't actually move left and right because we didn't account for sliding along surfaces Because what's happening is gravity is being applied every frame and if I hit left to right here Well, now I have a vector of motion that's actually going like diagonally down into the ground Either left or right and that then would collide and in the code We have it set upon collision with any collider set the movement back to zero to nothing So we're not actually moving then and similarly if I jump against here and I hold left as long as I'm holding left Moving into this wall. We're just going to be stuck there. So we've accidentally implemented wall grab But if I let go now, okay now gravity kicks in fall back down But then we also have worse over here on these colliders. This one in particular. Yeah, I always fall into that one and this has to do with imprecisions of floating point What's happening here is that when we land there's a collision you can see it detects the collision. It stops momentarily um And the velocity is set to zero But then because of floating point imprecisions when we actually then move the rigid body We move it to a place where it's actually slightly intersecting with the thing. It's sitting on top of And the sweep test method Doesn't consider it a hit if the starting position of your colliders is already intersecting with something Those collisions don't count as far as the sweep test is concerned So next time around It's not colliding with the thing. It's sitting on top of and so gravity kicks in and applies force And it starts flying under gravity Yeah, so now it's resting on this thing because it just happens that the y value for this collider It's top edge The calculations just work out that When collision is detected and motion stopped it's positioned in the cube. So it's above the collider not intersecting That's just a a happy accident It just happened that the the numbers worked out that time and this thing got positioned sitting on top rather than partly intersected They're actually our cases get based on uh, how fast or velocity design. I think I can get this to fall through No, I did last time Anyway, there are cases where I've jumped from here to here and it ended up positioned in a place where it did fall through Again, these are just imprecisions of the floating pointer with the tick So our logic clearly is insufficient and what can we do about it? Well, that's not something we'll approach here Yeah, same behavior on that that edge. Yeah, so all sorts of bad things are happening because of these collisions um, it's just Now we we really only up there I fell through the floor Okay, so enough of that. So clearly our logic isn't adequate. We're using the right tools sweep tests collision checks That's the starting place but then actually getting this behavior correctly And then accounting for all the possibilities of making sure that if we land on a slope that never one We don't fall through it, but we can also like walk up and down it accounting for friction things like that We have to account for all this manually and it's difficult It's a tricky thing to do But it ultimately is really what you want If you want a more classic video gamey platformer feel in particular And we won't work through all that right now, but it's something I'll come back to We'll we'll go through a full proper solution for actual platformer physics