Unity Tutorial – Massive Multiplayer Online (MMO) Game with SpacetimeDB

freeCodeCamp.org · Beginner ·🛠️ AI Tools & Apps ·1y ago

Key Takeaways

This video tutorial demonstrates how to create a massively multiplayer online game using Unity and SpacetimeDB, covering topics such as game development, database integration, and multiplayer functionality. The tutorial uses C# and SpacetimeDB to create a game inspired by Agar.io with a space theme and multiplayer functionality.

Full Transcript

hi I'm Boars in this Unity course I'm going to teach you how to build a massively multiplayer online game or MMO from scratch while the game is small in scope it will easily scale to hundreds of players we'll be using SpaceTime DB as the database SpaceTime DB provided a grant to make this course possible it would be helpful if you had a little bit of unity or C experience but it's not required to follow along I'll teach you every step of the process the game that we're going to be creating today is inspired by this game agar.io where you have to go around and collect these little dots and the more you collect the bigger you get and you just want to get as big as possible and there'll be other players because it's a multiplayer game that you're interacting with uh you don't want one of the bigger players to uh collect you if you get big enough then you can collect the other oh like here's a giant player let what happens when see it just collected me so basically it's just like a web game where you can play with hundreds of other players to cultivate Mass to become the largest cell in the petri dish so we're going to create a similar game but it's going to be space themed and it's going to be a multiplayer game created with unity so we're going to have two different subdirectories we're going to have our server code and our Cent client code so first we'll create a project root directory you can use any name but I'm going to call it black Holio and then we'll just go into that directory and you can also do it visually on your computer in your file manager if you want and now that I have this directory I'm we're going to create the unity project which is going to be our client code and then by the end of this section we'll have a basic unit project and be ready to implement the server functionality so this is Unity Hub so you're going to have to go and install Unity Hub on your own you can do do that just by searching for Unity Hub and then just go to download but then after you get that installed and you get it open we are going to create a new project so we want to make sure we're using at least the unity version 2021.com have 2022 if you're just installing Unity for this first time it will definitely be the a new enough version so after I've chosen this new project I'm going to go to Universal 2D this is a template that uses the unity Universal render pipeline so I can go over to project name and I'm just going to call this client unity and then I'm going to change make sure the location is in the directory that we created so I'm going to go to the directory we just created select folder and then I'll just click create project and then we have to wait for it to finish creating this and then it'll just open up Unity with this new project that we just created okay after our project is loaded up we need to import the SpaceTime DB Unity SDK so we can add the package using the package manager so I'm just going to go to Windows package manager so HCK the plus button here and go to add package from get URL now I'll put the URL that you're supposed to use right in the video description but I'm just going to paste it in here and this is going to add that package the SpaceTime DB Unity SDK provides helpful tool tools for integrating SpaceTime DB into Unity it includes a network package man a network manager which will synchronize your Unity client state with your SpaceTime DB database in accordance with your subscription queries so I got this installed and we can just hit X here and now I'm going to create the game manager script so I'm going to go to this project window and then and in this assets folder I'm just going to create a new folder I'll hit the plus and then go to folder and then I'll call this scripts I'll go into the scripts folder and then I can rightclick and go to create and then do a c script and I'll call this one game manager the game manager script will be where we'll put the highlevel initialization and coordination Logic for a game so let's add the game manager to our scene first of all I'm going to go back up to this hierarchy thing up here and go to create empty so I've created an empty game object and I'm going to call this the game manager and now we just have to attach the game manager script to the game manager game object so there's two main ways to do it I I'm going to just drag this right onto here the other way would be to click this add component component and select the game manager but you can see now it's already added the game manager script has been added to our game object okay next we need to add the SpaceTime DB network manager this is a simple script which hooks into the unity update Loop in order to drive the sending and processing of messages between your client and SpaceTime DB you don't have to interact with the script but it must be present on a single game object which is in the scene in order for it to facilitate the processing of messages so when you build a new connection to SpaceTime DB that connection will be added to and managed by the SpaceTime DB network manager automatically so we want to make sure we've clicked on the SpaceTime or the game manager object and then I'm just going to click add component and then I can just click uh just do a search you can see what already showing up there searching for SpaceTime DB network manager and I can just double click that to add it to our game object okay our Unity project is all set up so if we press play um it will just for now it's just going to show a blank screen because we haven't really added anything else to it but it should start the game without any errors if we go to the console we don't see any errors here so now we're ready to get started on our SpaceTime DB server module so that we have something to connect to so I'm going to stop the game by pressing the play button again here and before we create the server module we need to make sure we have the SpaceTime DB CLI installed so if you just go to spacin bb.com install uh you can see the instructions for whatever system um you have so now I have the space time installed I can run it from the command line I could do SpaceTime uh start and then we can see we just started the database and you you can see it's listening at this port but I'm just going to stop it for now and we're going to initialize the SpaceTime DB server module project so we have to make sure we're still in our black jolio directory and then we'll run a command to initialize the space sign DB server module project and we can actually do it with either rust as the language or C so in this tutorial we are going to be doing it with C but uh everything could also be done in Rust so to initialize it I'm going to do space time init and then we'll specify the language Lang equals c and we could have done Lang equals rust if we wanted and then I'm going to specify the folder server DC so the command created a new folder named server uh St C in our alongside client D Unity directory and it sets up the SpaceTime Tob server project with c as the programming language so I'm going to open this up this whole folder in Visual Studio code but feel free to use any code editor you like so now that I have this open Visual Studio code I'm going to go into the server directory and then I'm going to find the lib.com basically some default code here but I'm just going to delete everything because I'm going to we're going to be writing it from scratch so first I'm going to add a basic import at the top of the file and in the description you can get a link to all the code for this and the first thing I'm going to do is Define A Spacetime DB table a table in SpaceTime DB is a relational database table which stores rows similar to something you might find in SQL SpaceTime DB tables different from the normal relational database tables and that they are stored fully in memory so they're super fast to access and they're defined in your module code rather than SQL each row in a space-time DB table is associated with a struct type in C so let's start by defining the config table this is a simple table which will store some metadata about our game state so this code code that I just add defines a normal C struct with two fields we have the ID and the world size we we've also added this line here the table name equals config public equals true this is an attribute that we've added to the struct this attribute signals to space time DB that it should create a new SpaceTime DB table with the row type defined by the configs type Fields this table attribute takes two parameters we got the name field which is the name of the table and what you will use to query the table and SQL and the public field this is basically a visibility modifier which ensures that the rows of the table are visible to everyone and this primary key attribute specifies the IDE D field that should be used as the primary key of the table and note that the primary key of a row defines the identity of the row a change to a row which doesn't modify the primary key is considered an update but if you change the primary key then you have deleted the old row and inserted a new one okay next I've defined a new SpaceTime type called DB Vector 2 and this is going to be used to store position the difference between the SpaceTime db. type and SpaceTime db. table see this is the type is that tables actually store data whereas the deriving SpaceTime type just allows you to create a new column of that type in a space-time DB table so this DB Vector 2 is only a type and does not define a table so now we can just um store 2D points in the tables okay now I'm going to create a few tables to represent entities in our game and add a few more tables to the end of this class so this first one we have here that's the entity table an entity represents an object in our game world we have decided just just for the purposes of this uh tutorial on this game that all entities in our game should share some common fields like we have a mass and a position and we can create different types of entities with additional data by creating new tables with additional fields that have an entity ID which references a row in the entity table and that's what we have next so if I scroll down a little bit we have this next one so we have a circle entity and then we also have a food entity so here I'll make it so we can see both these at once so food does not have any additional Fields beyond the attributes in the entity table so the food table simply represents the set of entity IDs that we want to recognize as food but you can see with the circle uh table it represents an entity that is controlled by a player we've added a few additional fields to Circle like this player ID here so that we know which player that Circle belongs to because remember this is a multiplayer game so there could be a lot of different players playing at once okay next I'll create a table to store our player data so we just added this at the end here there's a few Concepts I want to talk about here first of all we are using the unique attribute on the player ID field this attribute adds a a a constraint to the table that ensures that only one row of the player table has a particular player ID we're also using the auto Inc or Auto increment attribute on the player ID field which indicates uh basically that this field would get automatically assigned an auto incremented value we also have an identity say public identity identity and this field uses the identity type the identity type is an identifier that SpaceTime DB uses to uniquely assign and authenticate SpaceTime DB users okay next Let's uh write our first reducer a reducer is a module function which can be called by clients so let's write a simple debug reducer to see how they work so I'm just going to add some code here so see what this is just called the this reducer is called debug and then it's going to log this information here it doesn't update any tables it just prints out the identity of the client that called it this color that color identity a reducer in SpaceTime DB um it's basically a term coined by Clockwork Labs the creators of SpaceTime DB and it refers to a function which when executed reduces a set of inserts and deletes into the database state it drives from functional PR programming the the term and it's closely related to similarly named Concepts in other Frameworks like a react Redux reducers can be called in a few ways like using the CLI remotely the client SDK or they can be scheduled to be called at some point in the future from another reducer call all reducers execute transactionally and atomically meaning that within the reducer it will appear as though all changes are being applied to the database immediately however from the outside changes made in a reducer will only be applied to the database once the reducer completes successfully if you return an error from a reducer or Panic within a reducer all changes made to the database will be rolled back as if the function had never been called if you're unfamiliar with atomic transactions it may not be obvious yet just how useful and important this feature is but once you build a somewhat complex application it'll become clear just how invaluable this feature is so now that we have some basic functionality I'll make sure this is is saved and let's publish the module to space time Tob and call our debug reducer So within our command line let's do space time start and if um I zoom out a little bit we'll see it says SpaceTime here and when you see this line here we know that it is successfully running on our machine so now that SpaceTime DB is running we can publish our module to the SpaceTime DB be host so I'm going to open up a separate terminal window so I'm going to go to the the server folder the server CP folder and then I have to make sure I'm logged into the SpaceTime CLI so I'll run the space time login function and it says you are already logged in but let me just show you what would happen if I wasn't so I'm going to log out and then I'm going to log in again and then it it actually opened up a web browser you didn't see it here but it opened up a web browser where I was logged in and then it sent the response back so now I'm successfully logged in uh you may end up having to make an account at this point if you don't already have an account to log into okay now once I'm logged in I can uh publish so I'm going to do SpaceTime publish server local black jolio wait a second black Holio and it looks like I got air because theet SDK has not been installed yet so I have to make sure I install that first so I'm at net. microsoft.com usdownload and you can just do a search foret download and then put your OS I'm on Mac OS and you may have to do that even if you already have net installed you may not have the right version so you may have to upgrade now for this project we're going to need the net 8.0 and not theet 9.0 so I'm going to just click download and we'll start getting this downloaded and then I'll just go through the installation now again you may not have to do this because you may already have installed now I'm just going to run the SpaceTime publish command again if you have inadequate permissions then we can run something else to give permissions uh we got pseudo net workload install wasy experimental okay now we should be able to try the space on publish again server local black Holio okay then after it's done you should see this now it could be a lot take a lot longer to install or to create but once it's published you will see it's uploading to local publishing module and then creating the new database with the name okay now we should be able to use space the SpaceTime command to call our newly defined debug reducer so we'll do SpaceTime call Black Holio debug now it it doesn't actually have any output but we can see the debug logs by running SpaceTime logs black Holio and then here we can see the reducer was called and then it has the ID so that worked and I'm going to go over to my other terminal Tab and this is where the database is running and you can see an additional logs here now let's connect our client to our module let's start by modifying this debug reducer so I'm going to rame it to connect and we will add reducer kind. client connected in parenthesis and then we'll just update what's the what the log is so we'll just say just connected so this the when we put reducer kind. client connected that argument to the SpaceTime Tob reducer attribute indicates the space time to be that this is a special reducer this reducer is only ever called by SpaceTime DB itself when a client connects to your module SpaceTime DB gives you the ability to Define custom reducers that automatically trigger when certain events occur so besides so this one was the client connected that's called when a user connects to the space under module and the identity can be found in the the the color identity also we could have done us reducer kind. init which is called the first time you publish your module and anytime you clear the database with SpaceTime publish and then delete data also where's there's reducer kind. client disconnected which is called when a user disconnects from the SpaceTime DB module so now that we've made this update Let's uh publish the module again so I'm just going to do space just like just like before SpaceTime server local black Holio so let's try again with the word publish there okay we got it published and you know yellow just means um it's a warning but it's not really that bad if it was a red then it would be something that would be preventing our our program from working correctly okay now it's time to generate the client the SpaceTime CLI has built-in functionality to let us generate C types that correspond to our tables types and reducers that we can use use from our Unity client so let's generate our types for a module we should still be in our server DC let me clear this so we're doing the command SpaceTime generate and then we're specifying the language of C the output directory as client D Unity asset autogen now this La the name of the directory autogen it really could be anything but we're just choosing it to call it autogen okay finished successfully generate finished successfully now this is going to generate a set of files in the client Unity asset autogen directory so let me show you that and these files are going to contain the code generated types and reducer functions that are defined in the module but usable on the client it's also going to uh generate a file in this Dore globals directory with a type aware DB connection class we'll use this class to connect to the module from Unity at this point there should be an error in the unity project I'm going to go back over to Unity it's going to compile and then we see this error this is a known issue with unity and C 9 and we need to I I insert some new code into our Unity project so I'm going to go to the client unity and then I'm going to go to the assets scripts and then the game manager. Cs and then at the bottom I'm just going to insert this namespace system. roome time. compil service and then it is external init now that's just going to um fix this bug which it will hopefully be resolved in unity soon so if I go over back to Unity it's going to compile and we no longer have that error okay it's time to connect to the module so let's go back over to VSS code I'm still in the gam manager. CS file and we're going to set up Unity to connect to the unity to connect the unity client to the server so let me just add a few more Imports here import space time TB import SpaceTime tb. types and then I'm going to update this game manager class and then I'll uh talk about it so here we're going to configure the connection to the database by passing it some callbacks in addition to providing the server URL and the module name to the connection when the client connects the SpaceTime DB SDK will create will call the handle connect method allowing us to start up the game so we can see that we create some variables here we got onconnected on subscription applied border thickness border material we're just setting up all these variables to use instance local identity con and then we have start which will up which will be called when the game starts and we'll be setting up some more variables then we need to register our call backs and specify a space IMDb server URI and module name that we set above here then here um if there's already an off token stored in the Unity Player prep we can use it to authenticate the connection and then you can see we're building the connection that will establish a connection to the SpaceTime TB server so like I said earlier the handle connect will be called when the client connects and here we're we're building a subscription and then we we're calling the subscribe to all tables to subscribe to all data in the database this will cause this will cause SpaceTime DB to synchronize the state of all our tables with our Unity clients space time DB sdk's client cache you can also subscribe to specific tables using SQL syntax like select star from my table and if we go down we can see we also are going to handle errors we handle disconnect ction handle the subscription applied we have one for is connected disconnect and those are all the sections we're we're adding here if we go back up here um I just want to talk about the SDK client cache that's a client side view of the database defined by the supplied queries to the Subscribe function uh spice time to be ensures that the results of subscription queries are automatically updated and pushed to the client cache as they change which allows efficient access without unnecessary server queries so now we're ready to connect the client and server so I'll just save this and we'll go back into unity and then we just have to wait for everything to be compiled oh we have a few um errors here now there's one more import I forgot to add which is just using system so let's save that and then we'll compile the scripts here good that takes care of our errors so now let's press the play button okay connecting is connecting to our database connected and subscription applied that means everything worked as expected subscription applied indicates that the SpaceTime DB SDK has evaluated your subscription queries and synchronized your local cache with your databases tables we can also go and look at the server logs so if I go back to my terminal I can run SpaceTime logs black Holio and we can see the reducers called updated program database updated okay we've learned how to up a Unity project with the SpaceTime DB SDK write a basic SpaceTime DB server module and how to connect our Unity client to SpaceTime DB that's pretty much all there is for the setup so now we're ready to start building the game so let's start building up the functionality of the game and learn how to access our data table and call reducers in unity let's start by spawning food into the map the first thing we need to do is create a new special reducer called the init reducer space IMDb calls the init reducer automatically when you first publish your module and also after anytime you run the publish uh-- delete data it gives you an opportunity to initialize the state of your module before any clients connect so let's make sure we're in our server we're not updating our client we're updating our server we're on the Lo the li. Cs fi uh file and then right above where it says the connect reducer we already have the connect reducer we're going to add the anit reducer so we see it's going to log initializing and it's going to insert a config of a new config World size 1,000 this reducer also demonstrates how to insert new rows into a table we're adding the the single config row into the config table with the insert function now that we've ensured that our database always had us has a valid World size let's spawn some food onto the map so let's add some more code we'll go to the end of the module class so let's add some new code we'll go all the way to the end here all the way to the end of our module class so we're first going to set some new variables food the food Mass Min food Mass Max Target food count which is 600 Mass to radius we'll do some math here and then we have our spawn food there's no players just return we're going to set our world size we're going to be using the world size we configured along with the reduced context random number generator that's what this um RNG that's a Rand random number generator and you can see you can see how we're getting the World size or we'll possibly throw an error if the config is not found and then we do this Loop remember that the target food count is um what we set up here to be 600 so and this is basically going to be a count of the the food that has been added so far so we're basically using the random number generator function to place 600 food uniformly randomly throughout the map we've also chosen the the mass of the food to be a random number between two and four uh inclusive that's what we set these numbers up here for we'll keep going down here and and we also have these two helper functions which are basically going to get a random range as either a unit or a float and then we can see every time the food is spawned um we do spawn food so we're inserting The Entity which is going to be the food um see we're inserting the food here um and then we're or adding to the food count and then spawning the food although we've written this reducer to spawn food no food will actually be spawned until we call the function while players are logged in so this raises the question who should call this function and when we would like for this function to be called periodically to top up the amount of food on the map so that it never Falls very far below our Target amount of food SpaceTime DB has built in functionality for exactly this with SpaceTime DB you can schedule your module to call itself in the future or repeatedly with reducers in order to schedule a reducer to be called called we have to create a new table which specifies when and how a reducer should be called so let's add a new table at the top of this module class so our table name is spawn Food Timer and this scheduled equals name of Spawn food this tells SpaceTime to be that the rows in this table uh specify a schedule for when the spawn food reducer should be called each scheduled table requires a scheduled ID and a scheduled at field so that space time Tob can call your reducer however you can also add your own fields to these as well you can create delete or change a schedule by inserting deleting or updating rows in this table now you may see an error that telling you that the spawn food reducer needs to take two arguments but currently only takes one this is because the schedule row must be p cast in to all scheduled reducers so let's modify our spawn food reducer to take the scheduled row as an argument so we got the reducer context and spawn Food Timer and we'll call it underscore timer since we're not interested in the data on the row that's why we named it with the argument uncore timer okay well let's modify our init reducer to schedule our spawn food reducer to be called every 500 milliseconds okay so I'm at our anit rer and now we are doing the SP spawn food timer. insert and inserting a new spawn Food Timer scheduled at and a new schedule at interval of 500 milliseconds you can use this schedule that. interval to schedule a reducer call an interval like we're doing here SpaceTime DB will continue to call the reducer at this interval until you remove the row you can also use schedule at. time to specify specific time at which to call a reducer once SpaceTime Tob will remove that row automatically after the reducer has been called let's continue building out our server module by modifying it to log log in a player when they connect to the database or create a new player if they've never connected before so let's go to our player struct and we're we going to add a second table so we already have this first table player um name equals player but I'm going to add another one uh name equals logged out player that line creates an additional table called logged out player whose rows share the same player type as the player table but it's important to note that this new table is not marked public the player was public the logged out player is not this means that it can only be accessed by the database owner which is almost always the database Creator in order to prevent any unintended data access all SpaceTime Tob T tables are private by default if your client isn't syncing rows from the server check that your table is not accidentally marked private now let's modify our connect reducer we have this very simple connect reducer and we're going to modify that and create a new disconnect reducer below it so I'm just going to completely update this code so let's look at this code that handles player connections and disconnected connections from the game server it uses a clever two-table approach to manage player States efficiently so the connect R reducer activates whenever a client connects to the server and then when it occurs first it checks if the player already exists in the logged out player table this check helps distinguish returning players from new ones and then for returning players that's this if statement the system performs a transfer operation first it moves their data from the logged out player table to the player table effectively marking them as online this transfer involves inserting their data into the player table and then removing it from the logged out player table so it's inserted into the player table and removed from the logged out player table but if the system doesn't find in the logged out player T table it basically treats them as a new player and inserts the new player directly into the player table then we have the disconnect reducer uh it basically handles opposite scenario managing what happens when a client disconnects from the server so when the disconnection occurs the system first locates the player in the player table using their identity and then we can scroll over there we can hit we'll throw an exception player not found so we insert into the logged out player and we delete it from the logged in player table this implementation uses an approach called existence based processing instead of using a simple Boolean flag to track player status while it might initially seem more complex than using a Boolean logged in field this design offers several advantages from a performance perspective this approach eliminates the need for a Boolean checks when processing players when you need to work with online players you simply access the player table directly there's no need to filter through all players to find those who are logged in this design also reduces the memory footprint of the player type which can improve cash efficiency in the application the two table approach also brings Clarity to the C base a player status is immediately clear based on which table contains their data there's no need to check flag values or maintain additional State information this Clarity extends to queries as well finding all online players is a simple as reading the player table with no additional filtering required this shows the principles of data oriented design where data or organization is structured around access patterns and performance considerations by organizing the data this way the code naturally supports common operations while maintaining high performance and clear semantics this approach is particularly valuable in game development where performance and clear State managements are very important now that we've got our food spawning and our player set up let's create a match and spawn let's create a match and spawn player Circle entities into it the first thing we should do before spawning a player into a match is give them a name so let's go to the end of our modu module class and I added some code first we have a new variable start player Mass which is 15 basically the size of the player and the intergame reducer takes one argument which is basically the player's name we can use this name to display as a label for the player in the match by storing the name on The Players row so we're loging created player with name and then we are finding that player and then storing the player's name and then we are updating the player with that that's going to have the name and then we have the spawn initial Circle so we are going to spawn some circles for the player to control now that they are entering the game to do this we choose a random position so we have the spawn player initial circle with the player ID and then we have the random number generator we're we're going to get the the world size just like that we got the starting player mass and here's is where we're getting a random position with the bound within the bounds of the Arena to create a new player entity and corresponding Circle row so either spawn Circle at put in all that information to spawn that new Circle and uh when it says return SP Bond Circle at we're basically calling this we're passing all the information in including the position the time stamp and everything and this is where we are um creating a new entity and then we are inserting a new Circle which is this is um basically how we're setting up the player and that gets returned now let's modify our disconnect reducer so let's go back up to where it the disconnect reducer we are going to modify it so it removes the circles from the arena when the player disconnects from the server so first we're going to get the player here we're going to remove any circles from the arena so circle. player id. filter we're going to get that play So for each circle that's ass with that player we're going to get the entity ID and then we will get do the entity entity ID delete the entity ID and then we're also deleting the circle and then we are inserting the P player into the logged out this is same as before um or it be comes logged out it's and now not a player anymore okay I'm going to save that now we can publish the new module to space time Tob okay now I'm going to finally publish the new module to space time Tob with this command first I have to make sure I'm in the server directory SpaceTime publish D- server local black Holio D- delete data deleting the data is optional in this case but in case you've been messing around with the module we can just start fresh and so it's going to make sure I want I'm okay with destroying the module destroying the data I'm going to put yes okay it's published now let's create the arena we've set up our server logic to spawn food and players so now we want to develop our Unity client to display what we have so far so I'm back in the client Unity directory in game manager. CS so I'm going to add a few methods to this class let me go to the end here and make sure I'm still in the game manager class and I've added two methods set up Arena and create border Cube so basically this is the game area that we're playing in it takes the world size and it's going to call this create border cube four times passing in basically two arguments which is the position that's here they just going to calculate it and then the scale here and you can see we have the the north south east and west side and then here um basically we are creating a primitive Cube object we're calling it border we're specifying the local scale the position and then the material here so let's go to our handle subscription applied method so here is where we can now call our setup area area method what was I saying Arena before area so like it says once we have the initial subscription synced to the client cash we can get the world size from the config table and set up the arena calling the the setup arena with the world size and we can see when this is called this unapplied and then we call the handle subscription applied the unapplied call back will be called after the server synchronizes the initial state of the tables with the client and once the Sync has happened we can look up the world size from the config table and set up set it to our Arena here okay let's save this and go back over to Unity we're in the let's go to the scene view here and we'll select the game manager and then we'll go over to the Border material here and choose um I'm going to choose Sprites default okay let's talk about creating game objects now that we have our Arena all set up we need to take the row data that SpaceTime DB syncs with our client and use it to create and draw game objects on the screen let's start by making some controller scripts for each of the game objects we' like to have in our scene so in this project window uh basically in the scripts folder I'm going to rightclick go to create and create a c script the first script will be called player controller then we're going to do it again and create a circle controller and then we will do it one more time and create a food controller we'll modify the contents of these files later now let's make some prefabs for our game objects and the scene hierarchy window will create a new um a new game object so I'll go to 2D object I click that plus drop down to the object and then we'll go to Sprites and then Circle and and I'm going to name this circle prefab we'll modify the contents of these files later now let's make some prefabs for our game objects so we have this circle prefab object and so in this inspector window on the other side I'm going to click add component and then I'm going to search for the circle controller right here that's the circle controller script that we just made and then finally I'm going to drag the object into the project folder so basically I'm going to click on assets here I'm going to click on the circle prefab and just drag it over here so now we have a reference to it in the in our assets and now we can just delete this object from the scene because we already have it down in our assets we'll use this prefab to draw the circles that a player control RS now we'll basically repeat the same process for the food prefab and the food controller component so I will click the plus 2D objects Sprites and circle but this time I'm going to call it food prefab and then I'll click add component and then we'll bring in the food controller and then I'll move it down to our assets folder and then we can delete it from the scene and then we're done with that so in the project view which is basically this right here I'm going to doubleclick the circle prefab to bring it to the scene View and then what we need to do is right click anywhere in the hierarchy that's over here and then I'm going to go to UI text text mesh Pro basically this is going to be the text of our player name it's going to be a label attached to the circle prefab and you may need to import the TMP Essentials oh it says cannot import package and play mode I'll just have to I forgot that we were still in that mode over here so now let's try it again so basically if you didn't see that I just click the play button to to go out of play mode okay we have import we've imported the TMP Essentials you can see it down in this message at the bottom I can close this and now I'm going to set the transform position of the label uh we can see over here I'm just going to do 0 00 0 so zero position X zero position Y and zero position Z and finally we need to make the player prefab so I'm going to go back to our main M scene here plus I'm going plus and I'm going to add a create empty and I'll call this player free prefab and then I'll go over to the inspector window over on the other side of the screen and click add component now I'll add the player controller so that's just the script that we recently created now I'll drag the object into the project folder just like we did for those other ones and now I can delete the player prefab from the scene let's also create an entity controller script which will serve as a base class for both our Circle controller and food controller classes since both the circles and food are entities so I'm going to go to the scripts folder I'm going to create a new C script and this is is going to be called entity controller so now I'm going to open it I'll basically just go back over to visual studio code and then we we can go to the entity controller. Cs and I'm just going to select all the code and paste in the code uh remember we do have all the code in the description here this is going to provide some helper functions and basic functionality to manage our game objects based on into the updates so we just have all of our Imports very similar to our um our game manager here except we now have the visual scripting so we're see we're setting the lur duration the shade color property and then we're going to have an entity ID but really the basic helper functions are the spawn which is going to find the entity ID that we're spawning and getting the the lurp start position so we have a lot of variables that we're creating um including we have the lurp duration SEC the lurp start position the lurp Target position so one not World feature is that we linearly interpolate or lurp between the position where the server says the entity is and where we actually draw it this is a common technique which provides for smoother movement um I'll check out if you're interested in learning more about that I'll I'll put a demo um in the a link to a demo in the description uh but um it I'm not going to go into all the details and how it works in this in this course but basically we have a we can spawn we can set color by setting the color here and on entity updated basically we are going to be switching a new position on delete we destroy the object and update uh that where we're going to interpolate the position and scale then we have some helper functions uh to convert the mass to scale Mass to radius and Mass to diameter now at this point we are going to have a compilation error if I just save this and if we let it compile we're going to see a compilation error here that's because it says we cannot convert Ty Space Team db. types. DB Vector 2 to Unity engine. Vector 2 so to fix this let's also create a new extensions. CS script so I'm going to go to create C script extensions and make sure I spell it right and then I'm going to go into that script and I'm just going to paste in the code so this is going to help with converting the different types of vector 2os it basically just allows us to implicitly convert between our DB Vector 2 type and the unity Vector 2 type okay now let's open the circle controller script and we'll update this so for a lot of these scripts it was just default but we're going to put in the the new um the new script so basically at the top we are just defining some possible colors for our Circle we've also created a spawn function right here which takes a circle the same type in our Circle table and a player controller which sets the color based on the circle's player ID as well as setting the text of the circle to the player's usern name note that the circle controller inherits from The Entity controll roller and not mono behavior and then we also basically have this the spawn and then the on Delite here okay now let's go into food controller and I'll rep Place some code for the food controller again we set some colors and then we spawn the food and we set the color of the food now let's go to the player controller script again I'm just gonna delete everything that's already in here so here we are defining how often we want to send updates to the server 20 times per second and then we have some important properties I'm going to fix this indenting so we have these properties here um the local property is a stack reference to the local players uh controller uh think of as a way to easily access the player's controller from anywhere in the game and then we got some uh more readon properties that give us quick access to the player's username how many circles they control and whether this is a local player the initialize function or this initialized method is called when the player first joins uh it's going to set up the player's ID and if this is a local player it sets the static local reference and then we have a method for um destroying the function and it will destroy any circles if we have them now let's look at Circle management so we have the on Circle spawn and on Circle deleted these methods handle when circles are created or destroyed these methods handle how the circles are created or destroyed so we add a circle or remove the circle then we have the total mass you can see it says if en is being deleted the same frame that we're moving we can have null entity here and the center of math method is pretty interesting it calculates the weighted center point of all the player circles which is used for uh camera focusing and movement calculations and then we have the on guey it's going to display the player's total mass on screen but only for the local player and then we just got some stuff for testing down here okay now I'm going to create a another script and this is the prefab manager this script we can use as a factory for creating prefabs so let's go over to the code of our prefab manager and I will paste in some new code so we can create some different variables here uh basically this is using a Singleton pattern we have one static instance and we that we can access from anywhere we also have the public fields for prefabs the the circle the food and the player prefab we'll set those up later in the unity inspector now we have awake this runs when the game starts and sets up our Singleton instance then we have the circle controller we can show up show more of it here so the Circle controller is going to first create a new circle from our prefab it's going to give it a meaningful name with its ID initialize initialize it with the circle data and owner tells the owner they have a new Circle and then just Returns the new Circle controller next uh is the the spawn food it's similar to the previous one but simpler it creates new food for our prefab it names it with its ID it init it initializes it with the the food data and Returns the food controller and the player controller basically uses the same format and this basically centralizes all our spawning logic in one place okay now back in unity in the scene hierarchy we'll click on game manager manager and add the add to an add component and add the prefab manager We'll add this script as a component and then we'll drag so we have Circle prefab food prefab player free prefab we're going to add the prefabs we created earlier into the into the slot so I'm go to assets and then here's the circle prefab and then we're going to drag in the food prefab and then I'm going to drag in the player prefab right there okay now I'm going to make sure the scene is is saved time to hook up the data we've now prepared our Unity project so we can hook up the data from our tables to the unity game objects and have them drawn on screen so let's go back to our code I'm going to close some of the ones that we don't need anymore and right now we are going to be working with the game manager remember the game manager is under the client D Unity scripts and then the the game manager so we're going to add a couple of dictionaries to the top which we'll use to hold on the game objects we create for our scene so basically right before our DB connection or right after our DB connection I'm adding these two lines so we have this dictionary of entities um and then another dictionary players now let's add some callbacks when rows change in the database so let's go to the handle connect method and we'll add all these lines here so we'll add we'll add the circle on insert circle on update circle on delete food on insert player on insert player on delete and now for all these we're going to actually have to add the implementations for these callbacks to this game manager class so let me scroll down to the bottom here and we'll add these in the class so you can see on circle on insert we're going to get or create player that's another function that's down below and then we're going to get the uh access to the entity controller with a spawn Circle and then we're going to entity. add we're going to add the with entity ID and the entity controller then we have the entity on update um for the entity on update um we're going to find the entity in our tracking dictionary and if we find it we tell it to update with the new data then we have the entity on delete when the entity is deleted we we try to remove it from our tracking dictionary and if found we tell it to handle its deletion and the rest of them are pretty straight forward food on insert spawn the food using the prefab manager and then add it to our tracking dictionary player and insert we just call the player get her create player with the player which we'll be covering soon player and delete basically remove the player and destroy their game object and then here's that get or create player that I was ref referencing uh it's a method that tries to find an existing player controller and if not if not found it creates a new one and adds it to our tracking and then it Returns the player controller either way all these methods work together to handle our game's State changes okay I'm going to save this and one of the last steps is to create a camera controller to make sure the camera moves around with the player here so I'm going to create a new script uh make sure I'm in the scripts folder a

