Build a Multiplayer Game with JavaScript & Firebase

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video we're gonna be building a multiplayer game using javascript and firebase if you've never heard of firebase before it's a hosted real-time database solution that offers many features you need to create online multiplayer games it makes it really easy to implement real-time live updates it's backed by google it's well supported very stable i love using it let's take a quick look at the game that we're going to build in this video it's pretty simple but you can take these concepts and apply them to whatever game you want to make there's going to be this room here where players can join and navigate around with the arrow keys you can name your player and choose your appearance at the end we'll add coins that randomly get added to the world and then you can race your friends to see who can collect the most coins we're gonna build this whole thing from start to finish with just vanilla javascript and the firebase library as always you can take these concepts and apply them to whatever front-end framework you like to use but first hello my name is drew i make videos about game development on this youtube channel some are tutorials like this one others are more devloggy just talking about things i've learned by making games if you're interested in any of that please subscribe let's get started so let's start by taking a quick look at the project that we'll be working with today here i have a new project on my machine and it's pretty minimal but we'll just walk through it quickly here so i have an index.html file with some basic information in the head tag like meta tags and a font that i'm bringing in from google fonts i link to one style sheet here called styles.css and we'll see that in a second the body has just this one div in it right now the game container and that's basically just centered in the middle of the screen i have some commented out ui that we'll bring in as we go this video is going to be kind of a combination of live coding and just quickly bringing in elements basically because i want to focus on the firebase stuff that's kind of what we're here to talk about but as always the code is all linked below so you can check it out there for more detail i'm linking to this app.js file here and that's where most of our work is going to happen let's just take a quick look at the style sheet now so in styles.css i have some basic rules on the html and body tags things that reset some spacing add a background color bringing in that font and then centering the game container in the middle of the screen let's see what this looks like so far here's our scene we have our game container it's using a background image that's being loaded in here and then we have a set width and height that match that background image so if you change this out with your own image you can update that part the image is pretty small on its own so we're scaling it up by three times and then because we're using pixel art we can utilize this image rendering pixelated to retain crispy nice looking graphics here we have some basic styles for some of that commented out ui that we'll bring in in a second it's basically just some basic form stuff to make it look a little bit nicer so let's include firebase into our project now at this point we need to actually set up an app within firebase like create a new project it might involve you signing up for the service and that kind of thing i'm going to do a screen recording of that process now and it's worth noting that firebase does have paid tiers but everything we're going to do today we're just going to use the free tier and that's going to be more than enough so first we'll go to firebase.google.com and you should see the landing page here if you're logged in with your google account you'll see your avatar over here and you can click this go to console button if you've been here before you'll see your existing projects i'm going to go ahead and press this add new project button we can name it so i'll say something like multiplayer demo say continue it's going to ask if you want to add analytics automatically to your project i'm going to opt out of that now but feel free to research this and figure out if that's something you want for the tutorial we're just going to say no now this might take a second i'm picturing a lot of beeps and boops happening in some server somewhere okay and it's ready so i'll go ahead and click continue we're redirected to our console page i guess you'd call it the first thing we need to do is go into this real-time database section here and enable the real-time database for this project that we created inside firebase so i'll say create database and you can choose your zone us central works for me just for now you can go ahead and start the project in locked mode we'll talk more about that in a little bit okay and now here we've been redirected to the realtime database viewer page and this is essentially our json object type of thing in the cloud and so this is what our javascript game is going to talk to and use the next thing we're going to do is configure some authentication types so go to this authentication page click get started now firebase offers a ton of different options for authentication they've even added more since i've been here last this is really sweet all the stuff they have but we're going to use basically just this really simple one called anonymous so i'll click that and click enable here and you can come back here and enable like opt-in to other ones as you want them but this is all we're going to need i think so we'll say save next we need to add our javascript configuration so that our web page can actually connect to this firebase instance so we'll click project overview it has a few icons here for other platforms you might be using but we're using the web here which is cool you can use unity that's awesome web and then here you can give it a nickname click this register app button and here's what we wanted it reveals all this code that we can basically copy and paste into our project now there are two main options it gives you for including this code and they basically do the same thing but there's just two kind of different usages of them so if you plan to use this kind of concept in a quote like real build system with common modules and that kind of thing here's the npm option where you can npm install the firebase library into your project and then copy over this block here that's going to give you all your configuration stuff by like importing the correct functionality and that kind of thing again this tutorial we're saying real basic so we'll probably just use the script tag option here so i'm just going to grab this and we'll put it in our project okay so back in the code i'm going to go ahead and paste in some firebase configuration this is going to look really similar to what we saw in the firebase console but i've made some changes here and i'll explain that in a second so these days firebase is really designed to be used as an npm package just like we saw on the console before because of the simplicity i'm trying to keep with this particular tutorial i'm opting into just using script tags they've really broken everything up into modules so you can just opt into what you need which is kind of nice first we start with firebase app which is just kind of like the backbone of everything then we're going to bring in the authentication part which is going to allow us to log into firebase and then be authenticated to actually write data to it and read data from it we're going to be wiring up to that real-time database and so to use that functionality we need to include this firebase database partial also then we have that same script block which just configures firebase this is exactly what they gave us and then i'm popping it into firebase.initialize app and then pass it in that object let's take a look at app.js now and see what's in here basically i've started us out with just a few helper functions throughout this project we're going to be doing a lot of pulling random values from arrays things like spawning in random spots and we're going to be adding coins in random spots a few other things too so i have this helper to set up for us it just takes in an array and then returns a random member of that array similar to the pizza legend series we're going to be dealing with grid coordinates a lot x and y values sometimes we're going to need those as a string kind of sandwiched together and so i have a helper here that just takes an x and y and returns it as x x y finally we have this blank function that fires off as soon as the page loads this is where our work is going to happen so the first thing we're going to do is have our game log into firebase using this method here it's called firebase in their auth library a method called sign in anonymously so our database is going to be configured to basically not allow anybody to read or write from it unless you are signed in but we don't want to do the whole like email password thing for this particular video just hitting our domain is going to be enough so if you've landed on your web page here and loaded up the firebase javascript library firebase will kind of manage your logged in session for you that's going to protect us from like random bot attacks and that kind of thing so let's go back into firebase and check out the security rules so from the realtime database page here you can go into this rules tab and here i have security rules set up for this project now this is demo code only there are definitely things about this that aren't very robust and we'll we'll see that so when you're working on your real project you should really have the rigor to research all these rules and make sure everything is tight for your project this is really just for our toy demos sake but what we have is our basic rules object this is like a firebase specific kind of language that they have you write in you can look up the docs for better examples but we're saying as long as you're authenticated then you can read any of the data that's in here that's fine by default you can't write anything so randos on the internet can't just like write whatever they want we're going to have a players node in our database within the player's node is going to be a unique id firebase is going to give us this id when someone logs in you get like this wacky string that's unique to you that's going to be your id within the player node we're saying you are allowed to write data but only to your player node so you must be authenticated and your authenticated id must match this user id finally we're going to have coins too that appear on the map and we're saying here that anybody can basically write those coins because as you collect them you're going to be able to delete them which involves you modifying this coin kind of node again there are some imperfections there but this is going to be fine just for our demo sake and i'll have this whole object as part of the code download link below so back in our code here we're going to let this line fire as soon as the game boots up it's going to try to log us in anonymously if anything fails we can add this catch block and this is good to get in the habit of doing so if anything goes wrong an error will appear and that error has some information for us like a code on it that kind of tells us what happened and then a friendly error message if you wanted to show that to the user for example in our case i'm just logging it to the console say you skipped the step of opting into the anonymous login method like the thing we turned on earlier you'd probably see an error for that i don't expect us to run into any errors with what we have so far though now before we fire off this call to sign in anonymously we want to have an authentication listener set up too and so this is kind of the way firebase has you do it i'm going to add in another method from auth here it's firebase.auth on auth state changed and as soon as it changes we'll get a user back so let me close this up and here i can just console.log user and the pattern here is basically if you got a user back then you know that you're logged in but if you like logged out or something happened to your session then this callback would fire but user would be null and so in this case you're logged out so again the flow here is that when the app boots up we're gonna listen for auth changes and then we're gonna trigger an auth change by signing in anonymously and then that should cause our inner part here to fire this is the clear signal that we are logged in and ready to start reading and writing data here in our game if i pop open the console and reload you'll see that console log fires our user is this like really complicated object you can spindle through here and see everything that's in here the thing we really care about is the uid this is that unique string that's unique to me this is going to be our player id so here we're going to start scoping some variables to this inner function here so i'm going to be ready for player id and i'm also going to create something called a player ref we'll talk about that more in a second here and then when this user call fires i'm going to go ahead and populate those values now so player id is going to be user.id that's the thing we just saw in the console and next we're going to set up our player ref a ref is how you interact with a firebase node and so in our case our player that we're logged in as is going to be its own node in the tree we're going to have a reference to that node and then we can update it like change our name change our position change our color of the character appearance we have we can also delete ourselves from the tree when we close the browser and exit the game all that happens by interacting with a ref here and so the way you set that up looks like this firebase.database.ref and then you give it a path to the node in the tree we're going to be nested under players here this doesn't exist yet in the tree but as soon as this function fires or as soon as we write data to this ref to the first time it kind of creates the deep path so it'll create the player's parent for us and then it's going to create a node for our player id we'll see that in a second so to write the data to our ref we can say player ref dot set and in set you can pass it an object or a value say it was just going to be like a string or something you could just do a string here but we're going to be a little bit more complex than that so i'll start a new object we'll give our player a name and we'll just say drew for now even though we're going to change that pretty quickly we're also going to have a direction that we're facing and that's either going to be right or left so i'll say right a color can be blue we'll give ourselves an x y so i'll say like x y i'm just making these up we'll start with zero coins for this player we'll cover the coins kind of at the end of the video but i'm just sort of laying some architecture for it and then of course one thing that's going to be really helpful is including the id also within the object so i'll say id is going to be player id and i already messed this up this should be uid instead of id so when i reload our page now nothing visually has changed of course but under the hood we've done that command to write data to firebase so let's go into our database and just see what it looks like so now when we look back at the realtime database you should see data appearing and it's going to match exactly what we sent up see the id came through the name all of that stuff and now this is cool too if you open an incognito tab and go to that same domain see that now i have two instances of the game running another player has appeared in here randomly it's gonna match because all that you know all the values for the keys are hard-coded right now except for the id see this id is different than this one so as people join our game each person is going to get assigned a new id that's unique to them and you can see that that's working okay here now let's do a quick spike to make these values unique because again as as everybody joins they're all going to look the same and be at the same spot and that's not cool so first i'm going to make a unique name i'll make a function here called create name i'll go up here and just kind of paste this in i prepared this before recording the video but there's a function called create name it's just going to take a list of prefixes and choose a random one remember we have that random helper up here uh just you know like an adjective and then um an animal so it'll kind of splice together prefix animal like dope seal um you can take this and make it your own anyway i think it's kind of fun like google doc style so i'll collapse this because it's taking up a lot of space but basically we're going to create that name randomly and then use it here because the name of the variable matches the name of the key here we can just do this instead we can keep right like this that's fine but let's do something to randomize the color here i'm going to use our helper method again random from array and pass in a list called player colors and at the top of the file up here i'm going to go ahead and bring this in we're going to start adding data about our game at the top of the file here so first player colors this is just a array of strings we're gonna add some styles that use these strings in a second but it's worth noting that they line up exactly as our sprite sheet does in the same order so now we're joining the game whenever our browser boots up and that's good but now we want to do the reverse so if we leave the game if we don't do anything right now our player would just kind of like remain in the game stale so other players would just see like the ghost of her remaining character there so we're gonna do now is add another operation on the ref and it looks like this it's player f dot on disconnect so this comes from firebase this means whenever the browser is disconnected from the session we want to do something with the player f and so we're going to say remove okay so here's our database again we have those two sessions open i still have that incognito tab open off screen here i'm going to close the incognito tab and as soon as i do that that on remove thing should fire and you we should see one of these notes disappear okay so here it goes nice so firebase picked up on it right away it flashes red for a second red means something's uh getting removed and then that yellow meant that something inside the tree is changing we'd also see it appear green when new things appear which is kind of nice we can see that now here comes a new incognito tab green there we go so now we've joined the game we're ready to kick off the functionality of the game just locally for us and so i'll say a nit game so i'll come up here and make a new function here called init game and this is where we're going to do some kickoff stuff now that everything is ready to go we can start drawing characters to the screen and the first thing i want to do is create two new refs in firebase so the first one is going to be all players ref this is going to be a reference to every player in the game where previously that player ref we have is only ours and that's the one we have access to update and write but we can read all of them that's how we're going to be able to see other players in the world and then just for later i'm setting up this all coins ref so we don't have to come back and do it later but we're going to use that to be able to read all the coins that are in the game world now we're going to start to use two new methods in our firebase refs here both of them on players ref first the first one looks like this it's all players ref dot on value and then i'll close this up this is a listener that's setting up a callback to fire whenever the value of this ref changes so in other words anytime a player joins or leaves or there's a modification within a player this callback is going to happen this value keyword comes from firebase specifically and we'll get into the snapshot bit in a second that's how we're going to actually be able to read what the change is so this fires whenever a change occurs and now there's another similar one we're going to use called child added and this one fires whenever a new node is added to the tree so basically when a new player joins this callback will fire now more specifically a good way to think about this is that child has been added that's new to me so if the game has been going on for a while and i'm joining halfway through and there's already five players around in the world this will fire five times right away because there's already five there that are new to my client's knowledge now we're gonna start adding dom elements to our tree here i mentioned before or i think i mentioned it before that i prefer to do these tutorials as vanilla javascript basically just to peel away layers of abstraction that frameworks give you like react and angular and view and all those i love those frameworks so don't hear me wrong but just for raw education's sake i like to get that stuff out of the way and just deal with the basic elements here the trade-off there is that it kind of adds some overhead on how we manage dom elements so here when a player joins we need to like manually add a new div to our scene and then whenever that player updates we need to look up that div and update things on that div that's where like a lot of front-end frameworks really help you out things like react just rendering from state that kind of thing so it's gonna be a little bit more manual here but again you can totally apply these concepts to whatever framework you like to use i'll give us more room here so first let's look up the added player data so i'll say added player is going to be snapshot.val this is a method you call on snapshots that come from firebase refs you could console log this and dig through it there's a lot of crazy stuff in there but this is pretty much in my experience all you're ever really going to need to do is just look up the current value this will give us that object back that's going to look exactly like what we had down here with the name and direction and color and xy all that stuff next we're going to create our div in memory so we're going to create an element it's just a div we did this all the time in pizza legends if you saw that series let's add some classes to this div now so it's going to have a class of character and then we're going to have this utility class called grid cell we'll move over to the css in a second this is going to fire for every character that enters the scene but it's also going to fire for us the player that we are logged in as we have a bit of a one-way cycle data pattern happening here where basically we're always just listening for events that happen on our firebase data and then we'll always react to those to interact with our dom and so we're setting up this listener when our player joins our listener is going to get fired it just follows the pattern kind of in that way but anyway if it is us that's joining now we want to know that because we're going to do some things that make the player just a little bit different than other players in the game so here i'm going to check if added player.id which again the id will be present on any player that's joining is equal to me so that's going to be a player id again we're setting that here and it's scoped up above us we're going to add an additional class to this element that's just you that's going to allow us to layer you above everybody else and then also show a little green arrow that indicates who you are on the screen now so far we still only have an empty div here our div is going to have some content in it and so i'm going to go ahead and paste some stuff now and talk through it the inner html of our div is going to have a shadow in it our character sprite both of which are going to use that grid cell utility class that we'll set up that just does some like sizing and spacing and positioning stuff we're going to have this container called character name container that shows the text above characters heads inside that container there's a space where the name will go and then also a golden span of text that will count the number of coins we're just going to start that as 0. finally we'll have this div that's called u arrow character u arrow and that's going to have just a little indicator of which character you are on the screen that's what the css class is for i'm gonna indent here and this should be the structure of our characters now we're creating elements on the fly here but we need to keep a reference to these elements so that we can update them later in this callback whenever something changed like whenever a different character moves across the map we're going to need to update that div for that character and so i'm going to make a new object appear that's just going to house all of our player elements so i'll call it let player elements it's going to start empty but then here as soon as we create a new element we want to populate that object just at that key so we'll say player elements added player.id is going to be a reference to that element now we're going to fill in some initial state this is going to be like what the name is these dom elements are starting empty things like the name and the coin count are almost empty we want to fill those things in now so i'll bring in two lines here both are doing almost the same thing we're query selecting within our created div here one for the name and setting the inner text of that element to added player.name and same for coins the next two things i'm going to bring in are going to be utilized by css to style the characters properly and so here they come character element we're going to set attribute color data color to be whatever added player.color is the css will basically use this value to position the sprite sheet correctly to show the right color similar with direction it's going to nudge the showing frame to either show the left facing one or the right facing one next we know that we have a x and y value in the player's state so we can go ahead and use that x and y to position our character on the grid where they go so i'm gonna bring in these lines here we're gonna create a left value by taking our grid size and then multiplying it by just this simple grid cell position of where this character is and then we'll add the string pixels we're gonna do the same thing for top and why the only slight difference is this minus four pixels which is basically just going to take that character and visually nudge them up a little bit so they're like in the middle of the cell appearance wise instead of um perfectly aligned with the cell borders we'll take those two values and apply them to a css transform translate rule we'll later set up a css transition rule that basically animates this as it changes so instead of you just warping from like spot spot spot it's going to kind of have a more like seamless floaty easy movement okay we are finally ready to append this character to the dom uh so first let's make an a reference to our dom element or game container that's just our one div that we have going on here we're gonna grab this game container right after we're done creating the character and configuring it we'll say game container dot append child our character element now if we just look at the game again real quick to see what's happening you can see that our character is being injected into the screen and i can like reload the page to leave and join the game as a new character the name randomization is working but it obviously doesn't look right there's no character appearance or anything like that so let's go ahead and shift over and do the styles now so in styles.css i'm going to go down to the bottom of the file make a new section for characters here and just start bringing in some styles and we'll talk through them so first i'm going to bring in this grid cell class we saw that a few times already it's basically just going to make things position absolute and then size them to match the size of our grid cell which is 16 pixels next i'm going to bring in some rules for the top level character class the first is really basic it's just any time the character's position moves we want to animate that new transform value with a transition if we include that u class unlike this character on the screen is the one you are playing as we want to make sure that they're layered above everything else otherwise you'd be able to get into weird situations where someone could pass over you but be on top of you and that it just felt weird and so this way you're always on top also if you're you we want to go ahead and show this arrow above your head the rest of the styles for that are going to look like this where we're going to start with display none you know unless it's you absolute positioned above the character's heads and just kind of nudged into place to do the appearance we're going to be using a css background image that's how all the graphics in this particular demo are going to work it's just kind of the method i felt like using for this project i've got a bunch of different examples of other ways to do it on the channel here okay so next time we're going to have the css rules for our character sprite this is going to use a background image of our character sprite sheet i'll try to like put it on screen now or something it's going to be nudged just a little bit above the grid cell again to just kind of have some of that visual appearance of floating like they're like floaty balloons now we'll add in the bits that kind of specify which color should show at which time and so this looks like a lot but it's almost doing the same thing what it's saying is if this character has that data direction right on it we want to go ahead and shift the background position of just the x part to only show the right facing frames so by shifting the x we can choose between left and right we can shift the color by playing with background position y and so again in order as they appear in the sprite sheet we have red is uh needs to be nudged this much for it to be visible orange yellow green and purple so this is just raw css but if you were using a preprocessor like sass you could probably clean this up make it look a little bit easier to parse next we're going to layer that shadow image under the character and that's also a background image all these images are available in the project download by the way in the code sandbox link finally last bit of css we're going to add is for that name container that's the text that appears above the characters so it's absolute above their head a lot of absolute position going on in this demo today um a font size that's really small but uh remember that everything's being scaled up by three you would never want to font size that's truly that tiny uh just for accessibility reasons but remember it's being rendered on screen actually three times that we have some padding border radius just some uh background font stuff and then for our span of coin count we're going to color it gold and then include just a little bit of spacing with all of this in place when i reload the browser you can see that our characters actually kind of appear and look like something this character's in a weird spot right now i think because i hard coded the starting position to be 3 3 which isn't a valid space in this map we'll talk about that in the next section here but let's go ahead and fix that so i'll come over to app.js and instead of starting at 3 3 let's start it more like 3 10. watch that be wrong too now when i reload the character is actually in a realistic location so now that this is actually starting to look like something let's go ahead and make it interactive we're going to move on and start allowing you to move the character with your arrow keys so back in our html here i'm going to add another script to the page right before our app.js file there's a copy of it included in the code download links here but it's called keypress listener this is a utility that we created in our series pizza legends where we built like a full game prototype from scratch here's what the file looks like it just takes in a key code and then a callback that happens whenever you initially press that key down but the thing about this is that it will wait for you to release the key before that function's allowed to fire again it kind of gets rid of a lot of the repeating that you'd have in just a vanilla key down handler and that's the kind of tactile feel we're just going for in this game now so far in app.js we're just adding characters to the screen but we're not really tracking them after that and so we're going to make another bucket of states and i think at a glance this might look a little confusing so let me break it down a little bit these all seem like they're talking about the same thing but they're all actually different so id is just the string of our who we're logged in as in firebase ref is just our firebase ref so we can actually interact with data on the database side players is going to be the local list of state of where every character is in the game this is just going to be like x y values and colors we're going to look at this to update all the dom nodes on the screen and then we'll have firebase update this for us player elements is just a list of references to our actual dom elements we'll use that more in a second so the way we're going to approach this is that whenever we press a keyboard direction to move our character around a signal is going to get sent to firebase to update our character in firebase state and then that will come back down and notify us as a change and then as soon as we receive that change we can go ahead and render that to the screen to keep that cycle going so here we're just going to sync our player's value to whatever is in firebase so we'll say players is going to equal snapshot.value if the player's node in firebase were to be deleted somehow like if i went in there and deleted it then this would be null and so instead i'm just going to substitute that with a blank object and now we want to loop through all the information that we have in our updated players and sync that to the screen and so we'll update these player elements so i'm going to iterate through the keys of player here and from there we can pull out the state of each player so this character state is going to end up being like an object that just has our x y our name that thing that we wrote in the beginning of the video and then we'll look up our reference to that character's dom element on screen and player elements here again the keys are gonna be the same in both objects now we can repeat some of the stuff that we did down here again this is where our front-end framework kind of comes in handy with updating the dom for you but in our case just for the sake of a simple demo we're gonna bring these lines basically back in so if the name has changed coins have changed or the color or direction we'll get into changing name and color uh in a little bit here then that dom element on screen is gonna update but the most fun and meaningful update is this one where maybe their position has changed in this way we're gonna look up that same element and then just update the transform it's the same thing that we did down here you could totally clean this up but it'll work fine for now now we're ready to start firing off those arrow events so up here right above init game but still within our main function i'm going to start a new function here called handle arrow press and this is going to take in an x change and a y change we're going to be able to reuse this for all four directions and so i'm going to kind of set it up with some configuration for that the first thing we want to do is figure out the new x and y position of our character and so the new x is going to be whatever our player's x is currently and so to look that up we can look at the player's state object and then pull out just the key of player id and that's why we kind of have it stored and available to us like that we'll look up just the x value and then we'll add whatever x change was passed into this function so these are going to default to like zero um to basically default to no change but the up handler could pass like negative one here or one to go down that kind of thing we'll see that in a second but we're going to do the same thing for the y also to kind of figure out our next position now we're going to be adding some collisions to this game certain spots on the map that you can't walk unto or not be allowed to walk off the map but we're not quite ready to do that yet i am gonna like stub in the logic of where it's gonna go and so i'm just gonna say if true then we can go ahead and move to the next space uh in a little bit we're gonna of course remove this if true check to be more like can i move to the space but for now we're just gonna assume yeah you can move and so if you were able to move we can go ahead and write your new x and new y to the player's state and so that looks like this we'll look up that same node and this time we're writing it um setting it to to be the whatever the new x and new y is if we happen to move left or right like if we utilize the x exchange above like if it was 1 we can go ahead and set your direction to be right so that's going to look like this just updating a different key and we'll do the same thing for left so if it was negative 1 will update you to be left so now we have a player node that has a new position and maybe a new direction we want to tell firebase about that to basically notify ourselves and all other players so we're going to say play ref dot set to be whatever the new value of players like this player is so we'll just take this much so that will update this player in firebase which will then cause our value listener to be fired and then our lines of code that update the character positions will happen and we should see it just work now that we have this ready to go we can actually use it and so here at the top of the knit game i'm just going to create a new keypress listener again this comes from that utility arrow up is the key code for the up arrow key when that is pressed we want to go ahead and fire this handle arrow press and configure it for a y direction like an up direction and so that's gonna be zero and then negative one we can repeat this for all four directions up down left and right and then change the configuration here so down will be positive one on y these two horizontal ones will be zero on y but they'll be negative one for left and then one for right kind of basic grid stuff now when i reload the game and start using my arrow keys you can see that the character moves around the screen uh and the direction is updated too like when i move to the left he's facing left now to the right but the cool part is that this information of where he's at is not just local data it's also data that comes from firebase and so if i open a new incognito tab now you can see a second character has appeared so in this tab i can move this character around and you see the change happen in the other tab do the same thing over here so now we have the space that we can interact with and like hang out in together now we have a bit of a sinking issue i have left the game in the other tab but our character that was in that tab i guess it's this yellow one uh is still around and lingering so now we need to be listening for players to exit the game and when they do that we need to manually remove their dom element back in our code here i'm going to find that section where we're adding child to all players ref listening for child added we're going to do kind of the same idea but the opposite so child removed is another hook that we can listen for in firebase when child is removed it's going to give us the object of the child that disappeared and that object is going to have the id on it and so we can say removed key is going to be the value of that snapshot grab the id of it that's the dom element we want to remove from the screen so we'll take our game container remove child just the opposite of append child looking up in our player elements object the key that was removed and then once that's gone we can go ahead and clean up that key from our object because it's not there anymore so player elements removed key so we'll say remove so let's check this out so here's tab one incognito tab two i'll go ahead and leave the game and tab two and now the character has disappeared now let's shift gears and go ahead and add some of that collision detection so this doesn't really have anything to do with firebase it's just more in line with making the game right now i can pass through these tables and chairs and stuff we want to go ahead and block off those spaces to make the space feel more real back in our app.js file i'm going to come up towards the top of the file just we have some static data and i'm going to paste in some configuration info of the scene that we have on screen so this is an object called map data it's basically telling us the minimum x max x min y and max y which is just that basic area that you can walk in so you can't walk off the edges and then within our scene we have certain cells that have objects on them and so i've gone in and just manually added these this is kind of similar to how we did it in pizza legends 2 where there are just certain static spots on the map that you can't walk to we're going to go ahead and consider all of these factors before we allow you to move on to a certain space so i'll come down here and create a new helper function this is going to be is solid and it's going to take in an x and a y it's going to return true or false here in the arrow press handler we left this as true but we can go ahead and just change this to be is solid and then we'll call it with new x and new y and now we want to ask the question hey is it okay if i step onto this x and y now the first thing we're going to ask is is there anything at the location that i want to move to and so i'll bring in this line that says blocked next space is going to be map data block spaces looking up a key string using this x and y remember the very beginning of the video we said we have this helper that just helps us do that it's just going to transform an x y coordinate into something that looks like this if we have a blocked next space and is solid should be true but we also want to consider the constraints on the left top right and bottom of that sort of main area and so we'll bring in this bit of logic too that just checks that the x is within the x area and the y's within the wire it's a lot of ores all stacked up to each other but this check all together is going to determine if the space is okay to step on or not if you're taking these concepts and running with them you could configure this to match whatever asset of map you're working on and of course you know if you were in a different room or that kind of thing then you may need to change what the map data is those would all be good things to expand on and then here when we call the function we actually want to call to make sure it's negative so if the space that you want to move to is not solid then we're going to go ahead and run this movement code let's see this working now when i reload the tab i can move around still but when i get to one of those solid spaces it's not letting me walk into them i also can't walk off the side here or up through this building those are all handled by that min x max y all that kind of stuff so currently when you load the game every player is going to launch at the same point because that coordinate is hard coded so let's go ahead and add some code that kind of switches things up and randomizes where players can spawn and then maybe later where coins can spawn too so i'll come back up here to the top of the file i'm going to add one more helper function i'll collapse some of these to clean up the screen so i'll paste it in here this is going to be called get random safe spot and all it's doing is taking this giant array of x y potential spaces like this one or this one or this one there's tons of them i've looked at the map asset and just hand-picked a few grid spots or more than a few you know this many good spots of good places to spawn so there's no objects there or anything like that you could get fancier here if you wanted to sort of pick a random spot totally and then compare it against this list but for again for this tutorial i'm trying to just embrace simplicity here so we're just going to take one of these random known safe spots and then use that as our starting point i'll go ahead and collapse this too because it's kind of a lot to look at we'll come down to where our character enters the map which is here up here i'm going to say x and y should be destructured from our helper get random safe spot and now instead of including just a hard-coded x and y here we'll say x and y and now when i load up the game every time the character starts in one of those different spots and to show the other tab too when i reload you'll see the character bounce around to different spots now coins are going to be kind of the grand finale feature of this video tutorial but before we do that we want to bring in some of the ui that we currently have muted so like in here we have this playerinfo field i'm going to go ahead and bring that back in this is going to allow characters to rename themselves and then also set the color of their appearance so with this in the ui looks like this we want to go ahead and wire this up so that you can type whatever text you want in here and then that will update your character's name and then same with this color button so i'm going to come to the top of app.js or almost the top top of our function here and where we have the saved element reference to the game container i'm going to add two more one is going to be our player name input which is just a query selector for the id that matches that text input that's in the dom there and same for the button it's got an id called player color so first when we enter the game a random name is chosen for us that happens here create name and we want to sync that name back to the element right so um player name input we're going to set the value of it to be whatever the name is so now when i reload the page you can see that the name is chosen and then the initial text also appears in the input here now we want to allow you to edit that text box and then have it sync up to firebase so we'll find our nit game function here and then just at the bottom of it down here we can add a event listener to our player input name we're going to add an event listener for change so whenever the blur happens it's going to go ahead and update firebase we'll grab the event and we want to pull the text value from the event so we'll say the new name is e.target.value but in the event that someone like cleared out the field and it didn't actually have a value in there anymore we want to make sure you always have a name so we'll default back to just creating a new random name we're going to pipe that value back into the input again really just in case we backfilled it with a name that we created now we're going to grab our player ref again and this time we can use a different method in firebase called update so before to this point i think we've been using only set and set is where you just blanket set the entire value but here we want to update just one property in that node and so you can pass update a sub object or just an object and it's going to only update the keys that you give in here so for us we only want to update the character's name and its value should be new name so x y color direction all that stuff will stay the same but only name will update so i'm back in the game if i take this text node and change the text and then blur you can see that my name updates it will also update for any other players in the game so let's just add a comment here to know what we're doing so this updates player name with text input and now we're gonna do the same kind of thing with the button so update player color on button click so grab our player color button and add an event listener to that it's gonna be on click now to update the color we're just going to find what your current color is and then set you to the next one so we'll say my skin index is going to be the index of player colors that matches my color so like if you're on red i forget the order but if you're on red that would be one if you're on orange that would be two we're gonna take that two and then add one to it so that would be three which should be yellow and then if you're at the end of the array like you're on purple and you do plus one that value is going to be undefined and so we can just come back and default it back to zero so the code for that kind of looks like this next color is going to be the index of what we found plus one but if that index doesn't exist we can default back to zero next we're gonna do the same player ref update just like we did with the name to update it in firebase which will then update it for everybody but this time it's gonna be color so color is going to be next color now when i fire up the game and i click this color you can see that the color of my character's appearance is changing so i can choose whichever one i want so before we get to the coin feature in this video i just want to do a quick plug for our discord community if you have a gamedev project in the works and you want to show other developers maybe get a motivation boost find a accountability buddy our discord is a really great place to be pop in there tell us about your project the link to that is below i'd love to see you there okay let's finish this tutorial off with the coins feature so what we're going for here is when you're playing the game we're gonna drop coins randomly around the map you're going to be able to collide with them to collect them which will increase your account here the coins information will be shared for everybody in firebase so you'll see the same coins that everybody else sees and you can all you can like watch other people collect them it's a pretty simple thing but it'll be fun the first thing we're going to do is add two more buckets just like we're tracking player state and player elements we're going to be tracking coin state like where the coins are and then have references to the coin elements so that we can add them and remove them from the dom when they've been collected so i'll add in coins here and coin elements they're going to function pretty much the same way now in a knit game we're going to go ahead and just like we have operations on the all players ref we're going to start adding similar ones to the all coins refs so here right under the player's ref part but before the input listeners the order doesn't really matter but just for cleanliness i'm going to say all coins ref.on child added and that'll give us a snapshot back this is gonna happen when a coin enters the map coins are gonna have an xy value on them that's really all there is to them uh and so we can grab the coin that was created using snapshot.val we'll take the x and y that were on the coin there and then create a string key on it just like we've done before and we'll use that to update our local definition of where all the coins are it's going to come into play with the collision detection now we can go ahead and create a dom element for the coin that's being added and so i'll just bring in this block of code here it's just like the player block above it we're creating a new div adding some classes like coin and that grid cell to give it the right spacing the coin's gonna have an inner shadow and then also a sprite sheet but it doesn't need any of the other fancy stuff that players have we need to position this coin according to its x and y so i'll bring in some more code here that creates another left value does the same y value thing where it nudges it upwards just for like appearance and then applies both of those things as a css transform now that the coin is created in memory we can go ahead and inject it into the dom and then we'll also keep track of it in our coins element object that way we have a clear reference to it so we can remove it whenever somebody collects the coin and then of course here is the line where we're actually adding it to the dom now coins are pretty simple because they just get added to the map and then they get collected and removed they don't like change like the players are changing colors and names and position on the map we don't really have to worry about that with coins it's really just a matter of adding and removing so i'm going to add in a another firebase hook to cover that removal case so i'm going to copy over this one and update it to be child removed remember this is fired by firebase when anything is removed from its parent object the xy information of which coin was removed will come back in the snapshot and so we could say x and y is going to equal to snapshot.value vowel and so the key to remove is going to be our helper so get key string we'll pass in that x and y we'll have our game container look up that dom element and remove it so we're going to remove a child which one we can use this key to remove to look up our stored object so coin elements key to remove that will give us a reference back to that dom element and then just like we did with people that dom element's gonna be gone so we can go ahead and delete it from our kind of list you might be thinking this is a lot of work to manually manage the dom and you're totally right it is a lot of work but i do think it's cool to have these skills sharp because they do come up here and there it's just a good exercise to do okay so our firebase operations are all set up and ready to go we're gonna add dom nodes as they come in and remove them as they come out but there's nothing that's actually placing coins right now in the firebase data so let's go ahead and do that i'm going to come up to our just area up here and make a new function called place coin so here we can use that same function we made before called get random save spot to choose a safe x and y to use we now want to create a new ref in firebase to this coin that we're going to create and so we'll say coinref is going to be dot firebase.database.ref and then a path to that coin and so it's going to be coins is the name of the parent that we'll have and then now we want a specific id for this coin that we're creating and so we'll splice together the x and y in a string like that using our helper so get key string x and y so that'll kind of capture the position of where it's at and be a unique key for it and now we want to actually add this to firebase the way you do that is like we've seen so far coin ref we're gonna set and the data for this particular coin should be the x and the y value now this multiplayer game is really client only where clients are gonna start sending up instructions when to place coins it's not like a server-side operation or something like that that would probably be way more robust but it's also more overhead and complexity for this tutorial so how it's going to work is that every player that's in the map is going to randomly fire this place coin thing to just kind of keep having coins fire all the time so we'll fire this once but then after a delay we want to fire it again so i'm going to bring in this list of timeouts these are just millisecond timeouts and we're going to use this in a set timeout function but here where the time would go i'm going to use that random helper one more time random from array the coin timeouts it's gonna randomly choose two three four or five seconds and as soon as that timeout is up we can just recall this function so placecoin we need to fire this off for the first time because it's not ever being called initially and we can do that right when the game starts so we'll come down to the bottom of a nick game and run placecoin now we're almost ready to see this working but the thing is we won't actually see it working because there's no styles for the coin yet so let's go ahead and fill those in so at the bottom of our styles.css i'm going to make a new final section for coins this is going to look a lot like the character section above it where coin sprite is gonna link to this background image it doesn't repeat it's gonna have this nice little like floaty animation to make the coins interesting so we'll bring that in here it's just a keyframe that says um start at zero pixels in your y position and then go to 5 pixels and it'll just kind of like bob back and forth between that in a linear easing function it'll keep going and it'll also alternate reverse to sort of oscillate back and forth coins are also going to have a shadow so we'll bring that in now it just links to a dedicated shadow sprite sheet that better matches the coin's shape now we're ready to see this working when i load up the game you can see that coins are starting to sort of randomly appear so that's working they look good they look right but i can't actually hover over them to collect them yet because we don't have any coin collision code we'll do that in a second but for now you can just see the coins randomly appear and you can't do anything about it so let's go ahead and add that back in app.js here i'm going to add one more function we're going to add one here called attempt grab coin so the characters can fire this off whenever they move to a new position it's going to check if a coin is present and if so it's going to delete it and then up tick their coin count so we'll take in an x and a y here and then we can use our helper to splice together one of those keys x y and we'll look at the coin state object to see if a coin is there so if coins key we're gonna go ahead and remove this key from the data and then uptake the player's coin count and so to do that we can grab the ref by saying this it's going to be coins at the key it's the same thing that we named it up here and fire this dot remove on it that's going to remove it from firebase and then all the updater things will happen so you'll see it get removed from the screen finally we can update our player f here because we collected a new coin we're gonna look up our current coin value and then just add one to it and again this is going to be fine for our prototype but you should know that if you're building a production game this kind of system has a flaw and that the client can kind of just send up whatever the new coins value should be for myself so i could kind of cheat and add like ha i could get into the inspector and like add a really high score or that kind of thing this is of course just a prototype for educational purposes if you plan to make a game that's going to be played by a lot of people and you care about fairness and cheating and that kind of thing you definitely need to make sure that you're doing back end validation as well which firebase can do it's just a little bit out of scope for this tutorial now that that disclaimer's over with let's go ahead and grab our function and use it we'll use it when we move the character so that's down here and handle arrow press if we have a new direction after all this is done we can go ahead and run attempt grab coin and we want to pass in our new x and new y now when i play the game my character will start collecting the coins as they're collided with you can see the count is up ticking as well so i can collect all these make my score really high now i've joined the game here as a different character in an incognito tab and now this character can also collect and you see that they're kind of collecting from the same collection of data okay so that kind of wraps up the feature set i had planned for this particular video i hope you take these concepts and roll with them to make whatever multiplayer game you're dreaming up come true i've personally built a lot of production firebase apps including a multiplayer game and it works really well there are some edge cases that we didn't cover here again if you're building a production game you got to think about security and you got to think about network flakiness like people quitting and rejoining because maybe their connection was bad or they're on a phone that kind of thing so it does get kind of complicated but firebase is a really good tool to do it so i highly recommend that you check it out and i'm stoked to see what you make as always if you got value out of this video i really appreciate it when you hit the like button and subscribe for more videos like this one i hope to see you join our discord if you haven't already thank you so much i'll catch you next time
Info
Channel: Drew Conley
Views: 92,873
Rating: undefined out of 5
Keywords:
Id: xhURh2RDzzg
Channel Id: undefined
Length: 57min 49sec (3469 seconds)
Published: Wed Mar 02 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.