SPEAKER: All right.
We just took a look at implementing
gravity and the ability for Mario
to jump.
Now, we're going to use that
jumping to actually trigger
some updates with the game world.
So this is the block
update, because so far we've
had the yellow block that's been
visible when we generate levels.
And in Super Mario Brothers,
it's actually frequent
that you'll find blocks that you
can hit as by jumping that will
change the block's appearance.
Either it will change it from
yellow to, say, some darker color,
or it will actually
destroy it altogether.
In this example, we're just going
to take the yellow block that we
have already been using and essentially
just swap it, its ID, specifically,
with another block, a darker brown one
when we hit it to sort of demonstrate
this functionality.
Now, collision detection in Super
Mario Brothers sort of in this context
is a little bit different
than what we've done so far.
We're still using AABB, but in
this case, really, what we're doing
is only checking the top
part of Mario because all
we're doing really when
he jumps is just checking
to see whether his head has intersected
with something, not his entire body.
So what we're essentially
going to do is look
at his top left corner and his
top right corner, see if they are,
you know, at any sort of particular
tile in our world map that's not empty.
And if they are, well,
then if it's the block,
then we'll just transfer
it to the other block's ID.
We'll switch it.
And that's it really for the collision
detection in terms of just the jumping.
Mario9's going to be the
collision update where
we look at the other directions
that we can check for collision,
for example, his feet and his sides.
Currently, we don't have any collision
for his sides or for his feet.
He just walks across
the map because we say
that his height should be at that
point when he's not on the jump state.
But we'll correct that
in the next section.
So for this section, just
because it's a little bit easy
to screw up on this one given how minute
some of these changes are going to be,
we're not going to do it all live.
We're just going to take a look at the
code sort of as it's been pre-baked.
And the first thing that I want to
draw your attention to is Map:tileAt.
So this is a new function
that takes in an x and a y
This is a fairly easy
part of this update here.
But what we essentially want to do
is we want to pass in an x and a y
as pixel coordinates, not as tile
IDs in this sort of grid space
that we've been doing so
far with the tile map.
In this case, we want to pass in
our actual x and y pixel value.
So wherever our Mario avatar
might be walking around,
we want to get the tile
that's at that pixel location.
So what we do is we do our
classic getTile function, which
takes in the x and y at the grid level.
In this case, though,
what we're doing is
we're taking our x
divided by the tile width.
And then we're adding one to that.
And the result of that
is because everything
is one index relative to
getTile, this is essential
because we're dealing with pixel values.
And that'll end up going
back to a zero-based system.
We want to worry about a
one-based system in this case.
Same thing with tileHeight, y
divided by self.tileHeight plus one
will give us the tile that
is at that particular-- you
know, we're essentially dividing our xy
by the map tile size and condensing it
down to what it maps to at the
grid and sort of accounting
for that with the plus one.
Now, in order to make use of this
in the Player Update function,
we're adding a little bit of
code here starting on line 149.
And what we're really
doing is only checking
if our self.dy is less
than zero, meaning
that we're jumping up towards the air.
We can still be in the jumping state and
have a positive dy, but at that point,
we're not going to check
for jumping anymore.
We only want to check
to see whether we've
hit a tile with jumping
when our dy is negative,
so when we're actually
jumping up into the air.
And when we want to do is
use that tileAt function
as part of the map class to check
our own self.x and self.y as well
as our self.x plus our
self.width with minus one.
And the reason that
we do this is, again,
because, interestingly, because
we're dealing with pixel values,
we can be between two
blocks at one time.
And so this is kind of a way
to catch slight bugs where,
for example, if there
are two blocks together,
and we jump, and we're only
checking this left corner,
it'll only trigger this block to change.
But we actually want both of these
to be valid because we're essentially
in between both of them.
It should check the
collision accordingly.
And we'll do the same thing for
the left and the right sides
and the bottom of them as well
when we get to that section.
But that's why we're doing an or here.
We're essentially saying if
the tile at his left corner
or the tile at his right corner are not
empty, and that's what this tilde is.
The tilde equals means not equals.
This is a Lua specific piece of syntax.
If it is not equal to tile
empty, both of these, then
that means we have hit something,
so we can set our self.dy
equal to zero in that case.
We've instantly hit something.
We can start going back down.
Because, remember, we're
still in the jump states,
so gravity is going to kick in and
push us back down to the ground.
We don't want to keep jumping
through the block if we hit it.
We want to actually sort of mimic
as if we'd hit it physically.
And then we do this bit of code
here, which basically just checks
both of those sides, tile map
at self.x and self.y and self.x
plus self.width minus one and self.y
if they're equal to jump block.
And if they are, then
all we're going to do
is set the maps tile at that
particular location to JUMP_BLOCK_HIT,
which we have declared way up
here as a new-- oops, sorry.
That's in the map file here.
If we go to the map file up at the
top or sort of towards the top,
we'll see that JUMP_BLOCK_HIT
is equal to the value of nine.
All we're essentially doing
really is replacing, therefore,
the block as it currently
was, which was the jump block.
And we're just flipping its ID.
And because we're rendering
this every single frame,
it's seeing that now
the number is not five.
It's nine, so we should,
therefore, render the hit block.
So really, we're not doing much
besides just flicking a number,
changing a number, and that's giving
it the appearance of hitting a block
and changing its shape.
So I'm going to go ahead and run
this just so we can test it out.
Go ahead and run that.
So we spawned right below a few blocks.
Conveniently, if I jump right
below this yellow block,
we do indeed see that we hit it.
We stopped our velocity.
And because of gravity, we
ended up going back down.
And additionally, we
flipped the block such
that now it's no longer a yellow block.
It is a brown block.
So that's really it as far as
colliding with up above the character.
In the next section,
the collision update,
we're going to do something
a little more sophisticated.
We're going to look at left and right
collision, as well as floor collision.
And stop really treating the ground as
a sort of a constant hardcoded value
that we need to align Mario to.
And instead, let him fall through
gaps, for example, in the ground.
So we'll see you at Mario9.
