Code-It-Yourself! Role Playing Game Part #1

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello it's time for another big project let's make a top-down role-playing game without a doubt the most popular request I have had for a project is to create something along the lines of a Zelda game now I love Zelda but I've always been a bit more of a final fantasy fan so I thought would be an interesting project to try and merge the two together so we've got some as elder gameplay battle and exploration dynamics but we've got a plot given in the style of Final Fantasy and this is what we've come up with so far so I'm currently controlling this little character walking around the map and you can see some effort has gone into the graphics now all of the graphics have been created by the one lone coda community from people on the discord server and they're all still a work in progress because if this is a big project I don't have the time or resources or the skill frankly to create all of the graphics necessary I've needed other people to do that for me anyway so we're looking around the map here and of course the we've got some collision detection we can't crash into the buildings or trees and one of the things we can do is enter the other building we can see the tile set has changed and again we've got the collision whilst we control the guy around we can exit the building and we go back into the town level map all familiar stuff but for me RPGs aren't just about walking around finding things and fighting enemies I like story driven RPGs and so a lot of effort has gone into this project to develop a system which will allow us to deliver a story to the player so here we've got another character and I'm going to interact with him by pressing the spacebar and we can see straight away the character or in takes to an own position and some dialogue starts in fact this guy wearing an orange t-shirt is me hello let's make her hmm oh dear and the character we called him witty for now don't know if that's going to stay or not for the end game and so I've still no control but the script engine I've been calling it the theater engine has taken over and it's moving the characters around and presenting the dialogue I've got control again now and I'll go on I'm not going to talk to it myself oddly just yet I'm going to go step outside because one of the important things with a game like this is persistence but having that conversation has triggered other things to happen for example now I've got the introduction of two enemies now before they come and kill me I'm gonna go back inside I'll finish off this conversation so we'll talk to the character again it's no good I can't make a video why not well two things really firstly I've lost the sauce secondly I've lost my glasses so this is the start of sort of two additional quests and witty because he's a helpful resourceful type of guy jumps up and down and says I can help and again I've got control over the place that's all handled by this theater engine in the background we go outside and try and take on these enemies so the enemies have a limited amount of AI at the moment they just sort of follow me in a Terminator style mode and but they have to abide by the rules of the map too so you can see they can get stuck on solid things there's nothing clever going on here yet and we'll see throughout the course of this project that we can really sort of fine-tune things on a per object level because even though this is a video about an RPG it's really a video about object oriented programming well let's take on this skeleton so we've killed one of them now let's kill the other there we go this project is far too big for a single video so it will be split over several videos and I'm not yet quite sure the relief schedule will be I'm still actively developing this project now to be different to a lot of my previous videos this one is highly object oriented and that's because I think people aren't really exposed to object-oriented programming through most of the stuff that I've been working on yes we've used classes and strokes but we've never really used them in any form of anger an object-oriented programming approach is ideal in this situation because we've got lots of objects in the game that interact with each other in different and customisable ways also even though I'm responsible for programming the engine the rest of the community is contributing in terms of graphics and maps and quests or at least they can do if they want to now so this means we want to find a form of separation between the core and what we'll call it the assets and this is important because if the graphics or the quests or the objects change we don't want to have to hard code changes into the core engine an individual's approach to object orientated programming is polarizing there's no about that absolutely the way I am going to show how I have used object-oriented programming in this video is going to upset somebody and so a little personal disclaimer that this video is probably not going to be an example of best practice when using object-oriented techniques but nonetheless for the most part I think you'll get a a really good understanding of how object-oriented programming can really enhance and partition your development process but I will be breaking some rules now before we get started I've got three other things to say firstly I'm not going to be putting the source up at the end of this video I'll put the source up completed at the end of the project secondly at the end of the post I also put up a compiled version of the game and thirdly I won't be showing every line of code necessary in detail and you'll see why object-oriented programming has a lot of repetition and the size of this project they fight was to show me typing out every single light it would get quite boring and so with all that out of the way let's get started this first video of the series is really about the structure of the project and you can't start a big project without having a think about what the requirements are and for me the most important requirement of a role-playing game is to tell a story we also want to explore and this is traditionally split into towns and dungeons we know that just walking around isn't enough so we probably also want to have some battles and as well as just battling exploring and enjoying the story the player also needs to feel rewarded so we need some items weapons and power-ups so let's just have a little bit more of a think about telling a story well we know a story is going to have to involve some sort of plot it's got to be compelling he's got to keep the player engaged and we're going to use the plot and the rest of the system to develop an atmosphere you know it's something that will really absorb the players interests in order to tell a story we're going to need characters and the cast of characters in some way needs to be scripted to form cut sequences to facilitate exploration we're going to need maps and these could be things like towns and dungeons this sort of stuff you saw at the start of the video we also probably what hidden stuff so we get that real buzz from finding something that you think nobody else will have found we're going to need a way for the player to move around these maps so we're going to need a navigation and adjacent towns and dungeons can simply load to each other but we may also want to go from one town to another so perhaps we also need a world map battles are important too because that's how the play is probably going to grow their character through the game so we're going to need an array of enemy so different enemies and we'll probably want the enemies to behave in different ways so we're going to need some sort of behavior AI battles also need to be balanced and this might take a bit of fine-tuning it's no good if the first enemy of the game comes and kills your characters straight away but they also need to be fun they can't be cripplingly strong they can't be boring and mind-numbing button bashing to reward the player we're also going to use items weapons and power-ups and so this invariably forms some sort of treasure system it could it could be gold it could be exploring chests I think more commonly these days it's known as loot and buy power-ups I don't mean turning the character into some unstoppable force it's usually an upgrade to the weapons or armor but of course we're going to need something to keep track of all of this so we're going to need an inventory and it's quite possible the player is going to collect lots of loot in the game so we're going to need somewhere for them to get rid of it we'll have some shops it's interesting to see from this list already that we can start to identify what's game design and what engine design so for example the the plot here that's a game design thing the game engine has to facilitate the plot but ultimately it's the game designers role to come up with the story and the same goes for creating the atmosphere what does the art style look like what's the music like how do those things tie into the plot the characters is a bit of both of course that's plot an atmosphere but what I think is important here is that we're going to have to have multiple characters so perhaps that's an engine design thing and the same goes for cut sequences we need to think of how do we structure an order of events to display animation dialogue interaction to the player when we start thinking of maps we know that the game engine must support the loading and transition between maps but also the layout of the maps becomes a bit of a game design thing - so we'll highlight that is game design and certainly hidden things that's purely a game designer thing however moving between maps is probably an engine thing they'll be something on the map that says I must load another map and certainly the world map is an engine thing too because even though the world map will be designed by the game designer it's a it's basically the the central hub through which the player can find all of the other dungeons and towns to visit when we start to look at different enemies that implies that we're going to need assets which behave and do things differently they look and feel different to the player so that's an engine thing and how the behavior is implemented is also an engine thing - you want to expect the game designer to necessarily decide on the maths and physics involved to implement a particular AI so we're going to leave that in the engine column however tuning of the enemies that certainly is a game design thing because that needs to fit in with the plot and what the expected experience level of the player is and making the battles fun well that's probably a bit of both but that's still a game design thing - the types of treasure in loot well that certainly game design that's where you can potentially inject a little bit of humor into the game and the nature of the upgrade is also getting designed because we don't want to give the the player the most powerful weapons right at the start of the game however upgrades have a minimal impact on the engine all they're going to do is increase or decrease a stat supporting and maintaining in inventory though that's an engine responsibility and so is implementing the shopping system by drawing an admittedly blurry line between the game design and the game engine design we can start to see how to partition the project the player will mostly be interacting with the game through the top-down view and so that means we should probably start there so let's consider we've got the player-character and the first design decision I'm going to make is that everything is based on tile maps and everything that's interesting in the game is going to be one tile wide by one tile hi now I know that my player character can move in the compass directions north south east and west but some sort of environmental map will say where the player can and cannot go so for example if we've got say a tree here and a tree here and say some more trees why not yes those are trees told you well we know that these tiles well these are solid so even though they've got a graphic in them we'll mark them with a red outline to say that these tiles are solid locations the player cannot enter that tile and so this starts to yield some information about what we want to store in our tiles we're going to need an ID that represents the graphic that's displayed and we're going to need something to say whether it's solid or not now some of you will have seen some very similar ideas in the Cody self platform game and in fact that's where I'm going to start because I'm not going to reinvent the wheel and if you think about it if Mario didn't have gravity it would be a top-down walking about game or if Zelda did have gravity link would be falling to the bottom of the screen all the time they're actually the same thing so I'm going to exploit the fact that I've already created a tile map system with collision detection for this top-down role-playing game so this means we have a map in the background with static solid objects in based on their cell location this would imply them at anything that interacts with the map for example the player character is a dynamic object it can move around and this is where we stopped it with the Cody self platformer because we assumed we had one dynamic object which is the player character and the rest of the map was solid however in the RPG we're probably going to have multiple dynamic objects so let's say we've got a non playing character an npc well we know that for cut sequences and other things that we probably want to move them around so that makes them a dynamic object so let's not having a think about what a dynamic object is well we know that it's going to have a position somewhere in the world and because it's dynamic and we have a position it's very likely we're going to need some velocity - we don't know yet what the full extent of the dynamic objects will be capable of doing but we can probably make some assumptions for example dynamic objects probably cannot pass through all solid tiles how about what if the dynamic object was a ghost well or a bird it could effectively fly through the solid tiles so I'm going to create a flag which is a solid versus solid objects so that's sort of things in the map in the background but then I don't want my player character to be able to walk through other player characters at some times that could be quite rude so I'm also going to have a flag which is a solid versus dynamic and we'll see by manipulating these flags that we can extend the range of behaviors of what the dynamic objects can and can't do but let's extend this idea of a dynamic object even further by considering that all dynamic objects are interactable and I think this is an important distinction to make so if my player character walked over to the NPC and interacted with it something happens and this makes me think that somewhere we need to handle an event which is an on interaction between one dynamic object and another at the moment I'm really throwing ideas at the screen to see how things come together we may change some of this in the future but for now it's just to get us started now this does raise a slightly curious question how do we handle for example interactions with things that look like scenery so let's say we had a signpost in the map well that signpost is indeed part of the map and it's solid the player can't walk through it so it becomes a solid tile but we could also place on top of this solid tile a different type of dynamic object and this dynamic object will have all of these properties but most of them we ignore what we care about is the interaction so when the player interacts with this dynamic object it displays I don't know the name of the town or the direction to the shop we may also have other types of non-obvious dynamic object for example here and this one might be slightly different that instead of the player choosing to interact with it the player interacts with it by walking over it so in this case we would set the solid properties of this dynamic object to false it's not solid so my player can walk over it but when the player does walk over it there's an interaction and in this case this interaction might be to go and load another map let's say I have a another type of dynamic object in this case it's an enemy the dynamic object in this case is controlled via a behavioral AI so something else takes control of the position and velocity components to give some sort of movement behavior around the map and we can make an assumption that if our player character interacts with an enemy character then it's an attack of some sort but if our player character interacts with the NPC then it should be the start of a conversation it's a friendly thing and the third option here is of course that the enemy character can choose to interact with the player which again is an attack so I think at a fundamental level we need to decide whether things are friendly or not so I'm going to add another flag here which is it's the dynamic object something that is friendly towards the player so already we've got quite a few different things they're all essentially dynamic objects that can interact with each other but for example the signpost is is something static that cannot be moved around and cannot be walked over the NPC is again something that can move around by itself as is the the enemy character that can use an behavioral AI to move it around and decide where it needs to do and some dynamic objects are invisible to the player but perform functions because they're still interacted with in one way or another so even at this stage we can start to think about a class structure suitable for a role-playing game we know we're going to need a map and our map is going to have many tiles now I'm not using any formal notation here but typically if you're using something like UML you put a little star here to say this is a one-to-many relationship we also know that we're going to have something that's dynamic and we can start to tell already that something with inherits from dynamic is going to be a creature ie something living that's moving around so for inheritance I'm going to draw an arrow that way and we also know that something else it can also be dynamic of things like the teleport panels or the signpost so they're in some way some other type of interaction I don't know what we'll call these yet but that also is going to inherit from dynamic and let's ask creatures go we may have something like the player which is a type of creature which is dynamic and we may have a particular NPC which is a again some type of creature and so the interactable objects may have things like yes that the teleport oh the signpost and you might be thinking well why don't we just create teleport signpost NPC and players all separate things well the reason being is we can make all of our control and management code much simpler if we classify them all as the same type and this is really where the power of object-oriented programming comes in so let's say in our base class which is dynamic we have a function which is on interact when we implement a player subclass well the player doesn't really interact with itself so this probably doesn't do anything however when we override the on interact function for an NPC something may happen that's related to the current quest and we'll talk about quests in a later video but it could you know for example produce some dialogue on the screen or give the player an item when we interact with the teleport we know we can move the player to some other location and when we interact with a signpost we display information and the nice thing here is I don't need to code all the special cases all I need to do is provide the implementation for that particular object and because all of these objects are fundamentally a dynamic object I can store them all regardless of their subtypes in a single vector of dynamic objects which means all I need to do is call the on interact function and the compiler will sort out which particular on interact code to execute and this is called polymorphism which fundamentally means that all of these sort of leaf classes here the main subclasses share something in common they show this interface specified by dynamic yet how they implement that interface is up to the subclass this will become quite apparent once we start coding things up now even though I've just shown that we're really getting ahead of ourselves let's start with the basics let's take the platform game engine and convert it to something a bit more similar to what we want for this role-playing game and so here it is this is the one lone coda platform a game code I'll just run it to prove it and it looks quite similar to the video that went out about this engine and we're going to modify this to suit our role-playing game after all it handles all of the collisions between a dynamic object and the static background and so the first thing I'm going to change is of course the name and in keeping with the Nintendo Entertainment System resolution I'm going to use a 256 by 240 array where the pixels are four by four we will want to make some significant alterations to this code for example the original map was stored as a big string this isn't quite sufficient for a role-playing game firstly there's a lot more tiles in the role-playing game than there is in Mario so representing them all with characters becomes quite difficult but also there's not enough information captured here it assumes that anything that is not the period symbol is solid and that might not be the case for us a typical example being that the before we saw our player character walking across the grass and walking across the path so there isn't enough information here additionally editing these maps is quite tricky because it's not a faithful visual representation of what the map will ultimately look like also right now the level is part of the executable and this does have some advantages it can sort of be distributed as a single file but it makes it quite tricky for the game design team to include their changes so I think it's time that we start looking at the levels as being a separate file and a separate entity entirely and so I'm going to add an additional class and we'll call it RPG map and this is an important moment for the one lone coda channel because the first time I think that we've done a project that's included multiple source files so it's going to be a bit of a test for me to see how we navigate around all this I'm going to use the add class wizard just to two files a dot H and a dot CPP called RPG maps and we can see now it's created two additional source files however I don't want a class called RPG maps I was just being lazy and using it as a way to create the file names what I'm actually going to call it is C map and I'm going to use a lowercase C to indicate that this is a class of course I'll need to change the names of the constructor and the destructor we must also make sure to change these in the CPP file too now I'm not a fan of using setters and getters everywhere particularly for simple basic variables so I'm not going to in this case so if I want the width and the height of the map I'm just going to make them accessible directly by declaring them as public I'm going to either a function which is get index and this is going to return the tile index for a given location index and in Y so the user will request a coordinate and it will return a single number which represents which tile to display out of the tile map that's been associated with this physical map and we'll see a little bit more about that in a minute but I also want another one which is get whether the tile is solid or not in this instance I'm not creating the tile as a separate structure it's really not necessary but these two functions imply that I'm going to have a couple of arrays - I'm going to create these as private and this means they won't be accessible to anything other than inside the C map class and so my physical map is going to be stored as an array of indices and I'm just going to default that to nor pointer and we're also going to have a second array of billions will call that solids there are some additional public variables that I'm also going to need firstly I'd like to store the name of a map so what map is this location is it the village one is it a castle what is it and I'm also going to want a point - a one-line codice sprite which you'll have seen in many of the previous videos and this is going to be the imagery that is used to display inside the map it's going to be a pointer to it and we're just going to say P sprite now we can see that OLC sprite is not defined and that's because it's part of the console game engine so I'm going to include that up here so it gets defined now you'll notice that because of lots of bad practice reasons by including this file we've also just defined string and that's because this header file uses a using namespace STD you really shouldn't do it that way but in this case I'm going to justify it by simply saying I know I'm not going to be including any other package as part of this project the final function I'm going to add is a create function which takes a path to the external file containing the level data the pointer to the sprite and the friendly name so it populates all of our internal variables so let's give these functions some code in the map CPP file I'm going to just give all of my variables a default value and whenever the map gets destroyed I know that I've got two arrays so I'm going to call the delete function to delete those arrays for the get index function I'm going to check that the requested coordinates is within the bounds of the map and return the appropriate index for the array well so I'm going to return 0 on the one hand this means that the program will never crash it won't access memory that it shouldn't but on the other it will give a graphical glitch if there has been something that's gone wrong ie whatever tile is at index zero will be displayed and the game designers will probably quickly realize that things aren't looking the way they should another option is to return minus one here but I don't know how that get index function will be used later down the line and minus one probably isn't appropriate for indexing into a different array so I'll return 0 and it goes without saying that the get solid code looks exactly the same except it indexes a different array so let's consider the create function well the first thing that will happen is we're going to store the name and the pointer to the sprite locally so they're now part of the map class however we now need to load the file that contains the level data and I'm going to use if' stream to do this and to use if' stream I need to include F stream I think this is another first for the one line code a channel reading an external file well it's always good to make sure that the file was opened correctly so we know that the file name was given was proper so we can check using the is open function to see if that's true now if the file wasn't opened correctly we can return false so that gives some indication to the calling function that the file couldn't be found but if we did read the file successfully we're going to return true now some of you may be sent screaming II computers no no no no no this is totally the wrong way to do this and I agree what we should really be doing is putting error checking in at fundamental levels and I'm not going to do that because most of the video would then be about how do we do error checking so I'm going to make some assumptions that my assets are in the correct format and named correctly I feel that the code at the end of this will be more useful for study if it hasn't got all of the error checking stuff in here I've got a text file full of numbers and this represents a level in this case it's the the single house village scene you saw at the start of this video the first two numbers represent the width and the height of this area and after the width and height have been declared we've then got pairs of numbers which represent which graphic to use and whether or not the tile is solid now in this case that little village scene was surrounded by trees and the tree is represented by graphics index 9 let's just take a minute to look at a tile sheet so a tile sheet is basically a one line code of format sprite that contains all of the imagery required to assemble the map and it's indexed by moving along and checking what its width is so in this case its width is 10 and it's it's 3 high so index 0 is in this top corner and that's left so it's we go 0 1 2 3 4 5 6 7 8 9 so index 9 is this tree and by the way this folk sheet was created by Tom Elle on the disco server and this sprite viewer is a really nice tool was created by cross X on the discourse services thank you very much for that and the sprite view is quite nice because it allows you to zoom in and out and see the sprites at an individual level but also do some sort of analysis of what characters are there so knowing that index 9 represents this tree we can start to see that we've got a border of trees around the level however these trees are classified is not solid why is that well let me introduce to you another tool this tool was created by a tape from the discord server and it's a simple map editor for the role-playing game and I just want to say this is a really good example of how the community is coming together to create utilities to support this project and without them it just would be simply too much work for me to do on my own in the timescales that I have available and the sprite editor allows us to select sprites from the sheet that we saw before and place them around so I can place trees anywhere in the scene and we can assemble some interesting-looking scenes we see at the top we've got the coordinates of the cellar we're interested in now the file format we looked at before showed the row of trees with index 9 but it indicated that they weren't solid the map editor will allow us to specify whether a tile is solid or not and we can see by going into the solid tool we've got a little red rectangle in the top corner of each tile to indicate that it is solid so in this case the building is solid the trees that we've just placed aren't solid and also you can see that the door here isn't solid either that allows the player to step over the door but this top row of trees is also not solid I could make them solid but I don't need to because I know that surrounding the whole area is a solid wall the player can't get through to it anyway so that explains why our top row of the map doesn't have solid trees so reading data using if' stream is quite easy we can read the first two numbers simply by reading them directly into the width and height once we've done that we can create our two arrays solids and indices and because we know the width and height now we then just iterate through the whole file one element at a time reading in the appropriate number into the appropriate array so now we have our map base class but individual maps in the game are going to be subclasses of this class so let's create one for the first village so I'll create a class that inherits publicly from C map called village one and don't forget you semicolons and in the CPP file for the maps now because we've derived the village class from the base map class we just need to provide the constructor and in this constructor we're going to call the create function the first parameter is the path to the level file so that was the file that contained all of the numbers we saw before the second parameter is a pointer to an LC sprite now the constructor for LC sprite takes the path to the sprite sheet that we saw which in this case is located at RPG data graphics and it's called Tom l sprite sheet dark the third parameter is the name of the area and I'm going to call it coder town why not and so in this simple little bit of code we've created the whole map and it's self-contained we know that when Village one comes into existence it'll go and populate itself with the relevant data so let's go back to our main program now and include our map class so let's start making the relevant changes to get rid of the built in map information to start using our external maps and so I'm going to do that by creating a pointer of type C map to store a current map and I can do this I don't need to make this pointer of type village 1 because we're going to use the inheritance and polymorphic attributes of object-oriented programming to handle that for us and visual studio is very kindly showing us now all of the things that are wrong with the code so these are all the locations that we need to modify to suit the new way of doing things so the first change we need to make is looking at the collision detection in the platformer game if the cell was anything other than a period symbol it was considered solid that's not the case anymore now instead we want to look at our current map and we want to get the whether that's location is solid or not so we're going to use our get solid function of course we don't need to check for this anymore and so I can make all of these changes anywhere where we have a width and height of the level we also need to change too so in this case we can access these properties directly now and width and n height this was all of the code to handle the camera following the object on the screen we don't need to change any of this it's all completely valid however the way that we draw the map to the screen is now very different we still need to get an index that represents the tile and I return to type int now it's no longer a character I'll call it index but instead of this switch block we want to calculate the x and y-coordinates of that index in the sprite sheet so to convert from a 1d to a 2d usually we do it the other way around and we're going to use mod and div so our sprites X location I'll say int s X is equal to the linear index mod the number of tiles on our map which I know in this case is 10 and to get the spike tiles Y position we divide by 10 and it's important that this is all kept in the integer domain because this will give us the row that the tile is on because any information as after the remainder of this divide is just lost and this will give us the column that the sprite is on in the tile sheath now all we need to do is modify the draw partial sprite function with the new parameters so the x location is still the same that our width is still the same the tile offset none of that changes however the sprite does so that's now currently stored as a pointer in our current map piece sprite and the location we're not specifying by hand anymore we're going to use our new coordinates this is really nice because that means ultimately we can get rid of all of this which makes our drawing routine much more compact to debug this let's initialize our P current map to be village 1 let's compile oh dear we've got our first set of problems can you tell how this was all scripted if we look at the error information at the bottom and I appreciate it's a bit small fundamentally it says one or more multiple-- defined symbols found and this is something we've always been able to avoid by doing things in a single file for the previous videos we now need to think about things a bit differently in fact it's the console game engine itself which is causing the problem and if we look at the console game engine code right at the bottom we can see we've got three global variables which are used to handle the tidying up code when the user closes the application well they're not strictly global they're actually static variables that need to be defined somewhere and the problem we've got here is that our main program is calling the one lone coda console game engine file but also our Maps program is calling the file so the being defined twice and this is because in ordinary circumstances CPP files only get compiled once by the compiler but header files can be pulled in multiple times by whichever CPP file needs the stuff and things like this should be declared in a CPP file to ensure that it's only compiled once so it's time to make the console game engine object-oriented programming proof so I'm going to remove it and I've already done this it's actually not a big deal I will add in now what I've called OLC console game engine OOP and what we'll see is it's exactly the same file with all of the same information in except for when you get to the core engine file it's now slightly called at a different class it's just got the prototypes for all of the functions there is no body to it and these static variables that were causing us problems before are declared in the header file but they're not defined here they're not given any substance instead that's done in the CPP file where the rest of the console game engine functions are also filled in and this really has just been a cut and paste job there is no difference to any of the internal code or but at the bottom of the CPP file we can see we've now got the definitions of the declared variables so this means our main no longer inherits from the original console game engine is going to inherit from our object-oriented version and we must also change in our Maps dot H file to include the object-oriented version too and we can see now when we've compiled there's not been a problem we've only defined the symbols once and you'll see that this is a common pattern in object-oriented programming to have a header file and a CPP file where it's important not to do too much in the header file other than declare the things that you might want to use so let's see what it looks like well it's pulled in the map that looks good and we can see Jerry Oh from the platform game is still available and he can stand on the trees because if you remember we didn't make all of the trees solid so that means there should be an opening somewhere I think maybe maybe not so I can't actually get Jerry oh into the world but gravity is also still in effect which is something we don't want there we go so the map routine is handling itself it's drawing itself perfectly fine good but this brings about the secondary problem and it's a slightly complicated one and that's regarding asset management let's have a look at how we created that map in the first place to create the map we created a class called village 1 let's assume I wanted a second village called village 213 off go to maps and we go down to the constructor where we'll create the definition for village to assume this village to file but I want to use the same sprite data we can see here though that each village will reload the strike data and this is inefficient because I could have 20 or 30 villages in this game I don't need 20 or 30 instances of the same sprite information and just to make this even more different we'll just call this bug town the better solution would be to load all the assets we need was and use the assets were we need them and this means we need to break another rule of object-oriented programming we're going to need to create a singleton I've added another class to the project called RPG assets and this is going to be a single location that's responsible for loading all of the artwork and extra information that we need for the game I know that first start we're going to be loading sprites so we need the definition of the OLC sprite but I want to make this class a singleton which means the first time an instance of this class is created it's going to load all of this resources and they're going to remain persistent throughout the lifetime of the process it is in effect one gigantic global variable now there are some quirks to a singleton the first thing I'm going to need is a function so we can access an instance of itself and this is where things start to get a bit weird to create a public static function which is called get and that's going to return an instance to itself and you can see it creates a static local variable in this case called me and so once this is created it remains persistent here so it will always return the same reference to the variable me which is of type RPG assets so the first time this is called it creates the instance and then that instance remains persistent to ensure that this does remain persistent we need to do two more quite advanced things the first thing I'm going to do is get rid of the default copy constructor that's created by the compiler I don't want to create copies of this because every time I do it'll reload all of the assets again so we'll get rid of the copy constructor at the same time I also want to get rid of the load operator in this case it's equal so if we were assigning an instance of this to something else it would create a small copy of it we don't want to do that for the same reasons we've already loaded the sprite once and this is quite a common pattern for declaring Singleton's to make sure the user uses it as a singleton we can get rid of the constructor by making it private we might still want these things to execute but it means the user won't be able to directly create an instance of this singleton and as part of this singleton I want to store a container that stores all of the sprites and I'm going to use something we haven't used before on this channel I'm going to use a map and a map allows you to pair up a key with a value and the type of the key is going to be a string and the value in this case is going to be a pointer to a sprite and we'll call this M map sprite I'll need to include map at the top of the file the map is a little bit like an array although far less efficient but potentially a lot more useful instead of using numbers to index the location in that array we can use other objects and in this case because I know that we're only going to be accessing sprites relatively infrequently by accessing the point of this fight infrequently but I don't need to worry about the performance hits that that would involve and the benefits I'm going to get from using a map here is I can use friendly naming conventions throughout the whole program which means if I do end up having other people designing parts of this they can stick to this friendly naming convention and the engine doesn't need to be altered and this may still seem all a little bit weird but once I put this function in here which is get sprite you can see that we apply a name and we're using the name as the index to the map so it works in a very similar way to an array but it's a lot more sophisticated to our assets class I'm also going to add a function which is load sprite so let's go and implement the body of this function here I've got the constructor in the destructor and here I'm going to implement my load sprites function and this is where I want to do the single one-off load of everything that I'm going to need for the game I'm going to start by defining a little lambda function called load which takes a friendly name and the file name to the assets that we're trying to load and in this lambda function the first thing that happens is we create the OLC sprite using the file name we get a pointer to it and then I'm going to store in our map using the friendly name as the index that pointer and the reason I want a load function like this is I can now easily load new resources so for example let's say we take our village map that we had before I call load and I'm going to create an asset which I'm just simply going to call village and I'll pass to it the file path to the spritesheet that represents all of the tiles and that's all we need to do so wherever we want to use the asset that represents this spritesheet we're just simply going to call our get sprite function with this friendly name and so in this function we can start to load all sorts of assets we know they're only going to be loaded once we'll need to load the assets at some point so we'll go back to the main file now and include our assets class I don't need to create an instance of it somewhere because it's a singleton so I can go straight to the on user create function RPG assets remember it's a method directly applied to the class in this case we're going to get an instance of it and we're going to load the sprites so at that point we have now loaded all of the artwork for our entire game I can get away with this because this is a small game I can load everything at once the memory footprint will be minimal for really large projects you probably do spawn some things a little bit more sophisticated and loads things as and when they're needed my singleton has now loaded all of the sprites for the time being I'm going to leave in the Jerry oh spike because we'll handle that when we start looking at dynamic objects in the next video but let's go back to our maps now we no longer want to load the sprite here instead we want to use our asset singleton so in the maps header file let's include our assets and all we need to do here is instead of going directly to the file and creating a new instance we can go to our PG assets get an instance of it and get the sprite and we gave it the friendly name village and that will return the pointer to the one instance of that sprite sheet that we've got in the game we'll do the same for the other village so we're no longer duplicating resources coming up to the end of this video now so I'm just going to make some tide modifications to make it so we can move cheerio around a little bit more sensibly so let's take a look so here we've got our map loaded in the background we've got a Jerry oh and we can move Jerry around he can't go over solid objects he can fit into narrow gaps and we know that all of our resources have been loaded in an efficient way I think we'll do one more thing before finishing this video and that's showing larger text on the screen you know that this is a console and displaying text is what it does naturally however this resolution the text is very difficult to read so instead what we're going to do is create a sprite sheet of a font and display that font appropriately on the screen whenever we want to display text so using the sprite editor again we can see I've created a sprite which is a font and it's a font that's very faithful to the original Nintendo Entertainment System where each character is an 8x8 array of pixels black and white and they're also stored in ascii order so a is 65 in decimal for capital a so is 66 67 68 etc etc and so the location of the index of this sprite ties into its ASCII location and this is quite important I'm going to write a function to the main class called draw big text which is going to take a string of text and a location of where to draw it on the screen and in a similar way to drawing the map before I'm going to iterate through all of the characters in the text using the ASCII value to give me an index position of where I can source the sprite from the sprite map so it's exactly the same before it's a you choosing an SX and sy value using modern div but in this case it's scaled appropriately according to the sprite sheet and for ASCII so the sprite sheet really only started at ASCII character 32 even though that's in position 0 so that's why we've got a little offset there and I'm going to draw the character using the draw partial sprite routine in the place specified by the x and y coordinates however we've not got this sprite font variable so let's add that in to gratuitously cut and paste here but where do we load this well of course it in our assets if we go and have a look at the assets we've got one that's friendly called font now you might think do I access RPG assets and get an instance here well no because I'm going to be calling that a lot and accessing a map does have a bit of a performance overhead so because this is a variable that I'll be accessing very frequently what I'm going to do instead is cache it and that's why I've created a local variable here so let's go to one user create and once we've loaded the assets let's populate that's the font sprite variable and it's RPG assets get the instance dot get sprite font and helps have you put a capital A at the start and let's test this by after drawing the player let's draw some text on the screen somewhere draw big text and we're going to pass the string hello everybody and we'll draw that at location 30 comma 30 let's take a look and we can see we've now got big text on the screen which is very readable for the player in this video we've looked at how we can load resources and make sure we've only got unique instances of those resources we've considered how object oriented programming is going to help us develop a rather complicated and large game engine and we've looked at how do we partition the work between the programmer and the game designers in the next video of this series we're going to start looking at the dynamic objects how do we actually make the game a playable thing and how do we coordinate the interactions between objects as usual if you've enjoyed this video a big thumbs up please have a think about subscribing because I think this series is going to yield a video that's really quite entertaining and hopefully there might be a full game and I'm really pleased that the community is showing a lot of interest too so take care and I'll see you next time
Info
Channel: javidx9
Views: 155,693
Rating: 4.9642577 out of 5
Keywords: one lone coder, onelonecoder, learning, programming, tutorial, c++, beginner, olcconsolegameengine, command prompt, ascii, game, game engine, role playing game, rpg, code it yourself, code-it-yourself, object oriented programming, oop, singleton, assets, sprites
Id: xXXt3htgDok
Channel Id: undefined
Length: 50min 36sec (3036 seconds)
Published: Sun Mar 18 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.