GameMaker Studio 2: Ghost Recording Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody today we're gonna be taking a look at recording and then playing back a player's actions through the form of a player ghost okay so you can see here I've got my little dude in the context of a platformer although pretty much any game context works we use platforms that's what we usually use and if I press you notice this little green guy running around here kind of imitating our players movements something I recorded earlier if I press f2 this little record thing comes up and I can like we're gonna do a little jump run to this corner and I'll just jump like three times there for example in press f2 okay and then if I restart the game we'll find a new go some Incred and it will play back exactly that sequence of actions and what I've now done is actually created that as a file we stored that as a JSON file that we can play back whenever we want in in pretty much any contacts okay so you might want to record particular difficult sections or difficult concepts in your game to play them back is kind of like a tutorial for the player cares a few different games I've done that kind of thing in the past but you might also want to play back the player for a number of different reasons such as like a speed run ghost that you've recorded of the player or or a developer ghost for that matter for things like racing games or even for like super fancy mechanics like the shadows from braid that sort of play back what the player did when they when they did a rewind or something like that there's all kinds of different uses you can imagine for this kind of thing before we get started I do want to give a huge shout-out to Thomas I cannot pronounce his Twitter handle so I'm not gonna even try but I'm gonna put it on screen for he who has graciously allowed me to use his sprite pack for this particular tutorial and the source code for this episode will be freely available to download along with the sprites that have made freely available for you to use by Thomas but if you want to make further use of this awesome template character you should go and check out the full pack there's a pack available with animations for this character with a bunch of different types of weapon animations rolling animations crouching ladder climbing and all that kind of fun stuff there is a pretty steep discount for that pack right now it is on sale for I think about 10 days from when this video goes out to my patreon supporters and so probably about three days after it goes live on YouTube so go check that out it's a really great resource really well put together each animation even has its name especially prepared for game maker so you can just drag it straight into the IDE and or recognize and split up the frames automatically which is super awesome and honestly these animations not just as a great resource in and of themselves but they act there's a pretty good tutorial on each particular animation and how that sort of thing should and could look anyway that's that plug over I've not been paid to say any of that by the way he's just done cool work and has helped me out and I like helping cool people out so there you go so the first thing we're going to do is create an object that records everything our player does in here so I'm going to create a new object I'm gonna call it Oh recorder alright it doesn't need a sprite or anything like that it's gonna be invisible I'm gonna add an event I'm gonna add the create event and let's maximize that's perfect well I think that's nice big so we can see what's going on so in the career van as usual we're just gonna clear some variables so I'm going to say variables the name of this event and their core ghost record I'm going to declare ghost record as false okay and that's just gonna be the variable that decides whether or not work currently recording ghost record frames equals 0 and ghost record less equal TS os create so this is gonna be the number of frames who currently recorded we're literally gonna record every single frame okay and this here is gonna be the list in which we store all the information about those frames where the player is what animation they're in watch Direction they're facing them and anything else that's actually important for us to know okay next up because we've created a DS list are very important for us to also add the cleanup event data structures that's what we're cleaning up we've created es list so we want to make sure if this object ever goes away we deal with that D list and get rid of it so don't create a memory leak hey just for safety as well we'll check to make sure that this list actually exists before you destroy it so Dipti X exists ghost record less Houma yes time less okay so if there's a data structure and it's called that and it is a TS list okay and and that and then if that's true yes list destroy open bracket ghost record yes okay simple as that that's let's set up done for the recorder next thing I'm gonna add is gonna add open invent hitch by right-clicking code window step step event okay us and let's know going so what do we want the recorder to actually do well first of all we're just gonna have four records we're gonna have two sections in here one for toggling the recording on and off I'm one for actually doing the recording if I could name them right now record each frame so those are the two things that we're going to be doing in here so toggle recording that's obviously going to depend on your game but for this example I'm just gonna say we press f2 alright just to report it so if keyboard gank press over I get V kf2 game that's the f2 key then we're gonna start recording so ghost record which is like boolean we just made it's gonna equal the opposite it's also not ghost with corners exclamation mark ghost record so if it's true it'll become false and if it's false that have become true very very handy way to invert a boolean that next up if we are already recording then when we toggle it off we want to save what we've recorded into a file okay and this may seem like skipping ahead a bit but isn't what we get this done now so stop recording and save so if not ghost record so after after the toggle has happened if not ghost record so that means if it's false and yes exists ghost record less yes type OS okay so if we've just turned it off and the list of things for us to record still exists so those of you who have seen my previous JSON saving a loading tutorial this bits gonna look very familiar what we're gonna do is create a JSON file and to do that we need to wrap our des list into a DES map okay because it just makes the saving loading process pretty easy if we wrap everything if we wrap everything into a route DS map okay so I'm going to find bar underscore wrapper and this is gonna be our route map yes underscore math underscore create TS map and list okay to add the list to the map specifically for the purpose of creating a JSON underscore wrapper as the mapper adding to and the list we're adding or sorry the key on which we're adding this under is a root coma and the the list that we're adding is ghost record list if I'm starting to lose you at this point because you're like not really super familiar with DS Maps or JSON files and they're really not I'm talking about this stuff I really highly recommend going and watching my video on saving and loading with JSON that explains working with these files in a simpler context of just saving and loading okay and honestly I'm mostly repeating the same lessons in this particular video just to show you how another way of applying this all a song saving and loading stuff again so once we've added the map to list what we want to do is then encode this DS map okay so I'm going to type in var underscore the locks because it's just everything JSON encode wrapper so what does it mean to encode it what that means is we're taking this DS map which now contains our DS list and wrapping it into the JSON format so it will just turn it into a really long text string okay so by this point in the code by line 11 by the lodge is going to contain our super long text string that contains everything that we wanted to record it contains this entire list ramped within IDs map ok so now that we have that we just need to save it as a file so if file exists recording dot JSON which will be in the app data folder for this particular game file delete recording don't JSON okay so there's already one there let's get rid of it buh underscore record file equals file and store text underscore open underscore writes recording dot JSON so then that creates the JSON if it doesn't already exist which we know it doesn't exist now because we checked if it did and deleted it so I'll create a new file called recording JSON then file underscore text on the score right underscore string record file comma the loads okay so we need to underscore those law okay so then that writes all this about that huge long string that we're gonna have in here from the JSON encode into record file okay then all we need to do is simply close the file again so file tanks blows record file so we're done with it and then we can get rid of the wrapper and this is what's really useful as well if not destroy underscore and the really handy thing with this is that when you have a data structure created in this way where you've got a deist mount that's storing lists within it and then those lifts maybe contain maps and so on designed specifically for JSON handling if you destroy the root map it will destroy everything else in a cascading effect okay and it'll free up all of that memory so you don't have to worry about memory leaks and so on and going in and cleaning up the list you've just created and cleaning up the the contents of the list of each list contains a map and so on so forth cuz that would be a lot of work so it does all of that for you it's super super useful okay so that's our toggle for turning on and off the recording now I need to make it so when recording is on we're actually recording anything right so that's come down to here where we were and record each frame I'm gonna type a ghost record so if our recording is on instance exists Oh player so you know there's an object to actually record right hole or whatever you want to record so if this exists not DX exists that is ghost record list yes hi les okay so if this data structure doesn't exist because maybe we destroyed it when we stopped recording a previous one we need to create it and I'm gonna set ghost record brains to one and it goes record list to equal DF list okay next up just assuming all this is true and then we know there's a list waiting for us to record into you record this brain I guess that's kind of a similar comment but whatever haha bar underscore frame to record equals yes ma'am create okay so we're gonna store each frame as a DDS map so with O player let's get the info that we want to save so underscore frame to record and I'm just going to use the shorthand accesses to into stuff into this array of not array DF map so if you don't know that what you can do is from a dismount DF Maps work by pairing a piece of information or a variable date or etc with a key that key being a string name or something so I could have a value called food like cushions and the entry could be two etc okay so a shorthand way of using DS maps is to open a square bracket once you've type the name of the map and then a question mark symbol and then the name of the key that you want to modify or add to the DF map in this case the X is going to be the name of the string and it's going to store the x position of our player and then close the square bracket you can just head out to equal something and then that will set that key of this DF map to equal whatever you put here okay useful shorthand rather than having to use IDs map set and then type in everything like that would that function okay you can just do it like this so for him to record X is going to be the x position of our player remember with in our a player so we're getting variables from the player object frame to a record a question mark y and equal Y and then I'm just gonna paste in the rest of these real quick okay because they're all the same you don't need to see me type that out like five times in a row uh-huh but what we're storing is a key called X scale we're just storing our image X scale a key called sprite and we're just doing a sprite index and image which is storing our image index okay and we're gonna store that about every single frame you might be wondering at this point as well we'll talk a bit more about this in a bit whether or not this is gonna be super expensive like I'm Ramon Rick I'm recording every single frame on restoring all this information about every single frame isn't that just gonna mean to like a really huge file and stuff and you're gonna be surprised it actually takes a very tiny amount we forget how big kilobytes actually are so yeah so that's the stuff we're gonna store I want we've done that we're gonna add this map to our DS list okay first of all we do that just by doing D s list add ghost record list let's go frame to record and then we do D s list marked as map gauche record list yes lest sighs ghost record less - one close bracket again semicolon so that finds the list we just added to the map in the list and marks it as a map for the sake of doing JSON don't ask me why you have to do this when adding a map to a list whereas when you add a list to a map you simply do D s map add list I don't know why that's like one nice function for doing it there and with this you have to add it first and then mark it don't ask me don't know but you do that's how you that's how you have to do it again and then once we've done that I'm gonna type ghost before Reims plus plus okay because then we're gonna record the next frame locally because we're adding Lee if the deal is we're gonna add them in order of frames okay so that's not gonna be a problem for us but just to track how many frames we have recorded um I'm gonna keep increasing this value by one each time alright and that's it that's gonna so that's let's us toggle the record up here and also save the file out and also perform the recording every single step okay so I'm just gonna add the draw GUI event real quickly just so we can try this out and I'm just gonna paste in this chunk of code you can pause the video if you want to add this in yourself it's kind of unnecessary it's just to put a little circle in the corner to show is when we're recording just so it's super clear then I'm gonna follow the step that I always forget come to the room itself and I actually put a copy of OU recorder into the game okay and then I'm gonna run the game just so that just so we can do a little quick test record obviously the thing to playback all recording yeah but just to do a little test record just so that we know later on of what it's playing back is what we recorded so I'll just you know go up here cuz I started down here and there prank f2 you see that comes up in the corner and I'll do some jumping around up there down here and all like jump twice in this corner just so we can see how they press f2 again and then that's gone so that's recorded now in fact if I pop over to my user Shanti is at the local ghost lunch with has to be the name of the project the folder you can see recording Don Jason's in Korea ec it's 44 kilobytes that's really I mean obviously there's a really short recording but even with a much larger one like you could go on for quiet some time recording stuff and possibly only have it be like a megabyte or whatever which is I think it's really good really really manageable so don't worry too much about recording every frame being super expensive it does get more expensive if you store more things we're only storing up to like four different possible sprites position and like our X scale you might have lots more stuff to store about the player you're recording but I think it scales pretty well I think you can you can get quite get away with quite a lot and have this still be a very manageable size here's a JSON file but if I just open it with just like a text editor or something just in sublime text over here you can see if you just don't mind it'll look the same in notepad or whatever you can see it's just stored as a really long string just a ton of DF maps in list and a comma separated list of every single frames it's got you sprite your X scale your X and all that good stuff okay okay so we've got our recording we're able to record and if we were to make new recordings it would overwrite that recording and so on and it creates the file how do we then read that file back and play back the recording in our game well I'm gonna make a new object for this and it's gonna be OH ghosts create object Oh ghosts I'm gonna set sprite um too much the I yeah she doesn't really matter no I think about it cuz it's gonna get the sprites entirely from the file but just for reference um just makes it easier to look at in the objects list I guess I'm gonna make it match the idol sprite next up I'm gonna start with the create event as usual let's maximize that 12 got some space and the curie event is gonna be all about loading but goes later okay and start up for this is as follows and this have frame 2 equals 0 cuz that's gonna be the first frame you wanna play is frame 0 right image underscore blend is gonna equal the I'm just gonna have like a bluey-green blend on the sprite just so that we can tell the ghost apart from the actual player and then we're gonna get the name of our file which is ghost final name equals recording dot and JSON semicolon then we want to load the actual data from that file so I'm going to load data if file and the score exists a ghost file name I think you can guess all that goes so if the file exists ghost file equals file and just go to text let's go open underscore read Open bracket goes file name this is opening a file just as before but this time for reading information rather than writing information ghost data a root is gonna equal JSON underscore decode this time open bracket file tanks need string open bracket ghost file always try to close bracket semicolon okay so that's going to take that well this function here gets first of all that huge long string from our file and just returns it as a string but it's returning a string into JSON decode so that means JSON decode is gonna take that string and turn it back into a DF map that contains a DS list of those DS maps of each individual frame okay then that's obviously wrapped inside that wrapper that we that we use that but original DS map we want to get at the DS list that's in that map so I'm gonna climb ghost and painter equals and ghost data routes and then again just using our shorthand for dealing with a DES map question mark root that's where we stored it in the first place next up now that we have the list us work out how many frames there are just by counting the number of entries in the list so ghost frames equals des underscore Lisp underscore size goes data then you go on and ghost file equals file tax close open bracket ghost file very cynical okay because that's what we've we've got the list of frames we've got the number of frames we don't need anything else from this file so close the file if that file doesn't exist at all to create this ghost at all then this ghost isn't gonna really be able to do anything useful so let's just else instance destroy yeah okay all right so we have all the data now now it's just a matter of actually playing that data back okay so I'm gonna right click go to an open event and the regular step event and in here this is where we're actually gonna play back the recording ok so if brain is less than a ghost frame so if we've still got frames left to render right if frame equals 0 image alpha equals 1 that's gonna be important because we're gonna do like a little fade-out thing towards the end and then just play it again infinitely you might want to handle it differently but I'll leave that to you and so I'm gonna set that up just to help us later when we um they are alpha route frame data equals a ghost and data and this time we're using shorthand for a DS list rather than B's map so with this map to use question mark and with a DS list you use this little a vertical line symbol for me it's a pressing shift and Bank slash gets you this symbol if you can't find that on your keyboard you can also just use a DSS find value and then type the name of the DS list which is ghost data and the position which is gonna be frame okay so that will that will work just the same obviously rain data you want to do that a frame beta equals that so that that will work but if you want to use the shorthand you can just write the name of the DS list which is ghost data this little symbol here after a square bracket and frame okay so those two lines do exactly the same thing okay so it's just another way of writing it's just a shorthand version of this I'm just gonna leave the shorthand version in yes sure okay so we've got the data route so that's now what's in here is a particular DS map representing one particular frame that we've recorded so now we can access that DF map and get back or expositional wide position or X scale or sprite in our image okay so that's what I'm gonna do x equals frame data absque where bracket question mark X and that's gonna get our X back out then the exact same for y some racket question mark Y square bracket semicolon and image X scale equals frame data question mark X Cal and the rest okay so yeah also our sprite index is from Sprint and our image index from image okay and that gets back everything we need and put plunks it all straight into those values okay once we've got that all we need to do is increment our frame so that the next time around we get the next frame so frame plus plus okay very quickly just an increment of value and obviously also keyframing for frame plus plus one yada yada does the exact same thing okay so she's gonna add one and then we're gonna keep cycling it okay and so that's really all there is to it in terms of playing actually playing back the recording so what do we do if our frame is not less than the number of ghost frames so we've run out of frames to play back so we can else this and say image alpha equals max image alpha - mopping or not - 5 0 so we just have a really slow like fade out over time if image alpha X 0 set frame to be 0 and then we'll that will just mean we go back through the data and play it back again okay you can obviously do whatever you want last thing of course is to make sure when we're done with this object by whatever means we clean up the information that we've gone so and your cleanup step we're gonna want to make sure you do is a DS map just draw the ghost data route okay that's quite important so go state a remember is what you decoded the JSON into okay so what's important to recognize is this variable doesn't actually contain all the that information that like that whole thing it just contains a pointer to where that now is in memory okay and the same goes that goes state a here and that like the DS list and also each individual frame which we cannot even put in a particular value although when we get them here like like our frame data for example when we get a particular map out that's my tree getting all that information and sticking it in that variable just getting a pointer to where it lives in memory so it'll just be like a number awesome thing so those variables themselves don't need cleaning up in that regard because they don't contain like all of that data we just need to destroy the original to structure the original structure in memory by telling the F Matan destroy where it lives it lives at whatever that points to right and then when it destroys the route 1 it has a cascading effect and will destroy and cleanup all the other ones very very useful okay so a final step come to the room go to resources and drop oh ghosts somewhere in the room doesn't even matter because it's gonna take the exact position from our recording so we should now see when we run the game we have a little ghost up here where we recorded does I jump up here it'll come down here and jump like twice in this corner over here there we go that's what we record it and I can even now and he'll fade out really really slowly and he'll repeat the process again over there you can see spawns does the exact same thing but I can also write over that recording then just press f2 and you see it's recording again I'll just do a little jump jump up here and do a big jump over there stop recording and now it won't get it right away because obviously goes to the only record gets that recording when it's created so it's obviously not gonna replace that right away but if I were to close the game now run it again we'll see our new recording now I am doing that it runs up there does this thing cool they have it ghost recordings thank you once again to Thomas for helping out these sprites and making them available feel feel free and encouraged to check those out and as I said it's a free pack you can get we using just the sprite I've used here including some cool like background sprites and stuff he's done like like some walls and ladders and things like that you can climb let's go check out that free paint you can obviously also get this price just from downloading the source code for this tutorial but also go check out the full pack he's done because there's loads of really cool animations in this style here and they're really really good thanks guys hope you enjoyed this one and I'll see you later a huge thank you to my patreon supporters for selecting this topic and for funding this video a huge aisle in particular and in no particular order to Andrew Gilbert Arthur Kyle Wanderlei bauzá blue dog Bert et de kodanda go Dan Erik Matthew Hibbs James grimly Jason Macmillan Kim Huff's novel anthe malcolm mark Lintz matte coat michael ward Mike Kb oh and Morgan Patrick goofy penguin muffins Robert churches Rove and darlin run Stephen Hagen to buy a Schulten turtle time Sofia flame and Zen unmei thank you all so much I hope you enjoyed this one I'll catch you guys next time
Info
Channel: Shaun Spalding
Views: 14,253
Rating: undefined out of 5
Keywords: Game Maker (Video Game Engine), Tutorial, GameMaker Tutorial, GameMaker, Game Development, Indie Games, Tutorial Series, Game Maker Studio, Making Games, How to make games, GameMaker Studio 2, GMS, GMS2, ghost, race ghost, recording inputs, recording
Id: 6-CgMJfL7RI
Channel Id: undefined
Length: 29min 53sec (1793 seconds)
Published: Fri Nov 30 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.