Space Commander - Modelling the Game World

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
our space commander game models the game world as a two-dimensional map with all of the game objects moving inside it obeying normal physics of motion so we need to code this model and then translate the game world to our screen world so that the player can play the game let's see how that's done [Music] hi and welcome to bytes and bits we've been coding our space commander game for a couple of videos now we've got the vector graphics working and we're able to define draw rotate and scale the game objects but we haven't yet looked at movement and how we're going to model the physics of our games world and that's what we'll be looking at in this video now if you haven't seen the previous tutorials for this project then please check out the description below for links and don't forget to click on the subscribe button and notification bell to get hold of all my tutorials as i publish them so let's get on with the coding the space commander world is modeled as a 2d space a bit like looking at a map from above objects in the game exist and move in this 2d space and all our calculations will take place in this game world when it's time to draw objects on the screen we'll then map the game world to our screen world to describe objects positions and motions we need to define a few parameters so firstly we can look at the position so this is the x and y coordinates of the object in our 2d game space now screen coordinates tend to use the top left corner as the zero zero origin position with the positive x-axis to the right and the positive y-axis to the bottom now this differs from the conventional mathematical axes which have a positive x-axis to the right but their positive y-axis is to the top now it's really a personal choice but i usually stick to the mathematical model unless the game world is very simple but in this case we'll be modeling vector quantities for velocity and acceleration creating targeting code etc so using the mathematical model just makes it easier at least for me to see how the angles and positions all fit together we can make the game world match the screen world but it doesn't actually save that much computing power and it makes it harder for to get your head around the flipped mathematics now we also need to model the direction so when objects move or rotate we need a way to describe their direction or the way they're pointing using normal mathematical notation this gives us a zero degree angle parallel to the positive x-axis in other words horizontally to the right with positive angles being measured anti-clockwise from this so using this notation it makes all our angles and the signs and cosines and tangent calculations all match up with what we would expect from our mathematics so looking at distance as our world is imaginary we don't have to worry about real-world distance measurements our positions will be easier if we use pixel coordinates so it makes sense to measure all of our distances in pixels as well considering time again we get to choose units of our time we could use seconds but a much more natural measurement inside our code is the game loop so using one game loop as one muted of time it simplifies the whole time process if we set a speed of 5 pixels per loop we simply need to add 5 pixels each time our game loop runs and this but this method can have some problems it does rely on the game loop running at a set speed so in tick 80 our game loop runs at 60 loops per second but if our code gets a bit too complex each game loop can take a bit longer than this 60th of a second to complete so our game will start to slow down and objects will visibly move slower on the screen now if you've ever played any retro computer games you'll have seen this in action we also want the player to be able to fly as far in any direction that they want and this gives the idea of an infinite playing space if we use standard position measured in pixels from a fixed origin we'll hit a problem so in computers numbers have limits if we use an integer variable to model the x-coordinate of the player there'll be a maximum and a minimum value that this variable can store so if you're familiar with other languages such as c you'll understand about using different number sizes different numbers of bytes to store our integers so a single 8 bit byte a single byte integer that can store values from 0 to 255 a 16 integer can store values from zero to 65 535 and so on now if our player were to fly in one direction for a long time the coordinates may reach the limits of our variable for example if we did use an 8-bit integer to store our our x-coordinate we can count up to 255 but as soon as we go one pixel further this will result in an overflow and our variable will wrap back round to zero so to get around this potential problem we'll use the fact that we always want the player to be in the center of our play area so we'll use the player ship as our origin and have everything else moving relative to this so if the player ship is traveling up we keep the playership stationary but move everything else in the world down and this then gives us the same end movement now integrity which actually uses lua all of our numbers are represented by 64-bit floating point numbers and this means that um in reality we're never going to get a problem with our variables over running because the maximum interval that we can get up to is either positive or negative 2 to the power of 53 and and that is a very very big number so you'd have to be traveling for days in one direction but do be aware pardon me do be aware that this is a problem if you're coding in languages such as c and you do need to pay attention to the size of your variables and at least at least now you will know um what will happen if you do do that so we also need to model the position and movement of our objects we know the basics now and the basic parameters that we're going to use to model our data but we want to create several helper functions that will allow us to calculate positions movements rotations and so on now we're going to have a few different types of objects such as our player ship enemy ship missiles stars etc and we could write separate functions for each of these objects for example to rotate them but each of these functions would be basically the same record repeated multiple times and this isn't good coding practice so we want each operation to be handled by a single helper function which will be able to work with all our objects for example we want to create a rotate object function into which we can then pass either a player ship or an enemy ship or whatever and this should then work out those calculations based on whatever we supply it to now this relies on each object in our game storing its model data in a same format so when we create a class or an object definition of each game object it will inherit this data format and this is one of the principles of object oriented programming or this idea of oop and we call this inheritance or we can think of it as each object providing a defined set up to its values and this is an object-oriented programming interface now if you're interested in learning more about object-oriented programming please check out some of my python courses on udemy where i cover this in much more detail and take you through the full coding and and theory of object-oriented programming now antiquity we'll have to implement this idea of inheritance or interfaces manually but as i say in other languages such as python they have that built into their object-orientated programming system so each object in our game is going to have a position attribute with an x and y coordinate and a velocity attribute with an angle and a magnitude so if we want to move our objects in this 2d world as we've already seen the player ship isn't going to move and this position will always be at the origin 0 0 in pixel coordinates but it will have a velocity and an angle and a magnitude so to move the player ship we need to work out its x and y position increments so we need to take it we'll move a small increment and we can term these dx and dy and we have a formula for working these out where we're simply multiplying the velocity magnitude by either the sine or the cosine of the velocity's angle when we come to model the movement of each of our other objects so again because we're modeling everything with vectors with a magnitude and direction we can simply calculate the incremental movements due to their motion and simply add that on to their current position and that will give us then the overall movement of each object in each of our time periods so all the previous calculations allow us to move our objects around in our 2d game world where we are obeying all the mathematical norms for the axes and angles we now need to work out how to draw this on the screen so we know that we always want the player ship pointing vertically and this is a 90 degree angle measured from our positive x-axis so if the player ship is currently traveling at an angle a or omega we would need to rotate the game by 90 minus a degrees to get the ship pointing up the screen our screen coordinates are measured from the top left corner with x increasing to the right and y increasing down the screen so to map our 2d game world to the screen we need to take the game world x coordinate but the negative of the y-coordinate we then need to offset this by half the screen width and half the screen height to move the origin into the center of the screen and this will leave our new position with the actual screen coordinate version of our game world position also as we rotate an object around the origin to position it on the screen its coordinates will change but so will its angle of rotation we know that we need to rotate the game world by 90 minus the player ship angle so when we draw an object on the screen world its rotation will also increase by the same amount so we've now got all the information and calculations we need to code this game world and map it onto our screen so let's have a look at the actual code so moving into tick 80 i've got a little demo program here which lets us have a play with these helper functions now if you have a look in the description below you'll see there are links to my main project page on my bytes and bits dot code uk website and there you'll be able to download the files for this and view the code so you can have a bit of a play with it yourself but what this program lets us do then is we have the player ship fixed in the center of the screen but we now have the ability to move that ship so if i use my left and right arrow keys you can see that that then it's rotating the player ship but of course word have coded it so that the player ship remains stationary and the world rotates around it and we can then of course start moving um forwards and backwards and so on i've also then coded there to be four enemy ships in the um area and you can see those showing there so i've upgraded our enemy ship drawing routine to have all four um enemy ship types in there and we can see that as we rotate those they do behave correctly as we move around the world so in fact they are stationary within this world and my player ship is the one which is moving through it but of course we're getting that sort of effect happening with the playership staying stationary so let's go inside the code and see how that's done so we have a a block of code at the top which is part of the main sort of um getting everything up and running and again we will talk through that and when we come to do the final setup for the game but really what's happening is we need to set up the player ship and the enemy ships and you can see in this little function here where we're initializing our variables we are creating our player ship and initializing that so we create an object an empty object here called player ship and then we start adding in these attributes to it and the two we've been talking about are the position object so we've seen we have here the player ship position and that then is an object itself with an x attribute and a y attribute and again these are the x and y coordinates of the ship in the game world and then similarly we have then the player ship velocity which has both a magnitude and then an angle and i'm initializing the angle to be 90 degrees so that our ship actually is pointing directly upwards so that when we come to translate this onto the screen we're not actually going to have to make any movements because remember we we rotate the world by 90 degrees minus this angle to work out um the relative change going from the game world to the screen world so this just simply means that when we start drawing it our player ships are actually pointing on screen in the direction that we're going to be setting them so that's the player ship and i say these are the two objects then within the player ship which are helper functions are going to assume are there and that they describe both the position and the direction and the velocity of our of our object you can see then we have got a little movement object here and that's going to store the the current change in position for both the x-coordinate and the y-coordinate of our player ships remember whenever we start moving the player ship we're going to need those values to adjust the positions of all the other objects in our game okay so some of the rest that then of course is for the main gameplay when we finally get to that well then if we come down a bit further we have our main tick function underneath that then we have our spawn enemy function and again at the moment this is just doing a test one which is simply going to spawn in those four um enemy ships but again you can see here we are creating our enemy ship object which is in this line here we are then giving it a position attribute which is an object in itself with an x and y coordinates and our velocity again with a magnitude and angle and again that that actually copies the layout then for our player ship so any object which has a position attribute with an x and y coordinates and a velocity tribute with a magnitude and angle if we pass those into our helper functions our helper function will be able to pull that data from it and understand how that particular object has been arranged so let's come down a bit further here and you can see we have lots of other information then that goes into the ship describing its movement but let's go down and find some of our helper functions if we look at our tick function first so remember this is the main loop of our game which runs 60 times per second so really we're checking to see if this is the first time our game has gone through the loop and of course that's where we actually then spawn our enemy ships and so on but our main code then comes in in this block of code here so we're running through a number of functions which will update the various parts of our game so we're going to update our movement parameters and that's where we'll work out how far the player ship has moved we're then going to move our background stars stars we're then going to check our player ships movements we're then going to move our enemy ships and then draw everything on the screen so let's work our way through the code for this so if we go to our update movement parameters so let's come down here and find that piece of code so there's our update movement parameters so this is where we are doing that calculation to work out how far the player ship would have moved in this particular time period remember one time period being one click so we have here our player ship movement remember that was one of the object we put inside our player ship and we have this dx value which is the incremental x coordinate value and that then is the player ship's velocity magnitude times the cosine of the velocity angle and again that's what we looked at when we were going through the theory for this and again our incremental y um position is the similar idea but this time using the sine of our angle so that tells us because we're using pixels as our distance measurement and we're using one tick as our time measurement that then gives us the number of pixels per tick that the player ship is currently moving in both of those directions and we've seen then that that's what we'll be using to update the position of all the other objects in the game so if we go back up to our tick function we will see then that we are updating our background object which i'm going to leave for now we're then doing a check for our ship rotation and our ship acceleration and that's just really looking at the keys that we move our ship with to make sure that we are controlling that correctly so our player should rotation so if we're using the button two then we're going to increase the angle of our um player ship remember so remember the angle which is pointing is the actual angle in its velocity so we're going to increment that by a small amount if we press button three which is the um right arrow then we're going to take a little bit of angle away from that and then we are using a little function here so as our angles are incremented and decremented they can get quite large so remember we we're using radians for our angles so they should be between 0 and 2 pi and of course if we simply hold down say the left arrow button we will simply rotate um in an anti-clockwise direction and our angle will get bigger and bigger and bigger and again it'll go past two pi and then go past four pi as we keep rotating so we just have a little function here called wrap angle and what that will do it will have a look at the angle we supply it and if that angle is outside of the range zero to two pi so i either greater than two pi or maybe it's gone negative it will pull it back into the correct angle within our normal range and again from from a coding point of view inside the computer the computer's not so worried about that but if we ever try to have a look at what's happening inside our code and do some debugging then obviously if we have an angle which is sort of 50 000 degrees or whatever it becomes harder to work out exactly what's happening inside our code so this just simply makes sure that it's more human readable rather than anything to do with the processing inside the machine of course if you are using other languages and you're using very uh smaller precision variables you know it's like an it but variable to um store this information and obviously as you get bigger and bigger um values you do have that problem of the overrun um so so do do bare mind i say it's it's in this particular game i'm doing it just so i can see what the angles are and just so it keeps them in a in a sensible um range um but i say um in our particular instance it's not such an issue after we've checked the ship's rotation then we need to check its acceleration so that's really just looking at the forwards and backwards motion and you can see here we're just checking our up and our down buttons and the only way we we need to work with there is the up button increases the velocity of our ship so you can see here that we are then adding a little acceleration value onto that and again because we are keeping all of our units in in pixels and ticks so instead of this being meters per second squared meters per second for our velocities um these are all in in pixels per tick and pixels per tick squared and so on and again we can just choose those values just by just trial and error we're then limiting those values to maximum speeds and minimum speeds and after that we are then just doing a bit of a check to see if we're very close to zero then it will actually make it equal to zero and that's just to make sure that we can actually come to a standstill so that just sets up then our our ship movement so once our ship is moving and of course that point we will need to work out how far and how to move all the other objects in our in our game world so if we go back up to our tick function which is up here we'll see that um after we've updated our ship movement ideas here we will then go off and need to move our enemy ships so if i come back down and we'll find that piece of code so that is down here okay so at the moment um all we're doing in this particular demo is our enemy ships have not got any movement off themselves so they are stationary within our world which means the only movement that we're going to have to consider is their movement relative to the player ship so you can see here we have a four next loop which is going to iterate through each of the elements in this enemies array and that array will hold each of each element will be one of the player ships so we're then saying that our ship's position is going to be updated using this helper function called move relative to player and that x and that expects to have a position object being sent to it so again this move relative to player function we're going to use that for every type of object in our game so our our enemy ships here but when we come to do missiles and bombs and stars in the background themselves all of those will have to be able to be moved relative to the playership so that when we our playership moves in effect we keep it stationary but then move everything around it so if we have a look at that particular piece of code we have here the function itself so move relative to player it expects a position or a point to be coming into it and it simply moves that point um relative to the player ship so you can see here that it expects that point value so the the object being passed in it expects it to have the x and y coordinates and it simply updates those by taking away the player ship movement incremental value so remember we worked that out at the start of our tick function so the player ships movement for this particular tick we've broken that down into an incremental x value and an incremental y value so instead of the player ship being moved positively by those values we're keeping the player ship stationary and then everything else in the world is being moved um in the opposite direction in effect so that's why we've got this minus sign in here so this will return back this object which of course will have the x and y attributes in it and that will then become the new position for that particular object so again that is moving each of the objects relative to the player ship itself but this is all in the game world model okay so in this test program that's now moved everything inside the game world so our game world has all been updated and what we now need to do is to draw that on the screen so our our player ship drawing function is really just simply putting that icon in the very center of the screen so if i come down here and find our draw ones so we are drawing and draw background and draw player ship so we've seen here that the drawing the player ship just simply puts that icon in the very center of the screen the one which we need to look at though is how we draw the enemy ships and we've seen then that everything in our game world doesn't directly translate to screen position so we do have to modify and translate each of the position and velocity and direction values to make it look right on the screen so again all we're doing here is we are looping through each of the elements in our enemy's array so remember that each element is one ship we're then updating its position to correspond to its screen display position and then we're looking at the velocity and where again we're translating that into a velocity as used on the display again each of these two helper functions expects to have either a position being sent into it so it can then translate that game world position to a screen world position and then a velocity in this one here and it will translate that velocity and angle into a screen velocity and angle so if we have a look at those two functions then so our translate position ones so our position then we can see that it is accepting in a parameter which we know is going to be a position object with x and y attributes so we're saying here we're going to then obviously create a new position based upon that so we need to adjust it by an angle and we said here so the angle which we need to adjust it by is 90 degrees so when in radians that is pi over 2 minus the player ship velocity angle which is of course that's the direction in which the player ship is pointing so our adjusted angle then whatever value we get we're going to wrap that so remember we use this wrap function a bit earlier on and that's just simply taking our angle and putting it into the zero to two pi value so if we do get a value which is maybe negative or something like that it will give it then as a positive angle which is exactly the same angle as the negative value but just in positive radians rather than any negative radians we're then going to calculate using that angle we're going to calculate the new position so we need to rotate our point around the origin so remember the player ship is actually at the origin of our of our game world so we need to rotate this particular point around that origin by this angle and that's what this rotate point function does for us now if you've been following through the previous tutorials on this game you'll know that we've actually used this function already so this rotate point function we use that when we actually draw our vector shapes so again this is just making sure that we create a series of general purpose helper functions that we can use throughout our game to perform the same operation over and over again so again we're simply rotating a point we specify the origin around which we want to rotate it by and then we give it an angle by which you want to do it and that will return us back a a position of this rotated point and that's what we just simply then say here so that's the rotated point position and then as we said in our in our discussions we to get that to be a screen display pixel value we need to both invert the y value so there we have our x value is staying as itself our y value is being inverted and then we're moving the origin into the center of the screen by giving it these little screen offsets so at the end of this function this new position object will be our input position parameter which has been rotated flipped and offset so that it now is a true pixel coordinate for this point on the screen so now we've got the position sorted out we of course need to translate the angle of our object and that was the second call that we made there where we have this translate velocity to display we're passing in the velocity um attribute from our object remember that's going to contain at both a magnitude and an angle in this particular function all we need to do now is work out what is the angle that our object should be pointing when we draw it on our screen world so we can see here we're creating a new velocity um and we're then assigning it an attribute so the the angle of that is going to be our existing velocity angle so this is remember this is the game world angle which is being sent in through this parameter we're then going to add on 90 minus the player ship velocity and again that was from our discussions on what that how that works we then have our our new velocity angle we're wrapping it again so that it stays inside our zero to two pi range the magnitude we're not having to adjust that because that of course just stays the same all we need to do here is make sure that our ship is pointing in the correct orientation so that it looks like it is being moved um around the player ship and then we simply send that back and of course that then is being stored um within our drawing function so if we go back down to our drawing function then so now that we've got our screen position and in effect our screen angle worked out we need to store that for this particular ship so remember we're working through each of our enemy ships so we store at the screen position inside our object we're then doing a bit of a check here so we can have a lot of ships flying around in our game world but we won't be able to see all of them all the time so there's no point in us going as far as drawing all the vectors which make up a particular ship if we can't actually see it on the screen so what we're doing here is we're just checking if the if the current ship's position is outside of our visible range so that's what we're doing here and we're simply checking that as a rectangular area we're not actually doing any sort of pythagoras theorem or or calculating distances we're just doing a very simple if if it's too far off to the left or right or up or down then we just don't draw it but if we if it is within our visible range then we are blanking out a an object on the screen so we're drawing a little circle and that gets rid of any of the background stars and so on and then we're using our draw object function which is the one we've been using all along we are send telling it to draw a particular type of ship we're then giving it the positions remember this is now the screen coordinate position and this is now the screen angle that we need it to be pointing in and at that point our our drawing and movement is all finished so if we go back to have a look at the at the running um example then so if we go back and do that we can see here that when we start off then remember we said that our ship was traveling at 90 degrees so in other words traveling directly upwards anyway which means that when we draw our alien ships which are spawned at an angle zero then we can actually see them actually at that angle zero so if i then rotate we should find then that the ships both rotate around the player ship but also rotate on their axes so that they should always be pointing at perpendicularly to where the ship is so if we come right here you can see that we have that um happening so they are rotating around and when we get back up to the top again it's as if they had had never moved okay so that shows us then that our our functions are all working correctly if our ship starts to move we can see that our player ship stays in the center of the screen but it does look as if our player ship is actually moving all the stars are moving correctly all the player all the enemy ships are moving correctly so it does look like our player ship is moving through our game world even though as we already know now it's our game world is moving around our playership so that is all of that bits of code working now we can of course get a little bit more complicated with this so if i look up a separate demo program here so if i have a look and see we've got in here so it was the world rotate to and if i run that we can actually code our player ships to move themselves so what's happening here is again after um we update our playership movement we then have a little piece of code which is going to continually just move our player ships or our enemy ships and constantly change their direction so that they simply move in small circles and of course our our move enemy ships function now not only has to move them relative to our playership but they also then have to incorporate their own individual movements and again i'll i'll put this code on the main project page so you can download that and then have a look at it but it is pretty much just exactly as we've done just with the added complication of putting in the enemy ship movements on top of that so we've now got everything we need to model our game world move all of our game objects inside this world with their positions and velocities and so on we can then translate this game world onto our screen world so that we can display that then for our player to play the actual game so the next things we need to do are to actually start building up the actual gameplay and that's we're gonna work on in our next tutorial so hopefully you've enjoyed this video if you have please do subscribe to my channel every subscription helps a channel grow and lets youtube know that i'm actually producing some useful content so i look forward to seeing you in one of the next videos and bye for now don't forget to visit the course pages for this project there you'll be able to download the code for this lesson and get lots of extra hints and tips you'll also get access to all my other programming electronics and gaming projects all the links are in the description below for more games programming electronics projects and retro gaming please make sure you like this video subscribe to my youtube channel and visit my website
Info
Channel: Bytes N Bits
Views: 295
Rating: undefined out of 5
Keywords: tic80, games coding, learn to code
Id: lXHKOVb8s9Y
Channel Id: undefined
Length: 39min 7sec (2347 seconds)
Published: Sun Jul 18 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.