Original Description

In this Unity tutorial for beginners, you will learn to create your own MMO game with C# and SpacetimeDB. You will learn to create the game from scratch, inspired by agar.io. Tutorial code: https://github.com/beaucarnes/blackholio Full game code: https://github.com/ClockworkLabs/Blackholio Sign up for SpacetimeDB: https://spacetimedb.com/ SpacetimeDB GitHub: https://github.com/ClockworkLabs/SpacetimeDB Import the SpacetimeDB Unity SDK: https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk.git 🏗️ SpacetimeDB for provided a grant to make this course possible. ⭐️ Contents ⭐️ ⌨️ (0:00:00) Introduction ⌨️ (0:01:24) Setup Project ⌨️ (0:07:02) Connecting to SpacetimeDB ⌨️ (0:29:34) Implementing Gameplay ⌨️ (1:10:26) Moving and Colliding 🎉 Thanks to our Champion and Sponsor supporters: 👾 Drake Milly 👾 Ulises Moralez 👾 Goddard Tan 👾 David MG 👾 Matthew Springman 👾 Claudio 👾 Oscar R. 👾 jedi-or-sith 👾 Nattira Maneerat 👾 Justin Hual -- Learn to code for free and get a developer job: https://www.freecodecamp.org Read hundreds of articles on programming: https://freecodecamp.org/news
Watch on YouTube ↗ (saves to browser)
Sign in to unlock AI tutor explanation · ⚡30

