字幕表 動画を再生する
Hello.
Let's make a simple title based platform game on as his customer like to start these videos by show you what we will be creating today and you'll notice that it's quite graphical today.
But that's the least important part of what will be working up.
Let me introduce to you, Jerry Oh, or Super Jerry.
Oh, he's definitely not in Italian plumber on, even though Jerry oh, obviously does not know how to run properly and floats all over the place, it has many similarities to his Italian counterpart on.
So the engine we're going to be working on today is a tile based and junior Cassie.
We can collect coins and things on.
It's really about how do we handle the collisions between the tiles in A in a sensible way?
And what I'd like to get out of the way right up front is this is not complicated at all.
In fact, we're not going to be looking at any physics or geometry into sections or anything like that.
It really does exploit A few little quirks are floating point numbers on to D it raise.
We'll also be looking at how the camera pans around the level so we could see here is we get towards the level boundaries.
Jerry Oh becomes off center from the screen, but the camera will follow Dario around as he moves around the level, just like we did in the Worms Game will also spend just a little bit of time talking about the dynamics of the character, getting the feel of the character correct.
So when he jumps, he jumps in a controllable, on responsive way.
But he doesn't sort of break all of the rules of physics, and this will encourage the player to develop a skill set in order to control Jerry Oh, properly.
Now you may have noticed the ominous number one at the end of this video title on DDE.
That doesn't imply, of course, that this is part of a greater Siri's and it will be, but not in the same way that the code it yourself worms games was a Siri's.
The reason being is I think platform games are an excellent vehicle for delivering all sorts of additional material about how to do other parts of the game, but this 1st 1 will be quite complete.
We will just talk about how we create tile based levels using a tile mapping strategy.
How we control the camera, how we control the player on how we handle the collisions between all of the above.
Let's get south it Now you may have noticed that all looks quite graphical on.
We'll make it look graphical towards the end of this video, but to start with where it's going to be drawing colored rectangles on screen on this is a simplification that I think is necessary to really understand what the engine is doing beneath.
As usual, I'll be demonstrating everything, using them one lone code, a console game engine, which you can download from the get hope.
The game engine is a simple class, which handles drawing to the screen and user inputs, and all we need to do is fill in these two methods on music create, which we can use to allocate resources.
Andan user update Where we do all of the fun stuff.
I'm creating an instance of my new class called Game on I'm creating a console which 160 characters wide by 120 characters.
Hi on each character is eight by eight pixels, but now When we talk about tile based games, we typically talk about a two dimensional array off something that represents a space, the two D arrays broken up into rows and columns.
As you can see here, I'm drawing them out to Syria.
12345 On we fill a particular cell within the two D array with information that defines what we wanted that self.
So, for example, let's say I want a solid block here.
I'm going to use the hash symbol.
So here's a little platform off three solid blocks for empty space.
I don't want to use space.
I like to use the period character full stop, and that way I can count how many spaces I've gone across the screen.
And the nice thing here is that we know that all of the tiles lie on interview aligned boundaries.
So, for example, this point here would be 32 for two.
Make such a exacta on.
This implies that our tiles are one by one in size, and this is its unit less space.
But let's assume it's one unit that way on its one unit.
That way, working in a unitary space like this has lots of advantages.
Firstly, I don't need to store any of this geometry.
Everything is implied by its position in the array.
We can extract the location of where that tile is on.
We know its width and height.
Now let's say I take an arbitrary point.
Somewhere within the tile map, for example, I'm going to assume this one is about 2.43169 by 3.247 Clearly, this point is using some non into debates numbering format.
In fact, we'll probably be using the 32 bit floats Well, it's easy to work out which cell this point is in, because all we need to do is scratch out the fractional part.
And this is really nice, because we don't need a complex system of searches to work out where we are inside our tile map.
I think this approach is quite elegant, will be exploiting it for all aspects of our platform game.
For example, if I wanted to track a particle in and see if it collides at any point on the map, let's say it's moved to hear from one frame to the next, accessing that information is really trivial.
We just simply x and y into R two d array to extract whatever character is there.
So in this case of its equal to the hash symbol, a collision has occurred.
There are some caveats to this approach.
It does assume that each tile is a rectangle or square, and this boundaries are solid.
So if we wanted pixel perfect precision in our collision detection, we'd have to go one step deeper.
We're not going to do that in today's video.
So let's start by defining the level, and I'm going to represent my level as a string.
And I'm also going to store the wit on DTH e height off the level as in stitches.
I'll create the level in the on user, create function.
I'm going to declare the level for now to be 64 tiles wide, my 16 tiles high.
Don't forget a tile currently is unit lis, and the nice thing about using a string to represent your level is it can be quite graphical so that we've got 16 rose off level and I'm not created a to D array.
I'm just simply a pending it all to one big string now Designing the level can be quite fun using the insert key.
I can put in hashes wherever I need them.
Take that visual studio code and so I'm going to put in a ground plane.
So this is just a single plane going across the level that the character can't go below.
But in order to test collisions, we need to have some features in there.
So let's put in a small staircase of some description and you can see I'm being quite haphazard with this.
I'm not going into too much detail, but we don't want to design levels straightaway.
What we need is more of a playground that we can use to test the collision.
So I'm gonna put in a single block on its own on.
I'm also going to put in, Ah, a more complicated form here for the character to try and navigate.
And I always think it's useful to have some sort of tunnel as well, because this will really test the power of your collision detection routine and you'll notice that my tunnel is one cell wide.
And this is quite important because in some collision detection routines, you may find that things get stuck when the cells are just simply one space apart.
It's also quite important that we give an exit so that the player can get back out into the real world, so we'll just put that in, too.
Deciding which parts of the world we're going to be looking at requires a camera.
So let's add in a camera position X and Y variable.
And as the game progresses, the camera position is going to change, at which point we want to draw the level.
And it's during this drawer level phase that we give the world some scale.
We start to attribute size two things.
So to convert from my unitary tile map space into world space, I'm going to assume that each of my tiles are 16 by 16 pixels.
And this means that by using the screen width and screen height functions, I can work out how many tiles are visible on my screen on a computer display.
The top left is always 00 on.
We probably want the camera to represent the middle of the screen, so I'm going to create two more variables, which represents the offset from the middle of the screen to the top left, and this is simply taking our camera position and subtracting half the screens dimensions in both axes.
I go one the camera to disappear side of the level.
I wanted to stop when the camera position is close to the boundaries of the level, so I'm going to clamp it.
And in this case, if the new top left position goes less than zero, I fix it to zero, and I do the same for the other side.
But in this case, instead of checking for the level with, we're checking that the offset doesn't go beyond the level with minus the visible tiles on the screen for that access, because we want to display at least one whole screen on the screen.
Now we know where our camera is.
We want to draw tiles to the screen so we'll create two nested four loops for X and Y, and these are the same size as the number of visible tiles on the screen.
I feel at this point we're going to need a couple of little utility lambda functions and then to create one called Get Tile, which takes the X and y coordinate on returns the character in our string for that location.
But I'm going to do some boundary checking as well, because I don't want to get any invalid memory accesses, so we'll make sure it's in bounds in the Ex direction, and we'll also check the Y axis.
If it is within bounds, I'm going to return the character at that point in the string, simply by accessing the string is a single dimensional character ray using our good old favorite.
Why Times With plus X.
If we're not within bounds, I'm going to get it to return.
A space which represents our noble character is not quite the same as a full stop space, but perhaps we can use the space character to indicate an error has occurred.
Usually whenever there to get you also have an accompanying set.
So I'm going to create the same thing.
But to set a particular character within the two D location in the string, going back to our drawing routine, I can no extract a character from our string forgiven location.
I call it Tile, I d.
We'll use the Lambda function we just created on will pass into it the X on the Y coordinate and all we're going to do with this.
I d.
Is work out how to draw it.
So if it's a full stop, we probably want to draw some sky.
Come back to that in a minute.
If it's a hash symbol, we want to draw something that's solid.
And if it's anything else, we're just going to draw a black.
So if it is a period which represents nothing in our game, then I'm going to use the one Lakota Phil Command to draw a rectangle in that location.
So I'm taking the X and Y values, scaling it by the tile with and also taking the X and Y values plus one each and scaling those two.
Because we're going to be drawing a square from the top left to the bottom right of that rectangle on, I've chosen the color to be science.
Let's take exactly the same code for hash.
What I'll set the color to be read to indicate a solid surface.
You probably already thinking ahead that we can override these later on with spiked drawing routines, and we will let's now add in the ability to control the camera's position.
I'm going to add in something for the camera to follow, which will be a player.
So I'm going to create two variables Floating Point, which represents the position of a player on that we know for later on.
We're also going to need some velocity component as well to move the players position just before we draw.
I'm going to set the camera position to the player position.
You might think, Well, why we're doing this.
Why do we not just use the player position directly?
Well, the truth is, I don't know what we might want to do with the camera compared to what we want to do with the player, perhaps for a cut scene or something.
I want the camera to go somewhere else.
Perhaps I wanted to Georgia and shake around, but I don't want to change the place position in order to emulate this effect.
But for now, we'll just assume there's a 1 to 1 relationship between the two.
Handling input in the council game engine has always been quite simple, but I've made some modifications to make it even simpler on.
The first thing I've added isn't is focused flag, and this will check whether the command window actually is under focus.
Some of you may have been experimenting in the past and notice that when you typing things in a document, stuff is happening in your counsel game engine application.
You can still do that, but now you can filter out whether the window is highlighted and not by using this routine.
I'm going to aunt controls for the up, down, left and right directions.
We'll we'll add player physics in a bit.
But for now, I just want to test the collisions instead of using the M keys directly over Nice and tightly wrapped that up in a get key function.
So you just passed now which key you're interested in, and it works exactly the same as before.
It's just a little more consistent.
So if the player is pressing the key, I want to change my players.
Why Velocity?
And in this case I'm just going to set it to minus six.
Now you might think, wherever I got six from, well, these values I've tried and tested.
I don't want to show the experiments together in this video in a similar fashion.
Let's add in down, and I'll also cut and paste in for left and right.
But we'll make some changes.
They were working in the ex direction on for moving left.
We are going in the negative direction.
Change this to left, too, and for right, we're going in a positive direction.
What I will do for now is before any of this happens.
I'll send these velocity values 20 next time.
Why, and we'll use those velocity values to update the place position.
So the extraction becomes the ex direction plus the velocity times F elapsed time, which is the tolling between the last frame that was displayed on the screen.
And it's important to use every last time to smooth things out because we don't know how long it takes to update a single frame.
But we want the user experience to appear consistent after withdrawing the map.
We also they need to draw the player, and I'm using the Phil routine again to draw a green rectangle that represents the place position.
The main difference here, though, is you'll see that I'm subtracting hour offset position, which we calculated appear from the players current position, and this will neatly wrap up.
What