Code-It-Yourself! Asteroids (Simple C++ and Maths!)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello let's make asteroids asteroid is a game where you control a small spaceship that floats around in space and it follows all of the physics you would expect to see in space and you can flush the ship and rotate the ship and you shoot bullets to try and break up the asteroids if you hit an asteroid it's game over it starts again and if you manage to clear the screen of all the asteroids which admittedly in my version of it here is actually not very difficult to do he says firing aimlessly all over the screen then you get two more asteroids to shoot at guaranteed not to appear where the player is and your score increases it's really about how long can we survive when I started this project I expected it to be quite simple I was going to use some sprites for the asteroids and just move them around on the screen however it quickly became apparent that was rubbish and so I decided to go back to how the original was done an implement of vector graphics framework and this means I have to give a little warning upfront there's going to be some mathematics in this video you often hear people say that to be good at programming you need to be good at mathematics and I don't think this is necessarily true in fact I think the majority of programming actually involves rather trivial mathematics or here in the UK we would call them simple songs but if you're going to do games with slightly more advanced 2d graphics or full-on 3d graphics you're going to have to know the mathematics behind it there's no getting away from it but and with this video I hope to show with a simple tool kids of maths you can achieve quite cool things let's get started I shall be well aware by now I'm currently using the one loan code a game engine for pretty much everything this allows me to do graphics and input in the console at the command line so here I've inherited from the console game engine and we typically override the two functions on user create a non user update this one updates the screen and this one is called when the application launches and at the moment all the on user update does per frame is clear the screen it fills it full of black pixels in my int main I creates an instance of the game engine and in this case I've set it to 160 characters wide by characters tall and each character is eight by eight pixels asteroids only contains simple objects the ship and the asteroid and these are things that float around in space so I think we'll create a struct to represent these objects so let's create a simple struct and we'll call it space object and this object contains some simple properties firstly x and y coordinates for its position ie where it is in space and we'll also include some velocity coordinates and we'll come back to that in a minute so this will be the speed and direction that the object is traveling in I also know that most of my objects are going to be asteroids and they change in size so I'm going to store that here too I've got different types of objects in the game so I'm going to collect them together in vectors so this vector is going to store the asteroids but now let's populate this vector with a single asteroid I'm just going to use the initializer list to do this so I know that this is cheating a little bit but I know that the format of my struct is such that the first element is at the x position so I'm going to say that that's xx and I know that the Y is the next one well to some velocities let's say 8 and -6 so this is how much it changes per per frame modulated by F it elapsed time of course and finally we've got the size which I'm going to force it to say I'm an int that'll allow the initializer list to compile properly if we didn't tell if it was an integer it might think it's a short or a char or something else let's take a minute to do a very brief kinematics reminder ie the study a very simple motion we know that at any given time an object is at position P if an object changes position let's say it moves to p2 which is a new position from an old position that's got to take time and that of course gives us velocity in most the same way we can think about acceleration because if we've got a change in velocity - is also with respect to time it goes without saying then that if we know our original velocity the time that's passed and our acceleration we can calculate our new velocity which in this case becomes V 2 equals a multiplied by time plus V 1 and the same applies for our velocity we know that our new position P 2 equals the velocity times time plus the original position we'll use these very simple equations to update the position of our objects on the screen but let's not forget that P is actually an X in a y coordinate and so therefore V and a must also be directional they need to be vectors I'm going to update and draw the asteroids at the same time and I'm going to use a little for loop to iterate through the vector so using the equations we've just done we know that the x position of the asteroid needs to be updated by the velocity vector times the elapsed time and don't forget that this F elapsed time variable is the update between successive frames it's the time taken between one frame and the next and that allows us to run the program at a known speed across a variety of different computing systems I've just spotted error number one I've put this in the on user create function that's no good we need to do this on the on screen update we do exactly the same for the y coordinate in fact there won't be any situations were updating just X or Y on its own we'll always be doing things in pairs to see if the motion is sensible I'm going to draw the asteroid as a rectangle for the time being so I'm just going to iterate through X's and Y's according to the size of the asteroid and I'll use the draw function to draw a pixel of these locations let's take a look so we can see my asteroid drifting through space and oh it's gone off the screen and we'll never see it again and this is the first part that makes asteroids quite a challenging game to make we want all of our space objects to wrap around the screen which means we need to think about how we map information to the screen currently our screen is just set up as a standard two-dimensional array it's a grid of pixels but what we want an object to go off the edge of the screen we want it to appear on the other side so we need to wrap it all the way around and bring it back so if we create a system where we know that this edge is actually the same as this edge we can start by drawing that edge well we know that we need to wrap around like this and in fact it looks like a cylinder and this can be implemented by whenever we go beyond the screen width which would happen to be on this side we reset to zero but it gets a bit more complicated because we also want to wrap in this direction we want anything that goes over the top to also loop back round to the bottom and it may be tempting to think that we're treating this as some sort of sphere but we're not because a sphere can't maintain a standard coordinate system you've got to have some distortion as you go around it so as you can see at the top and bottom of the sphere all of the pixels get very close together as we go around the sphere around its equator we get larger pixels so this is a distortion and in fact if you want to wrap a 2d array around both its X and y axis you need a torus or toroidal mapping and with this mapping we've got equal spacing going around that way and equal spacing going around that way I've got a feeling we're going to need a mapping like this quite a bit for this game so I'm going to create a function which takes a set of coordinates and wraps them around using a toroidal mapping I'm going to call it rap coordinates and it's going to take an X and a wires and inputs we'll call those IX and iy and it's going to output o X no y so the first thing I want to do is set the output to the input and then I want to check if the input is beyond the boundaries of our array so let's take the x-axis first so if the input X is less than 0 then I want to adjust my output to be the input X plus the current screen width which is an integer that's why I've casted it to a float so let's say I X is minus 5 we end up setting the output to being screen width minus 5 so it goes to the other side of the screen likewise we can go checking if the input X is greater than screen width then we update the output again naturally it's exactly the same for the y-coordinate except instead of screen widths we want screen Heights now we've got a function that will create the toroidal mapping we can always update our space objects to make sure that this stay within the game space it's just a case of passing the current position x and y into the function and we get them back so it looks a bit strange this but it's valid let's take a look so we can see our asteroid now drifting off one side of the screen and it's appeared on the other well there was a slightly undesirable artifact there let's see it again when it goes off this edge of the screen we know that our rectangle is referenced on the top left so we don't see the top right of the rectangle peer on the other side and this is because even though our objects can be wrapped around using this coordinate mapping system the graphics routines in the console game engine can't they've done not a word of it they don't know that this should wrap around so we're going to use some polymorphism to our advantage in the console game engine all of the drawing functions ultimately call the draw function and this plots a single pixel to the screen so what I intend to do is to override this draw function to take advantage of our new coordinate system we need to make one change to the console game engine here I'm going to say that this method is virtual since I'm going to override it I'm just going to copy from here and create a new function in our new class underneath the wrap coordinates now we've overridden the draw function we need to use our wrap coordinates function so I'm going to create some temporary variables FX and FY and I'm going to use our wrap coordinates to take the requested inputs the x and y so this is wherever the drawing routines want to draw the pixel on the screen I'm going to generate the new FX and FY which are the wrapped coordinates then I can call the original draw function so not the one we've just over with the new coordinates and if you've ever needed an argument for object-oriented programming this is it with just this very simple change we've now changed the nature of some fundamental parts of our drawing engine so as we can see the rectangle goes off the screen but it draws appropriately at the bottom we'll see again as it's going across so the drawing routine wraps around automatically and so this has given us two different spaces one is game space which contains the asteroids and the ship and they're having the central coordinates wrapped around and the other is the screen space which is also using the wrap coordinates function the two are separate and we'll be doing all of the collision detection an actual game engine in game space and all the rendering happens in screen space now it's time to start thinking about how we add the player you know that the player controls a spaceship that can be rotated and so one property we need to store for the player is the angle of rotation we also know that the user applies thirst and so this adds acceleration in the direction the ship is facing in space nothing slows the ship now that's why it drifts across space so in order to slow the ship down you've got to turn it around the other way and apply thirst like a brake and it's this that makes the game quite challenging since it looks like angles are important I'm going to add them to the space object and so we'll also have to update our asteroid initializer we'll just set the angle to that to zero and we'll create another space object which is the player in the unused create function I'll initialize the player to be in the middle of the screen with no velocity and no angle now in quite a few of my videos you'll have seen me use sine in cars quite a bit I thought it'd be useful to understand why so let's assume I have an angle theta and I want to work out a vector related to that angle let's have a look on an axis so we've got why in that direction X here and we've got some vector to that point and we've got this angle well let's simplify it for a moment and assume that our angle is zero degrees therefore on our axis we know that our point lies somewhere on the y axis so we can see it has actually no components in the X and we know that sine of zero degrees equals zero and cause of zero degrees equals one if we take a point along the other axis this time we know that our angle must be 90 degrees change those from 90 s sine of 90 degrees is of course 1 and cos of 90 degrees is of course zero and these two functions are great because they will give you a circular line between the two points and in fact it keeps going around and draws a full circle with just these functions it generates a circle with a radius of 1 which means that if we treat our x and y as components of a vector we get a unit vector and this is very useful let's add some controls so we can steer the player so we'll just look at the M Keys variable and if the user is pressing the left key or holding it down even then we just want to adjust the angle of the player by a little bit it's exactly the same for the right except in the other direction so the negative becomes a positive first however is a little different the player will thrust the ship forward if they're holding down the up arrow but since we don't store thrust as part of our space object we need to update the velocity instead so for the x-axis we're changing the X velocity by sign of the player angle time so I'm going to pick a number at random here 20 times F elapsed time and as we've just seen with the maths altering stuff in the y axis uses the COS function so by doing this we know that we get a vector related to the angle that the player is pointing in and we can use that vector as our velocity vector but there's one little change to make that is we've got quite a little minus sign in front of the cars and that's because our screen is upside down that's not how maths works so as we learned earlier we know that when we change velocities we're using acceleration and of course that is what our thrust is so acceleration changes the velocity with respect to time and we can use a similar set of equations so now update the position using the change in velocity so velocity changes the position with respect to time so I take the player's x-coordinate and update it by its velocity vector that we've just calculated multiplied by F elapsed time let's not forget that our spaceship is also an object floating around in space so we'll need to wrap its coordinates 2 to keep it within the game space so now we get on to the fun part how do we draw the ship I could represent the ship as another rectangle the problem is I don't have any route teams to draw a rotated rectangle also it's not very useful it doesn't tell the player which direction the ship is facing so you don't know which way the bullets are going to go and he doesn't know which way the acceleration is going to be like when he presses the first button fortunately and this is becoming a theme with this video maths can help us out let's consider using an isosceles triangle as the ship so it's clearly pointing in the pointy direction we can see that this coordinate is about minus not minus five this point is minus two point five and the y coordinate is two point five and this one becomes plus two point five two point five whenever we see 2d coordinates don't forget we've actually got a vector from the origin so we've got one back to up there one vector there and one back to there and as we've seen previously we can use trigonometry to do things two vectors we don't need to worry about the lines so much because once we've got the points we can use the game engines draw a line utility to draw lines between them the abilities have wireframe objects on the screen once we've got a set of points we can use matrices to transform them now this video isn't going to be a full-on video about how matrices work but it'll give you enough to get going I see matrices is just a convenient way of grouping similar equations so if I have my input points x1 and y1 I want to get an output x2 and y2 I want to do some sort of magical transformation between them if I want to do nothing I create what's called an identity matrix which looks like this it has all ones in the main diagonal and you perform this matrix multiplication operation like this we take this component and multiply it by this component then we take this component and multiply it by this component and finally we take both of those and add them together so if I write this out what this becomes is x2 equals 1 times x1 plus 0 times y1 it's exactly the same for the second component the y0 gets multiplied by the X 1 this one gets multiplied by this y 1 and these two results get added together to give us y 2 so in this case we can see we have 0 X 1 plus 1 y 1 ultimately this of course resolves to X 2 equals x1 and y2 equals y 1 it's boring but I said it doesn't do anything this is a null matrix it does no transformation that's said if I make a simple change to this matrix for example change this one and this one if we change these to say 3 & 5 then our equations below the ones also change to 3 and a 5 and so therefore in this case our outputs x 2 equals 3 times our input for the X and for y it equals 5 times the input in short we have scaled our original point and so if we took that scaling matrix and applied it to our points we get a different size ship we've scaled by 5 in the y axis and these points would become because we've scaled by 3 in the x axis and 5 in the y axis even though matrices may appear intimidating don't forget they're just a notation for describing a set of simultaneous equations this simple example was of a scaling transform matrix however we're not going to scale the ship but we might want to scale the asteroids later on so we'll come back to this what we're more interested in doing is rotating the ship rotation matrices for more complex and Wikipedia has some excellent resources on how they're derived and how to use them in fact it does for all the 2d transform a in matrices but for completeness and for this video I thought I'd show how I can derive a rotation matrix because I feel as a programmer it's always useful to understand why I'm doing does what it does so when it goes wrong I've got more hope of understanding the problem let's assume I've got two points p1 and p2 and I want to rotate p1 to be in the position of p2 this problem becomes challenging because I might not know what the original angle of my point was all I know is that I want to change it by small amount let's just label these angles so we can keep track of them we know from earlier that we can represent our points using sine and cos I'll call that p1 x MP 1y or we can see in a similar way that p2 is actually the sum of these two angles so we could write this out as p2 x equals cars angle 1 plus angle 2 and p2 y equals sine of angle 1 plus angle 2 now our problem is we might not know what angle 1 is all we know is we want to rotate it by angle 2 so we can use some trigonometric identities to help us out when you've got cars and two angles added together you can also represent that as cos of angle 1 multiplied by cars of angle 2 subtract from that sine of angle 1 multiplied by sine of angle 2 and this is really neat because here we've got cars of angle one is also our original point and sine of angle 1 is also our original point in the y axis so we can rewrite our equation as simply being p2 x equals p1 X car's angle to minus p1 y sine angle 2 so now we have a way of creating our new point based on information that we know we know our existing points location we know the angle we want to rotate it pi we know enough to perform the transformation the y-axis uses a similar approach but it uses a different identity when we've got the sine of 2 added together angles the identity looks like this sine of angle 1 multiplied by cos of angle 2 plus cos of angle 1 multiplied by sine of angle two and just as we did before we can use a very similar approach we can see that sine of angle one is the same as our original point so knowing that let's write this one out as well for p2 y equals p1 y in this case times cars of angle two plus p1 x times sine of angle two and just as before we've got all of the information we need to solve this but if we just swap these around and we can do this just so everything is consistent what we see is we've got a matrix operation and this is in fact our rotation matrix so we've now developed a matrix for scaling an object we developed a matrix for rotating an object there isn't really one in 2d for translating an object that is moving it across the screen you just add a vector to the points so why was all that necessary well if we define our ship as a set of three points in the triangle as we saw before we can use matrix operations to manipulate to these points I'm going to create two more arrays to store the transformed points so the idea here is the model never changes but what we draw to the screen is the transformation of the model and this is how all wireframe graphics work in fact it's how all 3d graphics work even in the most modern of games if you want to be a game programmer particularly a modern day games program but you're going to need to become familiar with matrices and vectors when applying transformation matrices it's quite important to do it in the right order or else you'll get odd results so the first thing I'm going to do is rotate the model and this assumes it rotates around the origin of the model which as we saw before was zero zero and all this for loop does is go through all of the points in the model and multiplies them like the matrix versus the vector that we've just seen but the angle that we want to rotate by is the player angle so we can rotate the model triangle in the direction the player is facing once the model has been rotated I then need to offset it to where the player currently is so I need to set it to the players X&Y coordinates where the position vector of the spaceship once I've rotated and translated I want to draw it to the screen so I'll create a loop which goes through all of the points and draws lines between them you see goes up two points for that's because there's one more point here than that in the model and by using the modulus function in here and make sure that I get all three lines drawn and don't forget the draw line routine calls the draw function which we've already overwritten with our wraparound function let's see how this all comes together so I can see a triangle in the middle of the screen and I'm pressing the arrow keys to rotate it and I press the up key to apply some thrust and of course there is no break in this so the ship will just carry on drifting and as it went over the edge of the screen the draw line routine worked quite satisfactorily the thing is now that we've developed a system for rendering wireframe models are rectangular asteroids well they look a bit rubbish so let's make them as wireframe too because I don't want to repeat this code I'm going to wrap it up in a function that draws a wireframe model so the draw a wireframe model function takes in a vector of pairs and these pairs are the x and y coordinates so we can define a model and give it to this function and when we draw it we call a position X Y where on the screen do we want to draw it we have an angle of rotation we have a scaling factor and we have the color that we want to draw it and here we can see in the comments that the first element of the pair is the x coordinate and the second element is the y coordinate and the first thing this function does is create another vector to hold to the transformed coordinates we don't want to change the model coordinates each time they've got to stay static so I create another vector the same size and I do the rotation then I apply the scaling matrix then I translate it and then I draw the polygon exactly the same as we've done before but now we can draw any kind of model that we want so all of this original ship drawing code can go now bye-bye and instead we'll create a vector of pairs of floats some will call that wreck model ship and we'll define the model in the on user create function we're simply using an initializer list so there it is there's our spaceship simple isosceles triangle so now we want to draw the ship we call the draw a wireframe model function send it the the model the offset where it is in space and the angle of rotation let's just double check make sure that works excellent we'll just have a quick test of the scale so currently everything is a unit vector and we've scaled everything by 1 that's the default parameter passed through the function Alice I want to make everything 5 times bigger really we get a much larger ship but it behaves in exactly the same way we'll leave that at 1 for now so I probably want the same thing as a model for like one of my asteroids but instead of manually defining all of the coordinates I'm going to algorithmically do it so I'm going to assume that each of my asteroids contains 20 points ok little for loop to iterate through them the middle of the asteroid is assumed to be 0 0 the origin and each of the points are going to lie on a circle or a particular radius which I'll say is 5 since I've got 20 points that effectively gives me 20 segments in my circle and since the circle consists of 360 degrees I want to break up my segments into degrees per segment and so this line takes which particular point I'm on as a percentage out of all of the points and multiplies that by 2 pi adding the point to our model is easy because it's a vector we can use the pushback function but we've got to make a pair of coordinates and by now you should know what this is because it's for the x-coordinate is radius times the sine of the angle and for the y-coordinate it's radius times the COS of the angle isn't it great how all these things come together now we've created a model of the asteroid we need to draw it we no longer want to draw the rectangle like we did before so that can go what we can do is take our player ship drawing routine the draw wireframe model change the model to asteroid want the asteroids X location the asteroids Y location now the asteroids angle doesn't really matter so much at the moment let's take a look nice we've got a circle of radius 5 instead of scaling by specifying the radius here I could set that to one to give us a unit circle and in our draw routine we can use the size of the space object as our scaling factor let's take a look we can see it's a much larger circle now well you can't have a game of asteroids without bullets so another vector of space objects BEC bullets once we've updated the players position we'll check to see if the player has released the space key and if they have to the vector of bullets I'm going to push another space object bullets will originate at the player location X&Y they will have a velocity of their own which of course the direction of which is inferred by the sign and cars of the player angle bullets move a high speed so we'll set that to a high value the size doesn't matter and the scale doesn't matter but just like we do with the update and draw asteroid function we need to do the same for bullets so I'm going to start by copying a large part of that the bullets position is updated by the velocity and we need to make sure that the bullets stay within the game space drawing the bullet is very simple it's a single pixel and it's white that's the default setup for the draw command let's have a look some bullets um we can see them wrapping around the screen the origin of the bullets is wherever the player starts but I see a growing problem here there is of course far too many bullets on the screen we need to have some way of killing a bullet and the way I'm going to do this is any bullet that has gone off the screen is dead we're going to remove it from the vector of bullet removing off screen bullets is made much easier with modern see first thing I want to check does the bullets vector contain any bullets and then I'm going to use the remove if function from the algorithm library as part of the standard library and it works a bit like this it's going to return an iterator the remove if function doesn't actually remove anything it sorts the vector of bullets in such a way that anything that fails the if criteria is at the end of the vector so we want to pass in some iterators to say which part of our vector of bullets do we want to inspect well we want to do the whole thing so we're going from begin to end and now we need to pass it the criteria and of course being rod and C we do that with a lambda function so my function is going to take a type space object so in this case actually it's going to return true if the bullet has gone off the screen so that way the remove if function knows to remove it from the vector so if the X or Y position of the space object is less than 1 it's off the screen it gets removed we also need to check against screen width and screen height the returned iterator from the remove if function points to the start of all of the bullets which we can remove so we'll call the erase function well we'll make sure that there's actually something to erase first nice little crash so if the iterator is not equal to the end ie there is something to remove remove it and as you can see now when the bullets go off the screen they disappear you can also see they're not destroying the asteroids but nor is my ship crashing into any asteroids time to our collision detection fortunately an asteroids collision detection is very simple because everything is represented by a point so we know the center of the player ship is a point and we know the center of a bullet in fact a bullet is just a point and that our asteroids are also represented by a point so we can check all bullets against all asteroids to see does a bullet exist within a circle defined by the asteroid size and its central point the same applies to the ship and this gives the player a little bit of an advantage because if the ship is like this with the asteroid it's safe however if the ship is like this with the asteroid the ship gets destroyed and checking to see if a point lies within a circle is very simple indeed we calculate the distance between the two points and if it's less than the radius of the asteroid then the point must lie within the circle so it becomes if the square root ax take be x squared plus a why take be Y squared it's less than in this case size then we know a collision has occurred because we'll be doing a lot of collision detection let's create a function which checks is point inside circle now it simply takes the origin of the circle and its radius and the point and returns true if the point lies within the circle will do the collision detection when we update the bullets even though we're iterating through all the bullets we'll need to also iterate through the asteroids again and this could cause problems if you lots of asteroids and lots of bullets but for this simple little demonstration game I think it'll be just fine and we'll just check if his point inside the circle we give it the asteroids coordinates and size which is the radius and we give it the bullets coordinates then a collision has occurred when we hit an asteroid we need to do two things the first is we need to remove the bullet I don't want to remove it directly from the vector we're currently iterating through that'll cause it all to crash but fortunately we have a routine down here which will remove any bullets that have gone off screen so to remove the bullet I'm going to force it to be off-screen it'll get tidied up later on each time we hit a large enough asteroid it's going to split into two asteroids that are half the size it's no coincidence that I chose 16 to be the starting side so when we hit that asteroid will create two size eight asteroids and when we hit those will create two size four asteroids and I think four will be small enough else will become very difficult to hit so if the asteroid that's just been hit is larger than four we want to create two-child asteroids but I want to give the illusion that the asteroids have had some sort of impact so I'm going to choose a random angle and all of this is a nice way of choosing a random floating-point number between zero and one and then multiplying it by pi so I'm choosing a random angle between zero and two pi in this case and I'm creating two child asteroids so I want to do that twice however I don't want to do any changes to the asteroid vector because I'm currently iterating through it and it'll crash so I'm going to create pree vector outside of these two loops to store new asteroids so any asteroids I create get added to here and once we've come out of those four loops iterating through the vectors we know it is safe to change them so I'm going to append all of the new asteroids to the existing vector of asteroids now I can safely create new asteroids so again using my initializer format like I did at the start we want to specify the X&Y now fortunately these can be the same as the parent because in the same location my random angle I now need to convert to velocity coordinates you must know this by now I'm going to choose some numbers in this case it's ten times sine of angle and for the why the velocity why it's cos of angle I now need to specify the new size remember we need to cast it to an int when we use this initializer approach but it's easy enough because I can just bit shift it to divide it by two and the completeness will set the angle of the space object to zero so that's created one asteroid and that's created another will just change this angle angle to but there's still one more problem the original asteroid that's been hit is still in the vector we need a way of removing it without corrupting the iterators well we did something similar with bullets so I'll do the same for the asteroids if the asteroid goes off the screen I am going to force it to go off the screen then it's going to get tidied up it's exactly the same code in fact I'm not going to bother checking for all edges of the screen this time because I know that to kill an asteroid to remove it from the game I'm just going to set its x-coordinate to minus 100 so to kill the asteroid I'm going to deliberately set its position to minus 100 we know it'll be cleaned up by the routine later on let's take a look I've got a ship a fire a bullet it splits into two and each gets a little random direction and I can keep doing that until I've killed all the asteroids I suppose you best put in a way to kill the player testing to see if the ship has hit an asteroid is just the same as checking the bullets we iterate through all of the asteroids and we see is the point inside the circle but in this time the point is the players x and y-coordinates and if it is we set a variable be dead to true so I'm going to add a variable to our class now what we do in the event of the player dying well really we want to reset the game and to do this I'm going to create a reset game function I'm going to take some of the stuff out of the on user create function particularly the dynamic variables so the players location and the vector of asteroids I'm going to make sure there's nothing in that vector before I add to it I'm also going to get rid of all of the bullets and we've only got one asteroid floating around at the moment so I'm going to I don't know there I'm going to change up the starting position and starting velocities so it doesn't just mirror what the other asteroid is doing we know one should reset the game we're no longer dead either and because we've got the reset game function nicely untidily starting up some game data we'll also put that in the on user create and this shows how the on user create function should be used we're creating static resources we're not using it to define an initial state of the game so if I crash into this asteroid it resets I'll just try that collision detection on a smaller asteroid he says there we go so the player can track their progress let's add a score we'll initialize that to zero and of course we need to put that in our reset game function the scoring system will give you some points each time you destroy an asteroid so we need to look in our bullets and asteroid collision detection routine we know here we've hit an asteroid so we'll increase the score you can have a hundred points for destroying an asteroid there's no point in keeping a score if the player doesn't know what it is so we'll draw that in using the draw string function but what happens when the player finishes the game we can check for this condition by seeing if there are any asteroids left in the asteroids vector if it is empty then the player has destroyed all the asteroids so that's great let's reward them by giving them a big score but we'll also recreate the level we won't use reset game we don't want to just keep giving the same data each time but also we need to put the asteroids in a place this isn't on top of the player so we don't instantly kill the player the safe is placed to put some asteroids is either side of the player offset by set distance so if we know in our game space we know what our player angle is if we take a vector that is 90 degrees to our player angle on both sides we can place asteroids here we know that the starting size of our asteroid is 16 so as long as we position them further than 16 away from the player then the asteroids won't collide with the player when we put them on the game the two new asteroids just get pushed directly into the vector of asteroids using the initializer list again the first two parameters are the x and y coordinates which I've chosen here to be 90 degrees so that's PI over to either side of the player angle I then set the velocity vector to have a magnitude of 10 but it's also facing in the player angle I don't want the asteroids to start off and then immediately crash into the player I'm going to have one asteroid go forwards and by flipping this player angle here I can have one move backwards all this math you might be thinking well hang on you might have just placed the asteroids outside of the game space but that's okay the next time the asteroids get updated the rapp coordinates function will take care of that for us so now I'm just on the brink of almost cleaning up all of the asteroids and it creates some more for us our asteroids don't look very asteroid e let's see if we can do something about that when we create the asteroids we're really just plotting a circle and we do this by using our sine and cos functions to create all of these extra points however perhaps if we create these points with a plus or minus error margin we'll get a less circular shape but it'll be a closed polygon nonetheless so you can imagine that gets a point there this one here this one there this one here this one here here here etc and when these get drawn we end up with a far more interesting shape this is simply a case of changing our radius from one to some random number but it's got to be a fairly well tuned random number I know on the whole I want my radius to be one but I'm going to add point two margin of error which means I need to offset it by 0.8 for the minimum distance and it'll become one point two for the maximum distance I'm also going to change the color of the asteroid for good measure that's quite nice wobbly asteroid ething since our asteroids have an angle as part of their space object we could get them to rotate slightly very simply when we update the asteroid we can modify its angle too and we'll just pick a constant for this and because we've put all the effort into creating a wireframe rendering engine that can take rotation matrices it's very simple to add these sort of effects I could go to the efforts of making sure that our bullets interact with the asteroids in a very accurate way since they're no longer circles but I'm not going to I'm going to treat the asteroids as if they were circles given that they're approx circles and our circle collision detection function is adequate I think on the whole I'm actually quite pleased with this implementation of asteroids and it opens up quite a number of possibilities for what we can do with the console engine now we've got the ability to render wireframe graphics and so there you have it asteroid in the command line now I'm under no illusion of this video has been more challenging than some of the others but through implementing such a simple game we've learned about spatial transforms we've learnt about vectors matrices trigonometry kinematics the science of motion and we've also dabbled with a few often C++ techniques using lambda functions and the remove if function anyway as always all the code is available in github from the links below if you've enjoyed this video please give me a big thumbs up and I think about subscribing and I'll see you next time
Info
Channel: javidx9
Views: 111,583
Rating: 4.9667444 out of 5
Keywords: code-it-yourself, code it yourself, onelonecoder, one lone coder, c++ game, asteroids, tutorial, command line, matrix, matrices, trigonometry, sine, cosine, maths, programming, learning, game engine, wireframe graphics, 2d rendering, transformation
Id: QgDR8LrRZhk
Channel Id: undefined
Length: 53min 11sec (3191 seconds)
Published: Sun Sep 03 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.