Playlist

Uploads from freeCodeCamp.org · freeCodeCamp.org · 0 of 60

← Previous Next →
1 React: Production Server Setup Part 2 - Live Coding with Jesse
React: Production Server Setup Part 2 - Live Coding with Jesse
freeCodeCamp.org
2 cookies vs localStorage vs sessionStorage - Beau teaches JavaScript
cookies vs localStorage vs sessionStorage - Beau teaches JavaScript
freeCodeCamp.org
3 Browser history tutorial - Beau teaches JavaScript
Browser history tutorial - Beau teaches JavaScript
freeCodeCamp.org
4 Graph Data Structure Intro (inc. adjacency list, adjacency matrix, incidence matrix)
Graph Data Structure Intro (inc. adjacency list, adjacency matrix, incidence matrix)
freeCodeCamp.org
5 React: Parameterized Routing with Next.js - Live Coding with Jesse
React: Parameterized Routing with Next.js - Live Coding with Jesse
freeCodeCamp.org
6 React: Dealing with jQuery Issues - Live Coding with Jesse
React: Dealing with jQuery Issues - Live Coding with Jesse
freeCodeCamp.org
7 setInterval and setTimeout: timing events - Beau teaches JavaScript
setInterval and setTimeout: timing events - Beau teaches JavaScript
freeCodeCamp.org
8 Browser and Device Testing - Live Coding with Jesse
Browser and Device Testing - Live Coding with Jesse
freeCodeCamp.org
9 Last Minute Updates - Live Coding with Jesse
Last Minute Updates - Live Coding with Jesse
freeCodeCamp.org
10 Post Launch Updates - Live Coding with Jesse
Post Launch Updates - Live Coding with Jesse
freeCodeCamp.org
11 React: Setting Up Google Analytics - Live Coding with Jesse
React: Setting Up Google Analytics - Live Coding with Jesse
freeCodeCamp.org
12 React: Masonry Layout - Live Coding with Jesse
React: Masonry Layout - Live Coding with Jesse
freeCodeCamp.org
13 Load Balancing Digital Ocean Droplets - Live Coding with Jesse
Load Balancing Digital Ocean Droplets - Live Coding with Jesse
freeCodeCamp.org
14 try, catch, finally, throw - error handling in JavaScript
try, catch, finally, throw - error handling in JavaScript
freeCodeCamp.org
15 Load Balancing: SSL Passthrough Setup - Live Coding with Jesse
Load Balancing: SSL Passthrough Setup - Live Coding with Jesse
freeCodeCamp.org
16 Graphs: breadth-first search - Beau teaches JavaScript
Graphs: breadth-first search - Beau teaches JavaScript
freeCodeCamp.org
17 React: Masonry Layout Part 2 - Live Coding with Jesse
React: Masonry Layout Part 2 - Live Coding with Jesse
freeCodeCamp.org
18 React: WordPress API Live Search - Live Coding with Jesse
React: WordPress API Live Search - Live Coding with Jesse
freeCodeCamp.org
19 Creating WordPress Custom Post Types - Live Coding With Jesse
Creating WordPress Custom Post Types - Live Coding With Jesse
freeCodeCamp.org
20 Dates - Beau teaches JavaScript
Dates - Beau teaches JavaScript
freeCodeCamp.org
21 Miscellaneous Front End Updates - Live Coding with Jesse
Miscellaneous Front End Updates - Live Coding with Jesse
freeCodeCamp.org
22 Merging a Pull Request from GitHub - Live Coding with Jesse
Merging a Pull Request from GitHub - Live Coding with Jesse
freeCodeCamp.org
23 React + Prettier + Standard JS - Live Coding with Jesse
React + Prettier + Standard JS - Live Coding with Jesse
freeCodeCamp.org
24 React: Sortable Responsive Table - Live Coding with Jesse
React: Sortable Responsive Table - Live Coding with Jesse
freeCodeCamp.org
25 Geolocation Sorting by Distance - Live Coding with Jesse
Geolocation Sorting by Distance - Live Coding with Jesse
freeCodeCamp.org
26 Tradeoff Matrix - Agile Software Development
Tradeoff Matrix - Agile Software Development
freeCodeCamp.org
27 The Definition of Ready - Agile Software Development
The Definition of Ready - Agile Software Development
freeCodeCamp.org
28 Getting first React job without experience - Ask Preethi
Getting first React job without experience - Ask Preethi
freeCodeCamp.org
29 React: Google Analytics Click Tracking - Live Coding with Jesse
React: Google Analytics Click Tracking - Live Coding with Jesse
freeCodeCamp.org
30 Submitting a PR to an Open Source Project - Live Coding with Jesse
Submitting a PR to an Open Source Project - Live Coding with Jesse
freeCodeCamp.org
31 Should I go back to school to get CS degree? - Ask Preethi
Should I go back to school to get CS degree? - Ask Preethi
freeCodeCamp.org
32 Hero Section CSS Changes - Live Coding with Jesse
Hero Section CSS Changes - Live Coding with Jesse
freeCodeCamp.org
33 Working Agreement - Agile Software Development
Working Agreement - Agile Software Development
freeCodeCamp.org
34 A day at Pennybox with Co-Founder Reji Eapen
A day at Pennybox with Co-Founder Reji Eapen
freeCodeCamp.org
35 React: Sorting and Filtering Data - Live Coding with Jesse
React: Sorting and Filtering Data - Live Coding with Jesse
freeCodeCamp.org
36 React: Sorting and Filtering Data Part 2 - Live Coding with Jesse
React: Sorting and Filtering Data Part 2 - Live Coding with Jesse
freeCodeCamp.org
37 React: Building a New UI - Live Coding with Jesse
React: Building a New UI - Live Coding with Jesse
freeCodeCamp.org
38 Definition of Done - Agile Software Development
Definition of Done - Agile Software Development
freeCodeCamp.org
39 Getting started with jQuery (tutorial) - Beau teaches JavaScript
Getting started with jQuery (tutorial) - Beau teaches JavaScript
freeCodeCamp.org
40 Making a React Blog with WordPress Content - Live Coding with Jesse
Making a React Blog with WordPress Content - Live Coding with Jesse
freeCodeCamp.org
41 React, NextJS, CSS - Live Coding with Jesse
React, NextJS, CSS - Live Coding with Jesse
freeCodeCamp.org
42 jQuery events - Beau teaches JavaScript
jQuery events - Beau teaches JavaScript
freeCodeCamp.org
43 React/NextJS Routing and WordPress API Custom Types - Live Coding with Jesse
React/NextJS Routing and WordPress API Custom Types - Live Coding with Jesse
freeCodeCamp.org
44 React: Working with API Data - Live Coding with Jesse
React: Working with API Data - Live Coding with Jesse
freeCodeCamp.org
45 React: Refactoring Components - Live Streaming with Jesse
React: Refactoring Components - Live Streaming with Jesse
freeCodeCamp.org
46 jQuery effects - Beau teaches JavaScript
jQuery effects - Beau teaches JavaScript
freeCodeCamp.org
47 More React Refactoring - Live Coding with Jesse
More React Refactoring - Live Coding with Jesse
freeCodeCamp.org
48 animate in jQuery - Beau teaches JavaScript
animate in jQuery - Beau teaches JavaScript
freeCodeCamp.org
49 "Finishing" My React Site - Live Coding with Jesse
"Finishing" My React Site - Live Coding with Jesse
freeCodeCamp.org
50 Starting a New React Project (P2D1) - Live Coding with Jesse
Starting a New React Project (P2D1) - Live Coding with Jesse
freeCodeCamp.org
51 React Project 2 Day 2: Learning Material UI - Live Coding with Jesse
React Project 2 Day 2: Learning Material UI - Live Coding with Jesse
freeCodeCamp.org
52 The Agile Manifesto - Agile Software Development
The Agile Manifesto - Agile Software Development
freeCodeCamp.org
53 jQuery: get and set with http, text, val, and attr - Beau teaches JavaScript
jQuery: get and set with http, text, val, and attr - Beau teaches JavaScript
freeCodeCamp.org
54 React Project 2 Day 3 - Live Coding with Jesse
React Project 2 Day 3 - Live Coding with Jesse
freeCodeCamp.org
55 The INVEST approach to product backlog items
The INVEST approach to product backlog items
freeCodeCamp.org
56 React Project 2 Day 4 - Live Coding with Jesse
React Project 2 Day 4 - Live Coding with Jesse
freeCodeCamp.org
57 Chickens and Pigs - Agile Software Development
Chickens and Pigs - Agile Software Development
freeCodeCamp.org
58 React Project 2 Day 5 - Live Coding with Jesse
React Project 2 Day 5 - Live Coding with Jesse
freeCodeCamp.org
59 jQuery: add and remove DOM elements - Beau teaches JavaScript
jQuery: add and remove DOM elements - Beau teaches JavaScript
freeCodeCamp.org
60 React Project 2 Day 6 - Live Coding with Jesse
React Project 2 Day 6 - Live Coding with Jesse
freeCodeCamp.org

This video tutorial teaches you how to create a massively multiplayer online game using Unity and SpacetimeDB. You will learn how to set up a Unity project, integrate a database, and implement multiplayer functionality. The tutorial covers topics such as game development, database integration, and entity management.

Key Takeaways
  1. Create a new Unity project
  2. Import the SpacetimeDB Unity SDK
  3. Set up a database using SpacetimeDB
  4. Create a game manager script to initialize and coordinate the game
  5. Implement game logic to update and delete game objects
  6. Add callbacks to handle database changes
💡 Using SpacetimeDB to store and retrieve game data allows for efficient and scalable multiplayer functionality.

Related Reads

Up next
Lovable Review 2026 | Is Lovable AI Actually Worth It?
Tutorial Stack
Watch →