COLTON OGDEN: So with
mario8, we got our hands
dirty with a little bit of collision
detection-- some very easy collusion
detection, just checking
above Mario's head such
that now he can jump, and hit
blocks, and change their appearance.
In this update, we are going to actually
make certain objects in our scene
collidable, which otherwise were not.
For example, the column
there, as you can see,
Mario is actually in the walk animation.
I say Mario lightly.
It's not really Mario.
But Mario is walking towards the
right and colliding with the column.
So we're going to make
the column collidable.
We're going to make the
tiles collidable below Mario.
So basically, we have a whitelist now
of titles that we can collide with.
And in addition, we need to not only
check what's above Mario, to the left
and to the right of the
corners, but also, we
need to look for what's below Mario.
So if they're walking and
moving left and right,
we will always want
to be checking what's
below them so that we can
determine whether they should fall,
or also when they're jumping.
Same thing with the left and the right.
So if we're jumping and we
hit a pillar or the like,
we should check to make sure
that we are not bumping into it.
So for example, we can
fall down into the walls
and not sort of move back and forth
and do some weird stuff that way.
So that's really it for
the preface to mario9.
Let's get into the actual code here.
So we're going to have
a lot of the same stuff
that we saw in the last
section more or less.
We added a few functions here.
So the one thing that has remained
is that our update function still
has this bit of code here for when we're
jumping and detecting a block above us.
Additionally, in all of the states, we
have now added some additional code.
So idle doesn't have any
additional collision detection code
because really, we don't need to check
if we're colliding with something
or standing perfectly still.
But walking, for example, does have
a couple of new bits and pieces.
So we have two functions,
checkRightCollision
and checkLeftCollision.
And they do exactly as
their name-- they check
the right side and the
left side of Mario,
assuming that we are
going in that direction.
And we also have to see, when
we're in the walking state,
whether or not there
are two tiles below us.
And you'll look at this
and actually realize
that the code here is the exact
same, more or less, as it was before,
in that we are checking to see
if there's a tile at some value.
Only this time, we're
checking below Mario,
as by adding self.height
to the y value here.
So we're checking to see if
there's a tile at self.x, self.y
plus self.height.
And additionally, we're also using
this function self.map:collides.
So let's take a look at that.
So in Map, we're going to go over
down to the collides function.
So all this really does is
it just has a set of tiles
here, so it's just a table
of the constants of the tiles
that we have determined are solid--
ones that we can collide with.
And what we're doing here is actually
using some interesting syntax
we haven't looked at yet, which is how
to iterate over a collection, a table,
in Lua.
And so what we're doing is we're saying,
for every key-value pair in ipairs--
so ipairs is short for iterate pairs.
It's a way of iterating over all
of the key-value pairs in a table,
but you're also given an index,
as well, if you want that index.
And that's what you get
here as the underscore.
Doesn't really matter for
this particular example.
We're not using the
key in our loop here.
All we're checking to see is if that
value has an ID that is equal to v.
And what we're doing
is we're essentially
going over all of the
collidables, given this tile here.
And if tile.id is equal
to v, which is this value,
then we're going to return true.
And if it's the case that
all of those collidables
do not match what tile is here, then
we're just going to return false,
so we have not actually
collided with anything.
That's the addition to Map that
we've made in this section.
I'm going to go back to Player.
And so what we're doing is we're
just checking if map collides
with the tile at right below our feet
and to the right of our character,
because remember, everything
is relative to the left side.
So we're also checking the tile that's
below the right side and one pixel
down.
Just in case we're between two
tiles, we want to make sure of that.
And just to illustrate
that again, this is
a perfect example where
we have two tiles here
where Mario might be between them.
So we want to check not only
the tile below this corner,
but also the tile below this corner.
And we know that we don't
span more than two tiles
max because our width is only 16 pixels,
which it would be impossible to span
three tiles in that situation.
So I'm going to go back over here.
Now, if we do end up falling and
we're in the walking animation,
the walking state, what we
want to do is set our state
to jumping, which might be
a little bit unintuitive.
But really, just because we
have that falling behavior
and gravity is going to
apply to us, it makes sense
that our state should become jumping.
But we don't have to apply an
initial accelerated gravity
value of negative whatever because
we're not actually jumping.
We're just going straight
to the gravity hitting us
and making us accelerate downwards.
Additionally, when we jump,
when we're in the jumping state,
we want to check to see if
there are any tiles below us.
In this case, we are
checking the tile map,
or we're doing the exact same
collision as we did before.
We're checking self.y plus self.height
and self.y plus self.height
with x plus self.width minus 1.
So we're checking both
corners of the bottom.
And in that case, if we do hit the
ground or some collidable tile--
it could be a mushroom or a
block in this case, as well--
we're going to set our dy
to 0, set our state to idle,
our animation to idle, and also reset
our position, taking into consideration
the tile that's where
our feet are, basically
shifting ourselves up by a height as
evidenced by this minus self.height.
And we do the same thing elsewhere.
For example, if we do
checkRightCollision
and checkLeftCollision, it's sort
of the same idea more or less.
I'm going to scroll down here.
So checkLeftCollision checks
for our left and our right side.
So LeftCollision checks to
see if our dx is less than 0.
If it is, we're essentially checking our
top left corner and bottom left corner,
and the tiles that are there.
You're going to look one pixel
to the left of them, which
is what this is right here.
And if it's a collidable
tile in that direction,
we're going to set our dx to 0, so
we stop moving in that direction,
and then make sure that we
don't clip into the tile
by resetting our position to the tile
to the right of that's exposition, which
will put us right at that
position to the right of the tile
that we just tried to go to the left of.
Same thing for checkRightCollision, but
it is the exact opposite, in which case
we are moving to the right direction.
So if our dx is greater
than 0, we're going
to check the two tiles that are to our
top right and bottom right coordinates.
So for you, that's this side, top
right and bottom right coordinates--
to the tile that's 1 pixel that way.
And we're going to,
again, set our dx to 0
and then make sure that we set our
character's position to the left, which
is minus self.width.
We want to set it to the
width of our character
minus from that tile's position so
that we don't clip into it at all.
And that's essentially
it for this example.
And that takes care of the
top, the sides, and the bottom.
I'm going to just go ahead
and run a little example here.
So if I jump, I should be able
to land on top of the tile
just like that, which is pretty cool.
I can still jump and hit that.
And in addition, let's see
if I can land on this column.
Yep, I landed on the
column, which is great.
And I jumped down here.
And then eventually,
I can finally jump--
if I try-- my speed is a little fast.
Let's try doing it this way.
There we go, jumped
down into the pit below.
So that's it for collision.
That's really the trickiest part.
And it's a lot of numbers,
but if you read through it,
it's actually not terribly complex.
It's very easy to mess this
up live coding, though,
which is why we didn't do it live.
But everything is written here, so
do study this and understand it,
and it'll make, I think, perfect sense
once you get more in tune with it.
So that's it for mario9,
the collision update.
The last bit is a lot
simpler. mario10 is
sort of callback to Pong, where
we looked at adding sound effects.
This time, we're going
to add sound effects,
but we're also going to add music
and we'll fly through that one.
It'll be a breeze.
So looking forward to
seeing you in mario10.
