Game Physics (in Assembler) - Computerphile

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so Matt we have had to chat with you before about assembler and the game that you're writing so what we can look at today we're going to write some basic game logic and assembly language first I'm going to show the basics of the CPU from a programmers point of view so let's invent a CPU it's going to have a logic core and because we're programmers we don't concern ourselves too much with that what we do care about the registers and registers are very tiny typically four to eight bytes of storage inside the CPU itself for the logic court to operate on so it's imagine we've got a register one a registered to and we've got the pc the pc is the program counter and that stores the currently executing line of code so if you imagine back to your basic days we would have something like 10 print hello 20 go to 10 so the 1020 are the currently executing lines of code and basic obviously base it would have a software solution for this but the principle applies the pc would hold the 10 so the logic core would fetch that line of code to execute it would then advance the program counter to 20 and then execute that line of code but this go to routine would inject 10 back into the program counter so the next line of code would then be 10 again so this logic call let's imagine it's attached to some pseudo rom some ram maybe a graphics processor or something along physical wires and this is what we call the bus so the logical can fetch memory about using an hour bus when it initializes it's going to immediately start executing code the program characters could be initialized to 0 at which point SAT rom in our pseudo memory map it's going to immediately start executing code from the top of ROM so let's write some assembly we can interact with the other two registers then so the first thing we want to do is put some basic values in these two so let's do a move command so we've got address 0 which is the top of run and this instruction is going to move the literal value 8 into register r1 so that's what that command would look like next line of code let's imagine these lines of code are two bytes wide address number two we're going to move the literal value for into register r2 and then as a third line address for we're going to add the two together so we'll perform an ab command we're going to add eight and four together which we're in r1 and r2 so we add r1 and r2 together and the result would be stored in our two so what's going to happen when the cpu starts up its going to initialize the pc 20 which is address 0 in the run where our code is address 0 is going to move the literal value 8 into register r1 it's then going to advance the program counter 22 which is going to move the literal value for into register r2 then it's going to advance the program counter 24 and that's going to add register one to register to it's going to store the value into register two so we would expect 12 and register at this point just like basic using the go to Thurmond go and you can jump the pc around so let's perform that out operation again so on a dress 6 i'm going to jump back up to address for and that's going to perform the add again so once this instruction is completed is going to jump to 6 and that is going to inject address for into the pc so that the next executing line of code is going to be back to four again so we're going to again add r1 to r2 which would give us 20 so that would add what was still in r12 what was now in our to after the last ad yes yes changes are explicit you tell the CPU exactly what to do is not going to change these register values outside of the code you've written here this looks really good for you know the basics of doing some sums and things now how's this blow when you get into a game and I can see this being a good good way for adding up the scores but yep certainly we are going to look at some very basic platforming code so we're going to have a pseudo player that's awful start a blank page let me first translate this to 68,000 assembler actually that's what I was going to do okay so the 68,000 CPU which is in the sega megadrive is slightly different to the cpu we invented here it's got 18 registers which run from d0 to d7 for the general purpose registers those is used for a lot of logic and arithmetic we've also got a0 to a7 which are address registers which we use for accessing parts of memory rom ram other peripherals on the bus 68,000 logical we've got d0 to d7 registers we've got the a 0 to a 7 registers we've got the pc just like our fake cpu and the status register here the status register stores the state of the CPU after the last operation it'll have flags inside it called the Zed flag and the carry flag the Zed flag is used to determine if the result of the last operation was 0 so if we had four in our 14 and r2 and subtracted the to the result would be 0 it would then set the carry flag we can use that to compare two numbers to see if they're equivalent it's also got the carry register which tells us if the result of the last operation was a positive number going negative so if we had seven in our one we had a 12 in r2 and we subtracted are two from our 112 is greater than 7 the result is going to go negative is going to set that carry flag and we can use that for comparison so we can compare two numbers and we can perform logic jump around to different parts of code depending on the state of the flags and the status register okay so we're going to translate our pseudo example here into real 68,000 assembly so the first command the move aight into register r1 will be a move and we need to add the size of the operation here and that can be a biter word or a long for simplicity's sake i'm going to use along a byte is eight bits a word is 16 bits and a long word is 32 bits so we're going to move a long word worth of data 32 bits it's going to be a literal value eight and we're going to use these d registers which are the general purpose or rhythmic registers so let's use d0 next slime we're going to move another long word literal for into registered d1 and add together we're going to add two long words worth of data register d 0 to D 1 i've used long list for simplicity a bite would only write the eight into the lower bite and this would be whatever was last in the upper bikes of that register if we were to write it as a word we would get 08 into the lower half of the reg and whatever was last used in the register would be in the upper half but I always really work with long words so this register would contain 0008 and the same goes for the add operation we're going to add 32 bits of data so the entire register is going to be added with the entirety of another register I'm going to type this back up into the pburg ER and I'm going to show this running in the debugger so we can evaluate evaluate each step as it's running and then we get to add to it with some basic platform player logic let's go some basic assembly language then I've got environment setup for 68 k assembler for the sega megadrive which includes a basic skeleton here the first thing we do is we define the start and the end of the ROM file for including in the head or later we're going to include the header file here and previously explained that the pseudo CPU that we made was going to start executing code from address 0 for 68 k it's very slightly different the CPUs not going to look for code when it starts up it's going to look for this table in the first 512 bytes of memory so the first thing it's going to look for is the address to initialize the stack value to and this is the one we're interested in here is the CPU entry point so it's going to start executing code from the address that it finds in this entry of the table rather than immediately stream address 0 so we can define a label here a CPU entry point and then back in our code file here we can start executing code from here because this is a debugger it's very slightly different to a standard program we have to initialize the connection to the debugger using this subroutine but don't worry too much about it so we can then start typing our code out so our example before was to move a long word literal eight into register d0 we were then going to move a long word little forward to reg D 1 and then we're going out of the two together so add long word worth of data d 0 to D 1 and that should assemble and we can fire that up them ok so let's switch the devkit on load up the debugger and then we'll load our executable we have done a video on the dev kit for anyone who's interested oh just give people a kind of one sentence on what this dev kit is its a sega mega-cd development kit which has a snazzy board inside 468 keightley bugging on top of that it's got the Mega Drive daughter board on top of that it's got the mega-cd daughter board this is connected to the back of the pc by a scuzzy cable to a nicer card which can interact with the debugger here we've got an old ms-dos based debugger ready to debug code so it slowly executable the first thing we want to do is reset the CPU and then we can bring up a source window here ok so we can set a breakpoint on the first line as f9 to go so that executables now running on the debug get here and it's showing us in real time the results of that operation so we're on this breakpoint here so the first instruction was going to move the little eight and to register d0 so if we step we can see the result of that operation here the next line was going to move a little for into register d1 we can see the results of that here and then we're going to add the two together the d 0 plus d 1 and the result is going to be in d1 so that gives us 12 in hexadecimal here so that's all working if you didn't use this literal word you might be just overwriting some part of that memory yeah you can write a long word a word or a byte of data which will use the first bite two mics or four bikes for the register the same goes for add divide multiply subtract etc you have to specify how much the registers you're going to deal with that includes wrapping so if you're doing a bike tad 255 would wrap around 20 if you're doing a word size at 65 k we're at 64 k would wrap around 20 again and it's not useful those things are useful in certain circumstances on yes tis yes because a smaller the operation the faster it executes on the CPU so you can do a lot of optimizations by doing by size operations instead of words or long words ok so we're going to write some basic platforming code imagine we've got a player at a floor and he has a positive x velocity and a positive y velocity so he is running and jumping and we're going to handle the logic back to move the player the first thing we want to do is to designate some registers for the player x and y position so if we initialize the players exposition a zero and to register d0 so play it x plus we can initialize the players y position zero and use d1 for that and then we can initialize the velocity values so in d2 let's store the X velocity something like 16 in 2d too so player X velocity and we're going to initialize the player y velocity to something positive because he's jumping so 8 in 2d three player y velocity okay so now we need a game loop so let's write a label for the top of the game loop let's call it player update and then we can start moving the player using the velocity so we would need to add players X velocity to the players backs cause so we're going to add do 220 we're going to add the players y velocity the players y position so we're going to add d3 to do one so then we're going to loop back up to the player update start so if we do a jump back to player okay that's going to continue looping forever so let's save and assemble that and see it in action so this is a discreet bit of code for handling where that player is would that be right yes this is a very tiny game loop which would handle the velocity applying to reply x and y position obviously stuff would wrap around this for drawing the character and all yeah there will be extras here for the graphics once you calculate the players x and y position you would send it to the sprocket X on Y position that's a subject for another day though okay so let's break on this line will run again and then we can break here so let's initialize d0 to the play x position 0 will initialize the player why pulse 20 we're then going to initialize the place X velocity to 16 I'm going to initialize the y velocity 28 and then going to enter this infinite loop here so we're going to add the players X velocity 2z0 going to add the players y velocity to d1 and I'm going to jump back up and I'm going to continue doing this forever and the loop would just basically make him move it will make a move for so he'll continue to move right he'll continue to jump up so he's jetpacking news jetpacking so let's add to it let's define gravity we would use the equate label and we'll have gravity as something like 8 let's define the floor height as something like seven I haven't use an odd number yet so in the player update before we apply the y velocity we want to apply the gravity to it so we can subtract long word it's a little so we need the hash again gravity from the player y velocity here before we apply it once the position has advanced we want to check if we've hit the floor so to do comparisons you want to watch the status register to look at the last state of the CPU for the last operation so if we do the subtraction one number from the other the status register will have a flag in it to tell us whether that number had become zero or had become a negative number so you want to compare the floor height with the players current white position if the result of that comparison was a negative number the player is below the floor so to do a comparison we would compare the literal floor height with the players wide position do you want and then we would jump to a separate part of the code if that condition was met so we do branch if greater than there's also branch of less than this beqa branch of equal there's also equivalent for unsigned numbers as well so that's basically saying if this certain thing is true then go to a different bit of code yes exactly so we start by comparing the floor height with a d1 which in the background would perform a subtraction operation but without writing results when he registers it would only set the flags in the status register state say if the result of that operation would have been 0 or would have gone negative and then we can check those flags with the BGT branch if greater than so that's just going to check if the value for the carry flag is one or zero so branch is greater than and then we jump to another label so we'll call this floor and then we'll define that label here above floor so we compare the full height with d 1 if that was greater than then we are above the floor and we're going to skip this line of code we're about to write and head straight to above floor so if that condition was met we are below the floor and in that case we want to snap back the players white position to the floor height so we move the floor height to the players y position which is d1 we also want to null out the velocity because once we hit the floor we don't want to carry on going down so we reset that register to their player what y velocity will be 0 in that case so let's assemble and run that and we can step through at one at a time so back in the debugger I've changed the initial x and y Paul so he's already above the floor for this demonstration so let's run this then initialize the exposition 28 we're going to initialize the y position 28 we've initialized the X velocity to 16 and the y velocity 28 so this time the first thing we're going to do is subtract gravity from the player y velocity so that sin that's down to four before we apply the x and y velocity so add d 2 to the 0 at d 3 to do one and then we're going to check if we are still above the floor so we're going to compare the floor height to the new white position and we're going to branch if it's above the floor which is still is so we skip straight to this line and then we jump back up the player update once again we subtract gravity from d3 which sends it 0 which means we've hit the apex of the jump we're going to add the x la citty at the y velocity compare a four-syllable the floor which we still are once again we subtract gravity to d3 and this now goes negative which means we're past the apex of the jump we're going to start applying downward velocity instead of upward velocity so once again apply the X velocity to the exposition the y velocity to the light position i'm going to start moving downwards instead and we're going to keep going until we are below the floor here so the floor height was set to seven the white position is now zero so this comparison is going to ring true branch is greater than above the floor which will fail there we go so we are now below the floor we need to snap back up to the floor height so we set the full height into the Y position you want and then we know the player y velocity qui don't want to carry on going down so the y velocity is now zero and then back at the player update and then forever we will always snap back up to that floor height and we are always on the floor so now he's still moving to the side but he's just staying on the floor here's just stay on the floor yes because gravity's are basically clamping him to the floor right yeah indeed from here on it's not tricky to add things like acceleration deceleration in air drag things like that and once you start getting into control pad input and stuff like that that you can then apply the acceleration to the current velocity and then have basic pad inputs we've seen on your game in the previous video that you've got bouncing balls in it and is that just an extension of this there's a very basic physics engine in there which is just an extension of all of this very basic collision detection is just comparison of numbers applying clamps or bounce or restitution etc you can build it all up like Lego blocks like this just learn one thing at the time and if somebody out there wants to learn this kind of stuff and they obviously haven't got the dev kit and all this old kit lying around where would you suggest they start to sort of learn these these basic bits and pieces you can do exactly the same thing using an emulator and there are some freeware assemblers out there you just need a text editor assembler and an emulation off you go some are better than others find one with a debugger built-in obviously otherwise you'll get a bit lost but all the principles are essentially the same is this whereas what's cuz he is yeah it pronounced scuzzy I didn't realize that it was such a widespread terminology I thought I'd get laughed at saying scuzzy so I said se SI but whatever thank you internet
Info
Channel: Computerphile
Views: 627,868
Rating: undefined out of 5
Keywords: computers, computerphile, computer, science, computer science, NVA, National Videogame Arcade, Tanglewood, Sega, 68000, MegaDrive, Genesis, Development Kit, Code, Coding, Assembler, Assembly Language
Id: Kalmryn9_sE
Channel Id: undefined
Length: 19min 24sec (1164 seconds)
Published: Thu Dec 15 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.