Placeholder Image

字幕表 動画を再生する

  • 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 happens when the player has approached the boundaries of the level.

  • So I've done that for both the X on the Y axis.

  • In contrast, when I'm getting the tile from the array, I want to add the officer.

  • So in this case, the offset is moving us further into the two D array, and in this case, the offset is pulling the player back into the screen, the viewable area.

  • So let's take a look and see what we're up to so you can see we've got the Scion background, which represents empty space, and I've got a green rectangle moving smoothly around representing the player with the arrow keys.

  • I can see a red rectangle and I can move around the level.

  • In fact, there's the level we can see.

  • We've decided on the string, so that should be a tunnel down here somewhere.

  • There it is.

  • We'll see.

  • Things aren't quite lining up yet.

  • Fair enough.

  • Fine.

  • We're not quite there.

  • But everything seems to stay wrapped around tile boundaries.

  • As in you can see, we've got this jerky movement.

  • We need to smooth out the map.

  • Moving around.

  • One final test is As the player approaches the edge of the level we can see he moves over to the side of the screen, not that impressive so far.

  • But let's see if we can make it a bit Tidier.

  • The first thing I want to change is the number of tiles that I've got on the screen.

  • But instead of changing the screen resolution for now, I'm just going to change this size off the tiles and everything that we made was adaptive and can accommodate that very nice.

  • The second problem we saw is that the background tiles only seem to move in interview values, and this is completely understandable because our X and Y location moves in.

  • Introduce.

  • We grab an interview tile from the array, and we're drawing out to interject clamped boundaries.

  • We had a similar problem with the code it yourself Frogger game, but in this case, what I'm going to do is calculate Cem offsets into the individual tiles toe, work out how much to displace them by when we draw them on the screen.

  • So let's see what this means.

  • We know that our map offset value in this case, F offset axe is continuous and can have decimal points quite legitimately.

  • After all, it just really tracks where the camera is.

  • This code here gives me the fractional part off the floating point number on because we know that we operate in unitary space.

  • This is very easy, then to map onto how much of a tile does that fractional component represent?

  • Because we simply multiply by the tile with So if we're up to 3.5 has an offset here, this becomes 0.5, and we know that we're half a tile into the offset.

  • I do this for both the X and Y axes.

  • Now that we know are tile offset.

  • We don't want to draw clamped to interview tile boundaries.

  • We want to apply the offset instead, too, when we draw the rectangles.

  • So in this case, I'm subtracting the offset from the X axis.

  • Do it again for the Y axis.

  • And with this Phil routine, you don't specify width and height you specified to absolute coordinates.

  • So we need to also add it to the next two parameters to make sure that so why?

  • And instead of typing all that out again, I'm just going to replace our solid block with same code unchanged the cooler to read.

  • So now we're drawing our rectangles.

  • Instead of being on interviewer line boundaries, they are interred your line boundaries, but also offset a little bit, depending on where the camera position it's.

  • So let's take a look.

  • As I move my green rectangle across the screen, we can now see we have reasonably smooth movement.

  • In fact, it's much smoother than it Waas, and it seems to work in both the X and Y axis.

  • The camera clamping is working nicely, but we can see it was the edges of the screen.

  • We've got information popping in and out.

  • She doesn't look quite right.

  • The boundary of the bottom seems a bit distorted on DTH.

  • E boundary on the right hand side doesn't seem very well, either.

  • Well, one way to approach this, and it's a little bit lazy is to simply overdraw everything that we need.

  • So instead of just drawing from the precise number of visible tiles, I'm going to draw to a plus one boundary of tiles around the visible screen.