 Welcome to my second Commodore 64 basic tutorial, for example, and who says you can't make a video game in basic? Well, most sane people, but it can be done if you don't mind it being quite simple. Everything's a trade-off with memory and time, so things take up a lot more space in the computer's memory using basic because the code's got to sit in there as well as any graphics or sound effects, whatever, and the code just takes up a lot more in terms of bytes, takes a lot more in terms of processing power to then interpret that into machine code to execute yada yada. There's plenty of arguments against it, which is why most of the games for the 8-bits were made in assembly, but anyhow, here is a very simple video game. It's about 75, 80, somewhere like that, between 75 and 80 lines of code if you don't count some of the lines that are just remark statements. I'm going to go through it rather quickly, and this one in particular is very specific to the Commodore 64 because as you'll see there's plenty of poke statements, and what poke does is it inserts whatever comes after the comma into the memory location, which is the first argument in the statement, so poke into memory location 5, 3, 2, 4, 8, the value that's in X. Anyway, let's go through it line by line, and I'll try and keep it brief and snappy. Any questions or comments, put them in, well any questions, yeah put me in the comments below, and I'll come back and answer them. Okay, so the very first line, we are setting things up. So poking 0 into 5, 3, 2, 8, 0, and to 5, 3, 2, 8, 1, we'll set the border and the background or paper, so the border and the paper color, you know, the color of the screen that you type on, on the Commodore 64, sets them to black, 0 is the color for black, 1 for white, and so on, I don't know, off the top of my head, have to look them up, but anyway that gives you a nice black screen for maximum contrast, I thought, and the type of game that we're going to be, that this is a very simple kind of shooter, if you like, Space Invaders kinda-esque, then yeah, the black was, that was my choice. Poking 1 into 646 sets the text color to white, and I don't know why they're so far away, you know, in terms of the number, but that's what it is. So we set the border and background to black, the text color to white, the maximum contrast for anything, any text that we then dispel the screen later on, and then straight away after that, we go to subroutine, starting at line 1000, so let's whiz down and have a look at that, okay, and you can see here, sorry, 1000, you can see here, this is the data, the data statements come from 1000, all the way down to 2000, it didn't need to be, could have been 1200 really, but whatever, in case there was more sprites, there's room now, I've left the room, so from line 1000, we're reading in the data for four sprites, so sprites 0, 1, 2, and 3, and in brackets afterwards, I've put what they are, so sprites 0 is the launcher, sprites 1 is the rocket, sprites 2 is the UFO, and sprite 3 is the boom, so rather than try and do it any other way, I just created a sprite that is an explosion sprite for when there's a collision, they are single color sprites, and the color was originally set to 1, so again for maximum contrast, black background and border are white sprites as well as text, however, I left that out in one iteration of the code, and whatever was in those memory locations for the color for each particular sprite just works, I think the rocket comes out red, the launcher is white, the UFO is kind of a blue color, yeah, you'll see anyway when we get to paint it, so we've gone to subroutine site on 1000, read in all the data for the sprites, come back up here, that's the end of that line, line 10, set up a couple of variables here, and in case you've forgotten from the previous video, or by watching it, the colon on a line separates commands, so you can put individual commands, more than one command on a single line, it'll still get read into, translate into its own memory address by the interpreter, but whatever, for readability, similar statements, I like to group on the same line, so we've got three poke statements and a go sub, and then we've got two variables being initialized, x with the value of 170 and y of 225, yx and y, well, because they will be coordinates, as you've probably seen from the remark afterwards, so rather than just have to refer to actual numbers, each time we put them in a variable, we can then manipulate that variable, can't we, so we can add or subtract from that variable, rather than having to do the maths ourselves, and remember, numbers, it just wouldn't work, and certainly not as well, and the next four lines, that data that we've input, or that's been read in, needs to actually be read in specific memory locations, so we use the read command in a for loop, and what we're doing is here, starting at memory location 12, location 12,800 for the first sprite, and each sprite is 64 bytes long, so from 0 to 63 is 64 bytes in total, and we're going to read that data, and we're going to poke into memory location n, first bit of data, and read, it takes data and puts it into variable A, and we can loop through it, so poking the first into a memory location 12,800, poke the first bit of data, then we'll increment 12,800 or one, poke the next bit of data, and so on, this happens rather quickly, given that it's basic, so reading these four sprites, you'll see when the game runs for the first time, there's a slight pause, and then we're into the action, but that really, once this is done with the data's in memory, we can reference it and manipulate it with the poke statements afterwards. Okay, so moving on, we're going to set up the locations, well, first of all, the sprite pointers, so we need to tell the computer where to point to for the sprite for each sprite, so sprite point is 0 and 1, 200, so we poke 200 into 2040, and then for sprite 1, 201 into 2041, and so on for 2 and 3, very similar. These poke statements poke the X position, so that's 170, X hasn't been operated on since we set it into 53248, so that's the exposition for sprite 0, we're using the same one, the same exposition for sprite 1, which is the rockets, remember when we look down line 1000, so it's because we want the rocket when we fire it to launch out of the launcher, so you start them in the same X position, so that's left and right on the screen. Excuse me. And then the next one, I set up two things here, so the exposition for sprite 2 and have it 0, so I'm going to start on the very left most section of the screen, which is actually behind the border, so it'll appear from the edge of the screen, so sprite 2 starting at 0. I'm also going to set up a variable called UFO with the contents of memory location, that's what peak does, it looks, it peaks at a memory location, so we've just literally stuffed 0 into that memory location, and then we're getting it back output into UFO, I could have just done UFO equals 0 and manipulate it, but it seemed to me like a good use of the peak command, you know, they would do use it later, just so I could demonstrate it here and talk through it. Okay, a few more positions, so we've got the Y positions to help sprite 0, 1 and 2, so I've used Y on its own, first sprite 0, I've used Y minus 20, now am I testing because sprite 1 is the rocket, so when you launch it, if the Y position is exactly the same as the exposition, it'll appear on top of the other sprite, which would cause us a problem because we're using collision detection, so that a collision would be registered, and also it just doesn't look right, you know, the rocket needs to launch out of the launcher, so am I testing by subtracting 20 from it, it set the rocket to just above the launcher, which looked right before it started being moved up the screen, as we'll see later, and then for sprite 2, which was 0, 1, 2, the UFO, I set the Y position at 50, so you don't want that being hidden by the border at the top of the screen, so 50 seemed, am I testing a good position to start it from down the screen. Okay, and then this memory address deals with which sprites are currently being displayed or not, okay, so it's an 8-bit byte, obviously, and by putting 5 in there, it sets sprites at 0, the launcher and 2, the UFO, to be displayed, so it turns them on, okay, so if you think about it, starting from the right, if we just had a 1 in here, that'd be bit 1 would be set to 1, and that would just be sprite 0 would be on, okay, and if we had a 3 in there, so bits 1 and bits 2, so 1 would have a 1 in it, 2 would have a 1 in it, add them together, the decimals together, the values, that'd be 3, so that'd be sprite 0 and 1, so we're not having that one on, so we've got the first bit on, second bit off, third bit which would be 4, so it goes 1, 2, 4, you know, 8, 16, 32, 64 as you know, so by having a bit number 3 on, which is for the very fourth bit number 1, on value 1, add them together, you get 5, so that's how that works, if I've rushed through that too quickly, it's not quite clear to you, let me know in the comments, because I might make a video specifically on that, although there are plenty on YouTube if you just look around, and you may recall this from the previous statement here on line 136, the print chr $147, that prints a character to the screen, whatever character is referenced by this number 147, and as you can see from the remark, so as I demonstrated in the previous video, it just clears the screen of all text, it doesn't affect sprites, so any sprites that are being displayed will be displayed still, even though you, even though we're clearing the text of the screen or clearing the clear screen character, okay, it just means that the, when you see it running, what I'm actually doing is literally copying and pasting this code into the emulator, into the vise emulator, and you'll see it pasting in line by line, and then if we just run the code without that, then the sprites will be displayed over the top of the code, we just put in it to be a right mess, we clear the screen, okay, and here is the kind of main loop of the game, I guess, so we set up a variable k with the value of 203, memory location 203, well, it was special about 203 or 203, well, you know, the remark gives it away, let's see, let's check to see if a key has been pressed. Now I believe there are two locations you can check, 197 being the other one and 203, I don't know if there's any difference, I didn't, I can't recall if I tested 197, but anyway, when no key is being depressed on the Commodore 64, that memory location will have 64 in it, I believe it's 64 again from memory, yes, it's not zero as you might expect, it'll be the, you know, the value 64. So we're getting the value sticking into k, and then we're doing, there's three statements here to check the value of k, and we're checking for it to see if it specifically is one of these three, so 10 would be the value of a was being pressed, 18 if d was being pressed, and 60 if space was being pressed, and if either of them are true, then we go to sub routine starting at like 200, 300 and 500 respectively. Okay, so let's have a look and see what happens if, well, first of all I should say, if nothing happens, if no, so if no key has been pressed, then we will fall through here, none of these if statements will be true, so they'll all get skipped over, and then there's another if statement, so if the value in UFO, you might remember we set it to value of that memory location, which had just been set to zero, so this won't be true either at the moment, but the value of UFO is 255, then it resets to zero. Okay, why is that then? We'll get to that in a moment, and then we're going to poke memory location 53253, which is the Y position for the UFO, for sprite two, I should say, we're going to poke that with the value that's already in that memory location, plus 20, okay, so it probably is a way to do this, it's easier on the eye, but it's just another demonstration where you can use peak and poke together, so we get the value that's in that memory location, adding 20 to it, and put it back in there, so that's the Y coordinates, so that's the up and down axis on the screen, so you might have worked out what this whole whole thing is about, so if that doesn't get executed, because UFO isn't, the value of UFO isn't already 255, then we're going to add, we're going to move the UFO down by 20 pixels, okay, so what's happening is UFO has got the X coordinate in it, when that reaches 255, it gets reset to zero, and then we drop 20 pixels down on the screen, so if that wasn't clear from my rambling a moment ago, so that's, if UFO is less than 255, none of the rest of it get executed, I know this is a separate command, but that's it for this line, this just doesn't happen, okay, so let's, as would be on the first run for a UFO would be equal to zero, so none of that's going to get executed, what happens here, well UFO is going to get incremented by five, so if that, whether this happens or not, UFO is going to get incremented by five, so either the value is already zero, or some value less than 255, and five's going to get added to it, it's going to go up increments of five, one at one, well because this is where basic, the limitations of having a video gaming basic come into it, if it was only incremented by one each time, that the UFO would be moving across the screen at a snail's pace, so by, during my tested, having it increment by five meant that the UFO just moved across the screen at a more reasonable pace, look better, more playable, it does make it slightly jerky I guess, but you probably won't notice it when the game's running, when you see that in a moment, okay, so we can increment UFO by five, poke the value of UFO, the newly incremented value back into the X position, so that's the effect of moving it across by five pixels, okay, then we also check this memory location, what is this? This is a collision detection, I want to say register, but it's not really, it's the memory location, if there's a value greater than zero, then a collision has occurred, but the only way this would be greater than zero is if the UFO has made it all the way down the screen and crashed into our launcher, in which case you would lose, hence why there's a print statement here with the string you lose after it, you may have noticed something new you might not have seen before, after print we've got tab 30, so what that does is it moves, moves the cursor across the screen 30 spaces for printing the message, so I have the effect of printing it in the kind of right-hand side of the page, and then it would go to subroutine side of 600, which I won't do right now, but that's just the, that's the kind of end-game subroutine, we'll get to that when we get to that, now something I haven't explained here yet is what was special about the value 255 is that the right-hand edge of the screen is not, no it isn't, so the screen is actually 320 pixels wide, but 320 does not fit in an 8-bit byte, the maximum is 255, okay, all the bits are set to one, so the Commodore does have a way if you've been able to use the full width of the screen, you just have to set a value in another memory location, two or one, and then you'd reset, you still reset back to zero, but then you'd have the remaining digits from 320, so 320 less than 255 is 65, I believe, no, yes, so you've got 55, no, 55, 65, 75, oh, crikey, and so I did a lot of this from memory, unscripted, and I hope I haven't lost your interest just yet, so I'm not doing that here, it was just a bit too much faff for the sake of this basic game, so what's going to happen is the UFO will hit an invisible wall on the right hand, yeah, partway along the two thirds of the way, say along the screen to the right, and it'll just snap back to the start, okay, and that's why this area of the screen from, you know, 30 spaces over, it's kind of right-hand third will always be empty and it's in a good place to display messages, okay, and once the execution gets to line 190, we're going to go back to 140, so this is our main loop, so unless we've branched away from this loop with a go sub, this loop will just keep repeating, which has the effect of the UFO moving from position zero to position 255 in increments of five across the screen, and it hits that, then resets back to zero, so back to the left-hand edge of the screen and drops it by 20, basically a pixels, sorry, a sprite's height, 20 pixels down, okay, so line 200, well 200 would be hit, you know, would be read and executed if the key A has been pressed during this loop when we're checking for it, and if so, that has the effect, A would move the launcher, you know, the player controlled sprite to the left, so Y if X is above 30, only then would we decrement X by five, well 30 is about how wide the border is, 30 kind of pixels, and yeah, it's the width of the border, basically, so I didn't want the launcher to disappear behind the border, even though it's black and you can't see it, it's still there, and as long as we're not above 30, we can keep decrementing by five, if it is, then we don't, you know, if this turns out to be false, you know, so if X is equal to 30, then this won't happen, okay, and then we're going to put the new value of X into the memory location five through two for X, which is X coordinate for sprite zero, and then we return, so it's as simple as that, so in that particular subroutine, only three lines in total, it's just to deal with moving the player controlled sprite at the launcher left until it reaches the border, okay, if D was pressed or have the opposite effect, it would increment X by five, as long as X was less than 255, okay, because again, we don't want it, well, it wouldn't hit the border, but we don't want it going, we don't want to try and store a value higher than 255 into an 8-bit byte and cause in an error, okay, so it will stop when it reaches 255, and then we go back. Subroutine 500 is called if the space bar is pressed, and this one's a little lengthier, a little different, so what we do immediately is we turn on, so remember this memory location deals with which sprites are being displayed at any time, a seven will have the effect of turning on sprites zero, one, and two, typo there on the mark, zero, one, and two, so now the launcher, the UFO, and the rocket are being displayed, and we also set the rocket's exposition, although yeah, we set the rocket's exposition because obviously the launcher may have moved, so we just make sure that that's up to date as well so that the rocket appears in line with the launcher, okay, and then we have a loop here, so we're setting M with the value of memory location fire through 251, which is the Y coordinate, and we're going to decrement that to zero, so by doing that, it would move up the screen, the rocket would move up the screen, do that in steps of nine, that's minus nine because the value's getting, you know, starting high and going towards zero, and that again, reason for nine is just so the rocket moved at, you know, kind of reasonable speed that you might expect a projectile to move at, and then we're going to poke the value of M into the Y coordinate for sprite two, yeah, whatever one the rocket is, I forget now, okay, so during the loop, because the end of the loop is where the next M is, so down here, so we've done that, put memory location in, sorry, put the Y value in to the memory location and turn the sprite on, now VC is a variable to check the contents of memory location fire through 278, which is the collision detection, so it'll always be zero unless there's a collision between two sprites, and in my testing, when the rocket clouded the UFO, the value went to six in this memory location, so we're going to set VC with the content of that memory location, if it's a six, then we're going to print over the right hand side of the screen, you win, you win is a slightly shorter string than you lose, hence why we've tapped over just a couple more spaces, so it's still in that area of the screen that's not being used by anything else, so we print you win, and then we'd go sub, go to subroutine silo 600, which we'll be getting to shortly, which is just wraps up, that's the end of the game, so it's very simple, either the UFO is going to hit you after it makes its way down the screen, or you're going to shoot a rocket into it, and that's when the game will end, win or lose, okay so assuming that VC doesn't have six in it, we are then going to, we're then going to poke zero into 53278, the collision detection memory location, reading this out loud now, I don't know if we actually need to do that, but whatever, it's in there, it's in there now, it should already be zero if there isn't a collision, but I think this, no I don't know, we're not going to ramble on about that now, pontificate on why I've done that, we'll see if it works shortly when it's all run, okay then there's another riff statement, if the UFO value is 255, then we set it to zero, and do the same thing as we did on line 180, what are we doing there here? Well if we didn't, then what happens is when you shoot the rocket, the UFO would freeze, and just stay in one position on the screen, so we need to continue, we need to copy those, which I have done, copy those commands from the main loop into this loop as well, so although we've branched out of the main loop, we still need certain things to have executed, to still execute, okay, and then we're back to the next go round in this for loop, this for m loop, and the loop will end when whatever value was in 5 through 251 reaches zero, when that happens, the rocket will have left the screen, so we then go back to just displaying sprites, zero and two, zero to four, zero to three, zero, one, two, three, future the four sprites, okay, so we turn the rocket off, and then we're going to set the y value, the y variable, back to whatever is in memory location 5 through 249, so we reset the rocket starting position basically, so we set y to that, which would be the same as the launcher y position, and then we minus 20 off of it, so that the rocket when we turn it on, appears just above the launcher, and then we're going to set the x coordinate as well, so it's the same as the launcher, and then return, so back up to the main loop, okay, so if we fired and we've missed, we'll end up back in the main loop here, if we fired and we hit, if the UFO has hit us, then we will branch out to subroutine starting at 600, so what this does here is it switches off the collision detection, so poke zero back into that, not registered by that memory location, and the reason we do that is if you want to play the game again, and that won't automatically get reset to zero, if we don't exit the game and we start again, the game will instantly be over because it'll detect a collision, because this register is set to one, what, we're greater than zero, okay, so we do that, turn off the collision detection, and then we also in that variable that we set up earlier to hold that value, we set that to zero as well just to be sure, and then we poke the x and y locations for sprite three, which is the boom into the same location that the rocket was, the rocket or the UFO, whatever these represent, I can't remember, that's the problem with dealing with just raw digits, you soon forget, I could look them up, they'll be in the code up here, when we set them all up, but it doesn't matter, so where are we? So here, yeah, so we're setting the sprite for the boom, and that will be, there's another for loop here which flashes that sprite, so I don't know why I've used O, but anyway for O equals zero to 200, so it's going to flash 200 times, and that happens rather quickly, we can turn all sprites off, and then eight will turn, will have the effect of turning just the boom on, I believe, we'll see in a moment, it'll either be the boom, or the launcher, and the full sprites are going off, it won't be flashing the launcher as well, so this will just have the effect of having the boom flash on the screen, so the message you win will get displayed, and boom, or you lose, and the boom will flash, okay, and then we just turn all sprites off, set the collision detection to nothing, far through 279 I haven't used before, and it probably doesn't need to be here, but there are two memory locations that deal with sprite collision, far through 278, far through 279, so just for completeness, I set them both to zero, and then there's another little loop here, for buff equals 631 to 640, poke zero into buff, so that's telling us that buff must be memory location, so 631 to 640, what's that? Well, you've probably already read from the remark, it clears the keyboard buffer, now if we've been pressing A and D to move our launcher left and right at space by multiple times to fire multiple rockets, those key presses will be stored in the keyboard buffer, there's a memory buffer, so if you're typing rather quickly, so that keystrokes aren't missed, they get stored in the buffer before they're output to the screen, or whatever the program running does with them, so by poking zero into them, we're clearing the keyboard buffer, so that when we ask the question in the next line, press Y to play again, or any other key to quit, we're not automatically going to press any other key, you know, an A or a D or a space is going to get passed through and we exit, right, so we clear the buffer out, display it at the message, press Y to play again, any other key to quit, and then it's just a basic A string with nothing in it, request input, if there is none, then we repeat, so we get stuck in this line 633 loop, if Y is pressed, it goes to 100, we start all over again from up here, setting the sprite pointers, we don't need to read anything into memory again, that'll all still be there, so that's why we go back up to 100 to set the X and Y values, if N can go to 636, which probably doesn't need to be there, it's probably did say, press Y to play again, N to quit, but being a basic input kind of statement, we're waiting, yeah, we're reading the key press, we're asking the user for a key press, and staying in that loop, you know, just because we're looking for our Y or an N, there's not the user pressing something else, so I don't think 635 needs to be there, because if something else is pressed, we're automatically going to go through to 636 anyway, which will clear the screen again, turn all sprites off and X is out to the ready prompting basic, so if you're still with me after all this time, we're going to zip over now to the device emulator, paste all this code in, and see if it'll run, so the device emulator here is set to run at the same speed as the actual C64, which is why it's quite slow, it's like if you list a big program in on the Commodore 64, if you list a big program, it will display at this kind of speed, anyway the first thing we're going to see is those poke statements set in the border and the background to black, and there's a pause while the sprite data is read in, and then the screen is cleared, so here we go, here's the game, and you can see the rocket launch at the bottom, moving left and right with the A and D keys, space to fire the rockets, just missed the UFO there, and there we go, we've scored a hit, and all the sprites have turned off except that boom's right, which flashes over and over, boom, and then the message you win on the right hand side of the screen, you can see here that the UFO just kind of disappears at that, when it reaches that, the right most third of the screen if you like, and we're going to show, this run through is going to show what happens if we miss and the UFO wins, if you like, and crashes into the rocket launcher, if you don't get it on this run through, you're cooked, I've tried to run the UFO there, but run out of room, boom, you lose, now you can just see there's a bit of artifacting here, well artifacting, look at that message on the screen, there's a few question marks in it and whatnot, and that's just, it's not that there's any error as such with the code, it's just something I've noticed that when you copy code over, and when you literally copy and paste it into the emulator, sometimes certain characters don't copy over quite as you'd hope they would, and certain things get input, but that only seems to happen, I've already noticed it mainly with print, we're using a question mark instead of a print statement, and speech marks I can cause a bit of an issue, but anyway, nothing to worry about, it works as expected, I hope you've enjoyed, and if you've stuck around this long, it's a medal committing, anyway, like and subscribe, if you don't mind, and leave a comment or question below.