Placeholder Image

字幕列表 影片播放

  • All right.

  • Welcome to G T 50 Lecture five.

  • Today's topic is The Legend of Zelda, as you can see on the screen there.

  • Very iconic game.

  • Last week we did Super Mario Brothers, which is arguably the most iconic video game of all time.

  • Legend of Zelda is a close contender.

  • Even now, just like with Mario, they're producing very wonderful games, I think last year, Breath of the Wild took all the I forget which ceremony it was our award sort of show, but it took like every award possible this last year of the latest Sell The Breath of the Wild.

  • So it feels sort of a proposed thio.

  • Talk about Legend of Zelda in that context as well.

  • Here's a screenshot of the original legend result.

  • It was an NTS title, just like Super Mario Brothers.

  • Eh?

  • You know, just like most games of its time, tile based you can sort of see how the surroundings of sort of layered tiles bit by bit.

  • Um, with the goal of the game overall was to sort of explore this open world, which is kind of a first of its kind controlled link, showing the very bottom there yet a sword.

  • You had bombs.

  • You had arrows.

  • Bed.

  • You went to go find Ruby's.

  • You went through dungeons, you slave monsters and bosses.

  • And then ultimately, the goal was to obtain the tri forest, which is shown at the very top left and right of the slide.

  • Here, Um, here's a screenshot.

  • Another screen privileges all the inside an actual dungeon where you can see at the very top.

  • It's got like a map, layout, maps or sort of arranged in a grid.

  • And you could go room by room, whereby each room was the entire width and height of the screen looking for, you know, solving puzzles, looking for items, that sort of thing.

  • You can see there is a monster there.

  • You have heart to the very top, right?

  • So when you take damage, heart sort of document, we'll see both of these the hearts and the, uh, the dungeon aspect of the game today in lecture as well as you know, the width and height of the room being a dungeon tile and controlling an avatar.

  • But this is sort of a representative screenshot of what the game looked like back in the day.

  • Some topics today that will be discussing in order to implement through the foundation for what a game engine like this might look like are things like top down perspective.

  • So you can see in this screen shot we're looking at, you know, link from the very top in a bird's eye view, as opposed to how we used to look at Mario, um, from the side where it was sort of like a side stroller.

  • Um, here we're actually looking at things from the top down.

  • So we have, ah, view of the room in a sort of a different perspective.

  • They're sort of there's not really a Z access, technically speaking.

  • But there sort of is You can implement things like gravity in a game engine like this by jumping over holes and things like that.

  • But there's no gravity like there wasn't Super Mario where, you know, you walk left to right, you jump over gaps, and it's very easy to see in that, sir, since we'll be talking about infinite dungeon generation.

  • So in the context of today's example, we'll see how we can go about implementing a dungeon that sort of you can go through forever and ever and how to sort of model that and make it look as if you're traveling through a dungeon over and over again and going through different screens in different rooms that are all different.

  • But in reality will see it's actually just an illusion like we've seen before.

  • In prior lectures.

  • We'll talk about hit boxes and hurt boxes and with the differences between the two hit boxes being rectangles on the screen that inflict damage upon other entities in your game world and hurt boxes sort of being the rectangle that models where your player or whether where an entity in the game can be hurt by other hit boxes.

  • Well, look at events.

  • So events are a way of sort of broadcasting some key or some message that tells the game world.

  • Oh, this thing happened and let me register a function to call when that sort of event is processed.

  • So on some event, you know, dispatch an event and then upon that event, being received by whatever is listening for it performed this chunk of code.

  • It allows you to sort of decouple aspects of your game engine a little bit and makes for a little bit more readable code and allows you to do some interesting things with, like, achievements, for example, where you don't necessarily want to pull every single frame.

  • Oh, did I do this sort of arbitrary list of things?

  • This frame Rather, you can just process all of that with any event and have a listener and a function that, you know, every time you broadcast Oh, pickup coin.

  • Maybe I have an achievement.

  • That's like, Oh, uh, how I picked up 50 coins in this level.

  • You know, you're achievement callback function in your event.

  • Can can then look for that.

  • And in your game loop, you don't have to say every frame.

  • Oh, if Player has 8 50 coins and you sort of take out bloat that would exist in your sort of overall game loop that way, and we'll see an example of how we use that in today's lecture, we'll get screen scrolling.

  • So a very common are very sort of iconic aspect of legend of Zelda is when you're going from one screen toe another, there is a sort of transition period as one screen loads and the other screen goes away in hardware in the NTS.

  • But, uh, this was sort of the only way you could actually render a lot of, um, sort of more than a screen with of tiles.

  • You actually had to dynamically load in tiles and sort of override tiles that existed before that in memory.

  • But today we'll see how we can sort of create the illusion of doing that by just drawing a room and then having our main room and then just sort of twinning over and then setting everything back to the origin at 00 And it makes it look as if we're moving, you know, back and forth between all these rooms when in reality, all we're doing is just doing a shift and then putting everything back to 00 So all sort of illustrate that on the screen, if I can, And one last thing will look at his data driven design in the context of ah, lot of types of games, particularly RPGs and action games.

  • It's often very valuable to be able to model all of your items.

  • Entities sort of abilities, anything you really can as data rather than logic in order to make it easier for you to write one and two for you to sort of allocate the design aspect of your game to other people, not just programmers, and have an engine that's very versatile and model.

  • And we'll take a look at how we implement sort of a a foundation for that later on.

  • But first, I'd like to illustrate a demo for today's lecture.

  • Um, a sort of implementation of Legend of Zelda.

  • Is there anybody that would like to come up into a demo this today in class?

  • Awesome.

  • Thank you so much.

  • So, whenever you're ready, go ahead and press Ah, the return key there.

  • And so we see on the screen Legend of 50 which is our legend of Zelda mock our, you know, rip off sort of.

  • So if you press enter, you go into this is the place state of the game.

  • So you control an avatar, you can walk around, you can interact with switches as we saw here.

  • When he presses a switch, the doors open and once the doors are open, you can walk through them.

  • And it does as where I lived before it transitions the screen one entire screen higher with depending on the direction up, above and below way.

  • See here now where you're pressing space bar to actually swing our sword.

  • It's destroying the entities in the game space.

  • So there's a hit box triggering when you press the space bar that collides with other entities in the game world.

  • If that hit box hits their hurt box, then they are flagged is dead and they disappear from the game world.

  • And so this goes on ad infinitum.

  • It's just infinite dungeon so way he can go in between as many force that we want to.

  • All we're doing is every time you go through a doorway, spawned a new room, delete the old one and just keep going forever.

  • Never, never in a game like Legend of Zelda typically doesn't work like this.

  • There's a hard set number of rooms, and they all exist in sort of a two D array.

  • And when you generate your dungeon, you sort of have to take in consideration things like, Where do I put the keys?

  • What I put the boss where I put treasure, that sort of thing.

  • We won't get to in depth as to how we can implement a complex algorithm like that.

  • But we'll touch on it a little bit and talk about maybe some ideas that we have.

  • And then, lastly, we just If you want a demo, we could see the top left.

  • We have hearts there, which is iconic, sort of Zelda.

  • And when we do take damage from an enemy notice that we flicker a little bit.

  • So there's some rendering behavior triggering, and we become invulnerable when we take damage.

  • And then last night, when we finally take the last hit, we get a little game over screen using the Zelda Font, and that's the game.

  • In a nutshell.

  • Press Enter and Luke back.

  • So pretty simple altogether.

  • But there's a lot of pieces here that we haven't really seen before.

  • So thank you very much for coming up to Demo the game.

  • All right, so that was a demo of, you know, legend of 50 Legend of Zelda.

  • It has a lot of the pieces that Zelda has.

  • Its not as fully fleshed out, of course, is a full game like Zelda, which would be monstrously large on, and there's a lot of things we need a factor in.

  • But the foundation is there.

  • We have the Dungeon Foundation upon which we can build a an actual generator if we wanted to.

  • We have entities.

  • We have hit boxes.

  • We could easily model because we have switches in the game.

  • We could model things like treasure chests that open that have different states, just like the switch had different states and have different objects in our game space interact with other objects.

  • We have a lot here, and we'll talk about all of it today.

  • So here's a few screen shots just to show, you know what we just looked at.

  • Our goal, mainly, is the second screen shot on the top, right, which is the place state that has all of the little pieces we just saw.

  • But just a title Together.

  • We do have a start state here in a game over state, which is relevant in regard to the hearts in the top left.

  • So the first thing that I'll talk about, um as we sort of get the engine built up is where do we go for getting our assets into the game?

  • And just like in prior lectures prior to today, we just have a spreadsheet like we did with Mario, where everything is laid out in a fairly even sequence of, um, tile segments.

  • In this case, the segments are 16 by 16 pixels.

  • Here I've over later grid, just to show that the picture is indeed perfectly 16 by 16.

  • And this is something that you should take into consideration and consciously do when you're building your game.

  • Assets make it easy to chop up into little pieces so you can an index into this sprite via some table quads, Um, and then a sign, an I D to whatever object or tile you want to rendered to the screen.

  • And so we see.

  • If you look here things like the doors, they're not perfectly modeled by one tile.

  • And so when you do have things that are larger than 16 by 16 it's not quite as easy as, oh, you know, have an entity or an object with this frame, I d and draw it to the screen.

  • You actually do a little bit more complicated.

  • Render logic.

  • So just offhand.

  • If I wanted to draw a door, does anybody have any suggestions as to how I would model that and or draw it to the screen.

  • So if we have a door that's not perfectly, eh?

  • 16 or a you know, 16 by 16 pixel tile.

  • Offhand, the you know what we need to do is just basically store all four of those tiles.

  • In this case, or at least you know, keep track of however many tiles you're, um, object is, and they just draw them based on some offset.

  • Have the, you know, an X Y that represents the top left of that object placed in the right position.

  • And instead of drawing just one tile, we draw four tiles.

  • And then, instead of having just one collision, boss, that's 16 by 16 tiles.

  • You can do a couple things.

  • You can either check collision on all four of these tiles or all at least all two of these door tiles or model your own custom hit box that then maybe that object that represents a doorway has control of so you can say, you know, doorway collides player, and then the doorway has a height and width of however many pixels.

  • It is wide by tall here, just this door part, and then you know, you are able to then build upon not just having one tile that models a an object or entity in your game space.

  • But now you have more artistic flexibility.

  • You can do things like have doorways that are more than one pixel white and sort of have a more convincing game world as a result of that.

  • And you see a lot of things like that in games like RPGs, where you have full houses that are obviously not just one tile.

  • Because that would be I mean, something.

  • You can model things as one tile if you want to.

  • But from an artistic perspective and from just a game engine perspective, it's a little bit easier to programmatically be ableto cut up all your assets into tiles and draw them as such.

  • Um, so being able to sort of build upon this just the single Sprite and be able to do multiple sprites to represent an object is the key to things like houses, things like big trees, um, things that are just more complicated than single tiles.

  • As we see here, the character spreadsheet is, as you can see, a little bit more complicated.

  • So this is an example of a spreadsheet that has padding.

  • Sometimes you will get spreadsheets that aren't neatly divided into even segments.

  • And for good reason, because sometimes you have tiles that are not perfectly the width and height of whatever your game engines tiles are.

  • In this case, the player is actually 20 pixels toll and 16 pixels wide, and on top of that, he's got different frames of animation.

  • We can see here at the bottom left.

  • He's got a sword swing animation.

  • The swordsman animation is actually stored in a 32 by 32 pixel frame because sometimes, um depending on which angle he's looking at, his spread could get a little larger or smaller.

  • So when you have a sprite with padding, what sort of a way that we can draw this to the screen, um, reliably, like, how do we How do we take this into consideration?

  • How would we render a screen?

  • Ah, spread with padding?

  • So let's say this right here.

  • Our character swinging a sword is in 32 by 32 pixel box, right?

  • This sort of box around here, this white space, but he's only still maybe 16 pixels wide by 20 pixels tall or maybe he's some amount similar to that in order to draw him to the screen, which you can look at in the code.

  • All we really need to do is a sign that sprite and offset just say OK, the sprites offset Accent offset.

  • Why are some value that basically lets us draw the sprite toe a negative X and a negative y value And that will shift the sprite up suspended aligns perfectly with wherever his x y r and weaken.

  • You can take a look at that in the code to see exactly how that works.

  • Lastly, the actual entities for our game world are different creatures, and this is a spreadsheet.

  • This is a more ideal spreadsheet where everything is 16 by 16 pixels wide and tall.

  • And all we really did here was just divide the spreadsheet using the regular utility function, generate quads by 16.

  • 16.

  • Um, we don't have to worry about separate, you know, wits and heights for everything.

  • And we can create animations very simply because of this, um, as a side note, something that I like to do when I'm, you know, parsing or when I'm piecing apart a spreadsheet that's got a lot of individual frames particular from creating animations, or I just need to know it for a tile particular tile to drop to the screen.

  • It's kind of a pain to manually look through each and every tile one by one and say, OK, this is one.

  • But okay, if I want to find out what's one?

  • This slime is I gotta count.

  • Okay.

  • How many pixels wide is this?

  • OK, and then it's time's forces 12 and then it's on the fifth row.

  • So 12 times four plus one.

  • Well, get me Okay, so it's Zay Index 49.

  • So I've spent, you know, a non trivial amount of time.

  • So hand calculating what?

  • All these d'oh!

  • I wrote a simple python script that will just go over a file and just add a digit to each individual quad to just show you at a glance what each Sprite is.

  • And this is included in the districts.

  • You can see what it looks like, saves a lot of time, and I recommend trying when you're, you know, sort of working with assets and you find yourself doing something that takes a long time in a sort of tedious and mechanical.

  • Maybe try.

  • Try to find a way to sort of automate that, or at least make it easier to do things at a glance.

  • In this case, just simply imposing a numerical grid solves that problem.

  • I don't have to spend a significant amount of time figuring out which frames of animation the ghost facing left is.

  • I know instantly it's 67 68 69 um, and allows me to just crank things out that much faster.

  • So the first thing we'll take a look at is, ah, sort of top down perspective.

  • Uh, and we mostly talked about this before earlier, but all it really is is a tile map, which we've seen before.

  • Uh, the only difference is now, instead of looking at things from the side, we're just looking at things from up above.

  • So what's it?

  • What's it Probably the most obvious consideration when designing a top down perspective versus a sort of side scrolling point of view.

  • Ping it, looking at, particularly at how the tiles are drawn, what stands out.

  • So the thing that stands out to me is that we have things like shadows on walls.

  • Here we have also corners and things altogether are skewed such that they are almost like rotated slightly as if they're simulating an angle of rotation relative to Thea camera facing from up above.

  • You can see this in like the player, for example.

  • He sort of looked sort of looks like you're looking at him from kind of backwards and up when you're modeling your assets that way.

  • Uh, you this it's more convincing, and Zelda has always done this to make your assets look as if they are slightly tilted and that you're looking up above.

  • So when you're designing a top down game just for convincing the sake of being more convincing, try and emulate that the entities here, like the skeleton and such are a little bit more straight on the bats and Slim's and what not, even though they still have a little bit of that appearance.

  • Like the spider, it sort of looks as if it's from the top back, but modeling your assets from a top down perspective.

  • Really, that's made mainly the thing.

  • Pay attention to shadows and highlights, which adds a lot in terms of convincing us that we're in this room with lighting And also make sure that you're doing things like corners and stuff and making it look as if things are slightly skewed.

  • Rotation wise, the first thing that we're gonna look at in terms of the code and the destro is dungeon generation.

  • So, uh, in Legend of Zelda, dungeons are fixed.

  • They're completely set in advance by the designers.

  • And in most games, this is actually the case in our example and in a couple of other examples, primary example of them being that I can think of that I haven't slides.

  • Ah famous game called The Binding of Isaac Dungeons can also be generated.

  • So in what's the sort of like the main unit of a dungeon, at least in the context of Legend of Zelda?

  • If you had toe distill what comprises a dungeon, what's like the most fundamental unit?

  • Yes, a room.

  • So we can almost look at this if we picture it in terms of A to D array, right, we have assuming that this is like index 11 in lieu a 00 in other languages going left to right top to bottom.

  • Basically, we have honor off relative to each of these off on on, off, off, off.

  • Each of the indexes in this Tootie array holds a room.

  • And so the room has connections implicitly between the other rooms.

  • If you wanted to go, let's say from this room here to the room up above it.

  • What's the offset in terms of the two D array?

  • How are we going from this room Up to this room.

  • So we're just going up a Y level.

  • Right?

  • So this is X level three.

  • Why level three if he wanted to go up to the next room, we need to load in if we're doing it the Zelda way, right?

  • And we're just going where we're doing a transition between one room to another.

  • What we need to dio is load in the room at this room minus one on the why and then perform the transition and then set that to the current room.

  • Such that Now we know we're at why Level two ex level three.

  • That's our dungeon.

  • In the context of two D dungeons in The Legend of Zelda, that's a simple as it really is.

  • You have a two d grid of dung of dungeon rooms, each room has its own collection of entities and objects and connections to other rooms.

  • But really, all you all you do to sort of fill a dungeon is filling array in a smart way, such that there's no rooms that are, for example, left by themselves, noticed that every room in the dungeon has at least one connection to another room.

  • Um and that when you're maybe doing your algorithm to create a convincing dungeon, lets say, this room here has a door on the right that has a lock, right.

  • We want to make sure that the key isn't in that room, because if it is, we're never gonna be able to get to it, assuming that we come from another direction.

  • So when you're designing dungeons procedurally, you want to take these sort of things into consideration.

  • And then, for example, the boss room.

  • Let's say this is the boss room.

  • The boss room should have ah, maybe a boss Qi or something like that.

  • But the boss Qi should not be obviously in that room.

  • It should be somewhere.

  • Maybe, where there's, ah, a couple of rooms before it that have a lock or a key so that you know, there's some sort of challenge involved in your dungeon.

  • It's not just random.

  • As as random as we've done before.

  • There has to be a little bit of sort of conscious design on behalf of your algorithms.

  • Today we're doing things completely random.

  • Um, for illustration is because a system like this is fairly robust and complex, but with some effort, you could create a simple dungeon generator just using those mechanics.

  • Just make sure that you have locked doors.

  • The lock doors can only open when you have a key.

  • Make sure the key exists in a place that's accessible and sort of create a chain of like, a sort of like a control flow model, maybe via a graph of some kind that represents your dungeon and the progression thereof.

  • So that's that's what Zelda Dungeon looks like.

  • That's what a to D dungeon in this sort of perspective looks like.

  • And it looks it will look similar to this in other game engines.

  • It doesn't necessarily have to be perfectly modelled as a screen with screen high room going into another screen to screen right room.

  • You can have arbitrarily complex rooms that have arbitrarily complex sizes and shapes.

  • Um, but you still need to make sure that the connection's going out of the rooms, like if you could still model, you know, left right up, down If you want to, you could model arbitrary numbers of connections between rooms.

  • Just make sure that you have puzzles that can be solved.

  • That's the main sort of obstacle in generating your dungeons.

  • Here's a game that I really like that uses the old legend of Zelda formula to very good effect.

  • Now it's called the Binding of Isaac Notice.

  • Already, we can instantly see that it's top down perspective.

  • It's the entire width and height of the room Is the dungeon of Ah, the entire width and height of the screen is the dungeon room.

  • Uh, you have a map up here that serves shows.

  • You okay?

  • I'm in this room right here.

  • I could go up, I go left, I go right.

  • I can go down this room up here with the yellow crown That's gonna be locked behind some door with a key.

  • So we need to have keys that spawn in any of these rooms that air just blindly accessible.

  • And Isaac does things a little bit differently.

  • Also in that it generates keys and bombs randomly so that you can actually get You don't necessarily have to plant your keys in very specific locations.

  • If your algorithm is sufficiently accommodating and complex enough, you can just at the end of every room, have a chance to spawn a key randomly.

  • And you know, if you're lucky or if you're not lucky.

  • And assuming that the end of the dungeon doesn't exist behind your locked doors, you can you have three opportunities stolen.

  • Lock those doors or not, and just go on throughout your dungeon as needed.

  • In this case, they don't lock the boss doors so you can go through the boss door regardless of whether you have a key.

  • So they've accommodated for this purely random approach.

  • And that just goes to illustrate how you can still take random ization using very complex principles and produce games that are extremely addicting and fun and, um, don't necessarily need to be super elaborate.

  • The first thing Okay, so hit boxes in her box for the next topic.

  • So I want to touch on in the code.

  • How we sort of do dungeon generation in the game engine here.

  • So I'm gonna open up.

  • There's a few files.

  • So doorway noticing in Ah, the source.

  • Destro, There's a world folder We've sort of categorized all of the files that have to do with world generation.

  • Within that world folder, We have a doorway file, we have a dungeon file and we have a room file.

  • So the dungeon file models, the dungeon, we just all of the rooms.

  • That former dungeon, um, just is a very high level, top level data structure.

  • It's actually very simple.

  • The room is, as we saw before the individual unit of the dungeon.

  • So a dungeon is effectively like a table of rooms, and then it models interacted mob.

  • It holds the code for how we can transition between them.

  • But that's sort of how we can think about it when you have a game level in general.

  • In this case, dungeon is sort of our game level.

  • You can model the different subset aspects of your level via some data structure.

  • In this case, we've decided to make it room.

  • But if you have just a platformer level, maybe you have a regions or zones or anything, just little sub segments of your level that you can transition between.

  • Um, it's useful to think in terms of that, because from an efficiency and performance standpoint, you want a dynamically probably load certain levels one at a time.

  • Certain aspects.

  • Certain components, sub areas of your level, one at a time rather than just the entire level at wants.

  • Because depending on how sufficiently complex and larger level is, you could get to ah, you know, exercising your computer's memory constraints, so I don't want to do that.

  • So in this case, our algorithm is we have a dungeon.

  • We have rooms.

  • We have one active room that's only visible at one time.

  • That's loaded in memory.

  • And then whenever we transition between rooms, we wanna have another room that gets temporary, really loaded.

  • So let's look at the dungeon class here dungeon dot lua.

  • So 14 self dot room's empty table.

  • We're gonna fill that with rooms, just room objects, self dot current room room, and we're gonna pass it in the player so shut the player has access to all the entities and objects they're in and could do things like collision detection, which is very important.

  • And also, um uh, so that the entities in the room can look at the player and then decide what they want to do with their A i which you can model arbitrarily complex.

  • Um, the whole innit function of room dot lua is gonna We're gonna show it here.

  • So in room doubt Lulu in that same world folder we've Instead, she did the dungeon at a high level.

  • We know the dungeons that it's basically a table of rooms.

  • So what's a room look like?

  • Well, a room as we saw before.

  • What is that?

  • One of the pieces that a room needs in order to function was the room.

  • Have to sort of keep control of so doors.

  • Anything else?

  • So doors, it has to keep track of right, because when we touch a door, we should transition to the next room.

  • It should keep track of the player so the player can update should keep track of objects in the in the room like switches, as we saw in the example such that you know, they can update those and CEO has the player stepped on the switch.

  • If he has opened the doors and then entities, right?

  • It should keep track of all of the creatures in the in the in the room so that they can update they can interact with each other.

  • The player can hit them where they can hit the player.

  • Um, and you can model whatever interactions you want to go, so you can see here.

  • Oh, and another thing, too obvious thing.

  • Probably the most one of the more important visual aspects of it.

  • We need to also have a set of tiles that model what the room looks like.

  • It's a container.

  • So we're gonna draw, you know, we have a corner, a corner, a corner, a corner, walls on the sides, walls on top of bottom, and then a floor.

  • And so that's we need to obviously draw the room before we draw all of the other things and update all the other things.

  • So tiles, doorways, entities and objects.

  • John, we can see here we have tiles self that tiles gets an empty table.

  • We have a function called generate walls and floors.

  • Entities.

  • Empty table.

  • We have a function called generate entities, and then objects equals empty table.

  • We have function called generate objects and lastly, doorways.

  • And then here it's Ah, because it's not necessarily as complex as we need for a, um, an entire function.

  • We just have four doorways and this is static.

  • I've chosen in this example to have all the doorways always be in the same place and sort of behave in the same way.

  • But you could create a more complex system whereby you especially if you have an algorithm that generates a dungeon dynamically.

  • And maybe your rooms aren't necessarily hard set.

  • Maybe maybe you have a room, right?

  • If we go back to our slides earlier.

  • And let's say we're looking at this room right here in the very center we can see, it has a door on the left, a doorway up top and a doorway to the right.

  • But there's no doorway on the bottom, Um, and that that looks like an arbitrary design decision on behalf of the designers.

  • But, uh, if we look at this room up top here, we can see that it's sort of behaves in the same way.

  • There's a doorway going to this room to the left.

  • There's a door going to this from down below but it doesn't have a doorway up top in a door on the right because there are no rooms going between that room and those directions.

  • So when you have a two D array of dungeon rooms and you want to model your door ways, it could be as simple as Is there a room in that direction?

  • If there is, and you will have your data structure sort of laid out in advance before you generate these doorways, if it does, if it does not exist, don't make a door.

  • If it does exist, make a door and then make sure that when you transition between, though left from, let's say, from the right to the left or from the bottom to the top that you go to the correct rooms at the correct indices in your two D sort of room array.

  • Does that make sense?

  • Anybody have any questions so far as to like how this works at a high level?

  • Okay, awesome.

  • So these doorways here are all because of this dungeons completely random, and every time it always has doorways going top, bottom left and right, we're always just gonna put four doorways going top bottom left and right.

  • Note that they take a string denoting which direction they are.

  • And this will become important later on in the doorway class, which we see here is model as a separate class.

  • Um, false here just means is the door open.

  • So by default, we're gonna close the door and then self so that we have access to the room from the doorway.

  • Um, the room should have a reference to the player so that it can model interactions between the entities and the player as well as the objects on the player.

  • Notice that it has a render offset.

  • So if we look at the game here, the tiles don't completely match up to the width and height of the screen.

  • And that's mainly a function of the virtual height, not mapping perfectly to 16 tiles divided evenly by 16 tiles.

  • So what I've done is I've made the dungeon a little bit smaller, and I've and also the fact that the doorways take up a couple extra tiles of padding on their on their sides.

  • This, like, sort of blank space up here.

  • We've shifted everything inwards a little bit.

  • We've made that we've made the dungeon one tile smaller or two tile, smaller width and height wise than the screen.

  • And then we've just rendered, offset by certain amount.

  • Since that is completely centred, we calculate how much padding exists between the fully rendered dungeon and whatever blank spaces left and just shift by half of that amount.

  • And that's our render offset.

  • That's why that's what Why render?

  • Offset is important.

  • In this case, when you're trying to center anything, you typically do it.

  • We just by calculating and offset calcula width and height of what you're trying to draw.

  • Calculate whatever you're with and height of your screen is minus that divided by two.

  • That's your render offset.

  • And then this is this.

  • These two fields here are interesting self not adjacent offset X and self doubt at Jason Offset.

  • Why does anybody have ah gases to, um, sort of what this is used for?

  • Yeah, so, yes, exactly.

  • So drawing itself when it's the adjacent room.

  • So when you load the next room, you're going to Instead, she ate a room just like this, but by default, it's going to draw at 00 However, if we want that room to draw, you know, not right where we are.

  • Obviously, if we're in the current room, we don't want the next room drawing right on top of where we are, because then it's just gonna layer right on top of the room we're in.

  • We want to draw it.

  • If we're going to the right, we want to draw a screen with to the right.

  • If we're drawing it to the left, we want to draw a screen with to the left and same thing on the Y axis, a screen height above or below it.

  • So, Jason, offset X or Y We just add to when we draw the room and that will have the effect of rendering it separately from, uh, from the room that we're currently in.

  • Aiken, try and draw having illustration here.

  • So if we have our room here, this is our current room, so self dot current room.

  • And if we let's say we have a doorway here, right, That's a Dorie object.

  • The player is here.

  • He collides with that object.

  • It's gonna trigger a transition to a room up above.

  • So what we do is we load in a new room, right?

  • away.

  • We always have a pointer called self dot next room.

  • And this is all kept track of in the dungeon dot Louie file.

  • But self dot next room by default is gonna be no.

  • But when we transition from the current room to the next room, right, we should set that to something.

  • So self dot current room is going to be the same.

  • But when we trigger this, we trigger this collision Self dot next room.

  • Ah, this is gonna be equal to just a new room.

  • And then we get which doorway we're in, we figure it out, we figure out which direction we're moving in technically and then if we're moving up, then we just pass in a, uh we said it at Jason Offset.

  • Why, in this case, too negative screen height if it's below, we set it to positive screen height, and we said it.

  • If we go here, it's gonna be negative screen with the Jason X will be negative screen with and then positive screen with on the X if we're moving to the right.

  • And so, uh, this sort of adjacent we could see the, uh if we do like X why?

  • I think that will be That's the best, basically, the adjacent offset.

  • And so, um, we end up when we draw our transition going from bottom up.

  • In this case, we just Tween the camera to this value.

  • So we have a camera, right?

  • This is our camera, and it's gonna be looking here by default.

  • So camera action camera.

  • Why those air values in our code as well When we triggered this collision on the doorway and we have current room here, which is it?

  • 00 And then we have this room here, which is at zero minus or plus are adjacent offset.

  • Why?

  • Which is negative screen height.

  • So it has the effect of making it negative Screen night on the why our camera ex miracle recall loved art graphics not translate is our camera.

  • So all we do is we just Tween that we say, Okay, here's our Camp X is gonna be here.

  • And Cam, why is getting a little bit messy?

  • Apologized but our camera x and wire here and then over time we're going to Tween that up into the next two rooms X and y, which is calculated.

  • It's just X plus adjacent offset X Y plus a Jason offset.

  • Why?

  • And then once, once this camera has shifted from here up to here, or whichever direction we're going whether it's up, down, left or right, Once we've completed that, we can normalize everything again, back to 00 by doing, uh, self dot current room equals What?

  • What What do we need to do if we're If we're gonna put everything back to, let's say, let's say I want to make this this room, the new current room.

  • What do I need to d'oh?

  • So we have current room and we have next room.

  • If I want the current room to become the next room, All I need to do is say self dot current room equals myself next room, right?

  • And then once that happens, Jason Officer, what happens to the adjacent offset X and Y Over the next room, they get set to zero, right, I want to take I want to take this room that we've offset up here and I just want to make it the center of the game world again.

  • I want to just put it at 00 so you could do this exact same calculation.

  • Bye.

  • Just setting adjacent offset X or y two a negative or positive screen Haider screen with relative to 00 So what I'm gonna do is just set, uh, the adjacent offset of X and y of the next room, which is now current room to zero, and it's gonna draw it right back at 00 and then camera X and camera Why are also gonna be set to 00?

  • And this is gonna have the effect of looking as if we're going up and staying there.

  • But in reality, we're just going up and then instantly shifting everything back to 00 including a player, entities and switches of that room.

  • So it's purely an illusion, but it allows us to simulate this sort of infinite exploring a dungeon effect.

  • Does that make sense?

  • Is overall flow off?

  • How this works makes sense.

  • Okay, so it's a little bit messy there.

  • Hopefully, I was able to, uh, illustrate the overall algorithm for how the infinite dungeon generator works.

  • Um, where did we leave off on?

  • We were in Oh, yeah, we were in the end, it function of the room.

  • So let's take a look at a few of the functions that comprise that.

  • So generate walls and floors.

  • This is very simple.

  • Very similar to what we've looked at before with, like, tile maps and Mario, for example, where we just go from White X and then we just pick a random I d or not random I d Well, it is random.

  • I d for some of it.

  • But sometimes we need an explicit I d.

  • So, uh, remind me, what does the eye d actually map too?

  • Uh, when were, you know, drawing tiles to the screen If we want to give a Thailand idea.

  • What is that?

  • What should that map to?

  • Yeah, the frame in the spreadsheet.

  • That's correct.

  • Um, it doesn't have to for all game engines for all implementations, but it's the easiest thing to do is just to give it your tile, and I d that you can then just draw you can index into your spreadsheet at that I d, um it is very, very simple.

  • Lightweight, clean approach to modeling.

  • And we can see here I d gets I d um after we've sort of figured out what I do we want now How do we determine?

  • Like, let's say I want to draw.

  • Um, let's say, for example, like this tile here no sense, it's a corner tile.

  • How would I What do I need to do to To basically a sign I'm gonna die before I even have the chance to, uh, to show you while I avoid enemy's?

  • If I wanted to draw that top left corner.

  • Uh, what?

  • Um, I sort of looking for are still taking damage anyway, relative to x And why?

  • What am I looking for?

  • What x and y does that, But is that tile need assuming everything starts 11 on the top left and goes down Thio height and width of the overall dungeon.

  • What is the x y need to be of the top left corner?

  • It needs to be one, right?

  • So if that's 11 basically the top left corner that i d should be equal to the corner.

  • Sprite, the top left corner sprite specifically.

  • What about the top right corner Sprite?

  • What should the XB Sorry?

  • Yes.

  • With exactly what's the why still gonna be one?

  • What about the bottom?

  • Left with comma height and in the bottom right or sorry.

  • Bottom left should be one comma height.

  • Bottom right.

  • Should be with come on height.

  • And so basically checking the position of each tile is how we can infer its i d, which is what we're doing.

  • Um, in the source code here, if X is one and wise one.

  • Okay, top left corner and those that we've put these end into constants that we've put in a constant stopped Luis just for readability, so we can instantly see Okay, I should set I d to tile top left corner.

  • Not some arbitrary number that's our index into the title sheet at like maybe like 40 something or whatever it is.

  • Bottom left is one and height top right is within one.

  • And then, uh, bottom right is with and height and we concert.

  • It's it's readable.

  • We can just sort of see at a glance what were doing.

  • Were you sort of conditioning generating all of our tiles?

  • Um, if none of those are true and then X is one.

  • What's What's that tile If X is one, but it's not a corner, it's a left hand wall.

  • And the same thing is if it's the with.

  • It's a right hand wall, and if why is one?

  • It's a top wall.

  • If why's height?

  • It's a bottom wall.

  • And then if it's none of those, it's gonna be a floor.

  • Exactly.

  • So that's That's basically how we generate the overall.

  • It's very.

  • It's a very easy, simple generation algorithm.

  • What I've done is for random ization.

  • Here we have, ah, actually a table of potential left walls, potential right walls, potential top and bottom.

  • And then we just describe it a random value within their based on however large, that is, and that gives us variable.

  • We can see it.

  • It's it's we have random clips every time I generate it.

  • So take note of maybe some of the tiles visually that you can see there on the map knows that they changed now is that the switch has also changed.

  • No said they changed again.

  • So everything is variable.

  • We have a little bit of visual variety.

  • This is what we did essentially with Mario.

  • We change the tile set and the topper set on Lee.

  • Now we're just changing.

  • We have only one tile sheet, but several variations of the same tile they're in so I'm going to do is pick a random variation of whatever tile and that involves us looking at the spreadsheet, picking out which individual tiles which separate tiles map to, uh, the specific type of tile and then is picking a random value from that table.

  • That's how that works.

  • So, um, a couple things I think left to show relative to the dungeon generation.

  • So, um, 48 we have generate entities.

  • So entities are here.

  • We have their names right?

  • Some of the entities we saw skeletons, bats, Slim's ghost spiders.

  • It's a very light weight function.

  • It's not to like 15 or 20 lines, but we're generating, you know, a bunch of different kinds of entities, because what we've done, we take way basically take a random type.

  • From that table, we create an entity, and then, using what we've defined in a global table called entity deaths, we take out what sort of matters in terms of generating each individual entity, the characteristics thereof, and we just put it in simple data form.

  • This is sort of like the Segway into data driven design for your game.

  • If you look at entity deaths here, we can just see that all of our entities are a sequence of data.

  • So we have appear.

  • We have player right online.

  • 10 player gets a table.

  • We give him walk speed.

  • We have a table of animations.

  • So he's gotta walk left animation, walk right, animation, walk down animation.

  • All of those have their frames there.

  • Interval there, texture.

  • Everything's just clean data, right?

  • There's no logic here, really.

  • It's just flags or values.

  • Simple things you could give this you could give anybody who has sort of the basic knowledge of what we're doing this file and what may be some textures and say, Hey, I want you to design.

  • I want you to lay out basically all of that that's involved in what makes a skeleton sort of rented to the screen like give him, like, create all the animations for them.

  • Give them that.

  • Give us that.

  • Give those animations their time and give them the exact frames.

  • Maybe maybe skeleton should have health, and maybe health should be equal to 10 on a skeleton or something like that.

  • There's not really any like programming going on here, but we're describing everything in our game as data, and that's important thing in complex games that have, you know, fairly complex systems, but that can be modeled by a some attributes.

  • You can just describe your entities and data and then lay your engine, parse this information and then create your entities programmatically You allow you sort of shift the burden from the programmer to the designer a little bit, and you afford your design team.

  • You and maybe other people who aren't as comfortable with programming the ability to modify the game engine, add things to the game without having to go through the bulk of your engine code and do anything too fancy.

  • In this case, it's simple.

  • All we're doing is just we're creating animations and assigning a texture to each of these individual things.

  • But I alluded to this last week.

  • You could have a file that maybe describe something like a goblin will see us at the end of lecture, which has maybe like a flag for isn't flammable.

  • How much help does it have?

  • What are its animations?

  • Um, what skills does it have?

  • Uh, what's its attacks?

  • Drink what?

  • The defense where where does it spawned?

  • Typically, by putting all these attributes together and having your engine sort of parse this you can create depending on how how many fields you have.

  • You can come create a very complex, uh, like potential list of things in your game, whether they're entities with other weapons, whether their items, abilities, anything you want to know, whether their levels even, um, based solely on just data.

  • So this is the holy grail of design and development.

  • When you get into especially very complex games like RPGs, where you can have skills that are, you know, have particle effects and do different damage to different things.

  • And you have entities that are, maybe you want them some to set on fire, some to be electrocuted, maybe some you don't Maybe some, uh, melt when they touch something, create a bunch of flags, create a function that parses this and generates entities as a result.

  • And you just allow yourself an incredible boosting productivity.

  • No longer do you need to create a spider class, a ghost class, a bat class.

  • It's all unnecessary.

  • All you need to do is define what sort of attributes Doesn't that have?

  • What attributes does a ghost have?

  • What attributes does a skeleton have, and anybody can therefore mod your game.

  • As a result of this, all they need to do is know what attributes a potential entity can have, and your design team is all the more productive as a result.

  • So that's a sort of spiel on why this is relevant.

  • We've implemented a very basic version of this just for the sake of modeling animations.

  • But we don't n

All right.

字幕與單字

單字即點即查 點擊單字可以查詢單字解釋

B1 中級

塞爾達傳說編碼教程--CS50的遊戲開發入門篇 (Legend of Zelda Coding Tutorial - CS50's Intro to Game Development)

  • 1 1
    林宜悉 發佈於 2021 年 01 月 14 日
影片單字