Tile Scrolling Platformer | 3. Tile Collisions

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello fellow scratchers and welcome back to part three of our series creating a tiled scrolling platformer in scratch and wow this is going to be a good one we are going to introduce a playable character to the game and delve into the world of tile collisions the bad news is that unlike sprite costume collisions we need to do a lot more scripting to pull it off but the great news is that not only will our scripts run faster and sprite sensing collisions but they will also work off screen and allow us to know what collided with what this is crucial for making really awesome games in scratch so stay with me and let's get scratching okay continuing from where we left off in episode two make sure we have the mario sprite selected he's not visible yet so click the show icon here to make him visible yay there he is i'll click and drag him into a free space this also ensures he's brought in front of all the other sprites in the game now gosh he's really small so set his size to 200 just here and then finally set his direction mode to left right this makes him simply flip directions when he's facing left or right that's great mario's in the game but if i run the project well he kind of looks like he's scrolling around the level but nah that's just wishful thinking he's simply sitting where we left him and doesn't know anything about scrolling levels yet to begin with let's get him controlled by the keyboard make with me a new block named reset player ticking to run without screen refresh we will put all the scripts in here that set the player's starting position and state we need to include two new variables to store our player's real position on the level make the first one named simply x now let's just hold it right there for a moment you've no idea how much i struggled with naming this variable i wanted to call it playerx but having a very specific name would not make it easy to copy scripts between sprites so we will go with a simple name x good then we'll need to make a y variable for this sprite only and set them both to 100 this will be the player's start position on the level next move the set camera x and y scripts to here replacing them with our new reset player block lastly it is a good idea to use a move camera block after setting up the player to ensure the camera is not out of bounds next create a new custom block named game loop now because a game loop is long running script we must leave the run without screen refresh unchecked you got that excellent now bring the forever loop down into the new define block and replace it with a call to this new block add a broadcast for the new event we'll name move player the order of the broadcasts is very important we want the player to move first and then we'll update the camera position before finally redrawing all the tiles this is to avoid sprites appearing to lag behind the scrolling of the level bring in a when i receive move player hat block make a new variable named speed x for this sprite only this will represent mario's current horizontal speed that is the velocity along the x-axis left and right now i want to show you a really neat trick bring in a set speed x block and set it to key right arrow pressed now run the project and see the value of speed x changing from false to true when we hold down the right arrow key okay no surprises there but look what happens when we place a minus block around the keypress block the value has changed from true false to one or zero because scratch knows we are working with numbers due to the subtract operator it has helpfully converted the true false value to a one zero value we can use this to our advantage c if we place a key left arrow pressed in the right hand side of the minus operator and test again we are able to get one for right zero for no direction and minus one for left and all this from one line of script awesome we can simply multiply this by six and we have a very quick way of changing the speed so make a new variable named speed y for this sprite only and we'll do the same for the up and down keys 6 multiplied by up key minus down key next we actually move the player introducing a change x by speed x followed by a change y by speed y bring the move camera block down from the game loop to here we want to position the camera right after we've updated the player's position on the level finally let's position the mario sprite on the screen just use a regular go to xy with our standard x minus camera x and y minus camera y great so it's testing time click the green flag and use the arrow keys to move mario we can still use the camera x and y scrollers to scroll the level but don't forget to click back on the stage after doing this otherwise the arrow keys stop working well that's funky but my hand is getting tired of operating the camera sliders let's get the camera to follow mario automatically locate the define move a camera script here at the top set camera x to x right away we can test this and see how the camera is following the player left and right nicely fenced in on the left and right by the edge of the level it would be easy to do the same for the camera y but instead let's do something a little better change camera y by y subtracted camera y all divided by four we can test this to see how the camera now tracks more smoothly up and down this is better for jumping games as it avoids any sharp up and down movements of the camera when the player is quickly jumping around try different values instead of four to track faster or slower but for us four is a very good value right we can finally hide those camera sliders from the screen yay so far so good the movement is excellent but unless we are some kind of ghoul we should really do something about walking through solid walls okay i hope you've got your wits about you because this requires some more tricky scripting to make it easier to follow we'll break the process down into four steps step one is to calculate the location of a point on the level grid step two determining the tile under that point step three handling point collisions and step four handling larger sprite collisions so here we go step one calculate the location of a point on the level grid rather than working with the mario sprite we'll open the costume editor and create a new costume and draw a small dot in the very center just here this will be easier to work with than the mario sprite for the next few tasks remember our explanation of how we use a simple number square to give a unique index to each tile in the level grid we are going to create a custom block that given a position x and y will give us back the tile at that location we'll make a new custom block get tile at x colon add a numeric input x a text label of y colon and another input of y click to run without screen refresh we'll use this block right after we update the player's y variable in the game loop pass into it the x and y of our player create a new variable named tile grid x for this sprite only now look again at this tile grid given the x and y position of the player we want to first calculate how many tiles across and up the screen the player is luckily this is easy to do we just divide the x and y position by the tile size 32 so back in the code set our tile grid x to the floor of the new input variable x divide it by 32. the floor operator is used to round numbers down to their nearest whole number we'll create another new variable tile grid y and do the same thing for the y input okay run the project and if we move the mario dot to the bottom left tile of the level we will see that tile grid x and y are both zero as i walk upwards our tile grid y variable increases by one for each tile walking to the right has a similar effect on tile grid x and we can use this to calculate the unique index of the tile in the grid list now we want the actual tile index so create a new variable naming it tile index for this sprite only now look at our number square example again the script for calculating the tile index from the grid x and y is quite straightforward the first tile starts at one then we add the grid y to get to here finally we add grid x multiplied by grid height to get us to the correct tile index so putting that into code add a set tile index to one plus grid tile y plus greater x times grid height let's run the project again and see if this works as expected we can check that the bottom left corner of the level is indeed tile index 1. moving up we'll add 1 to this number for each grid tile and moving right should add 20 assuming our grid height is still the original 20 tiles high that's working really well i'll just hide these variable reporters okay so step two determining the tile under that point since we already have the tile index getting the corresponding tile costume out of the targrid list is now super easy make a new variable named tile for this sprite only and set it to item tile index of tile grid and that's it i told you that was going to be easy let's run the project again this is really awesome if you remember our key tile costume 2 is the blank tile 9 the golden tile and 10 the wooden tile as we pass over the tiles in the level we see that we are now picking up the correct costume number from the grid list just as we intended perfect ok so step three handling point collisions we now have a way to detect what tile we are touching using our get tile at costume block it's not a great stretch then to now be able to look for collisions and try to prevent them we'll start by doing it the easy way bring in a new if tile is greater than 2 remember tile 2 is the blank one so this collision will be true for any non-blank tile if this is the case then we have collided and we change the player's y value back to where it came from that is negative speed y let's do the same for the change x remembering to also add a get tile at block like this okay run the project and let's have a wander around oh yes this is looking good we have been able to prevent the player dot walking through the walls this is fun however if we now swap the player's sprite back to mario and test again we shall find that we are not quite there yet our clever collision detection is only looking for a single collision point in the center of the player's sprite it doesn't know anything about handling collisions for a sprite with a width and height so step 4 handling larger sprite collisions the left and right hand collisions are not such a problem but the head and feet need to be addressed we'll do this by defining the player's height and then testing for collisions not just at the central point but at his head and feet too make a new variable named height for this sprite only within the reset player script set height to 24. this is actually half the full height of the sprite in case you're wondering it's just easier to work with half sizes to avoid repetition of scripts create a new custom block named fix collision in direction dx colon adding a numeric input dx then a text label d y colon and another numeric input d y ensure this is running without screen refresh we'll use it in place of both of the get tile at blocks here moving one of the if conditions into the define block we just created we only pass into the fixed collision block the amount we just changed speed x or y by and this is free just have both the change x and change y scripts in here together this is a good point just to retest the scripts to ensure that they are still working as before good we now have one script handling both the horizontal and vertical collisions now you're not going to believe me but let's make yet one more custom block named fix collision at point x colon an input of x a label of y colon and an input of y and we'll swap this out for the get tile x y that we just moved we'll pass in the sprites x and y variables so that it knows where to look for collisions and then within the define block plug the x and y input parameters to the get tile block so here we are checking just the central point of mario let's duplicate the fixed point collision twice more changing the top usage to check at mario's feet by subtracting height from y and the bottom to check his head by adding height to y to keep track of whether any of these points collided we make a new variable named solid for this sprite only and set it to the blank value before we use the fixed point blocks now at the end of the define fixed point collision script we add the if block that checks whether tile is greater than 2. if a collision has occurred then we set solid to the number 10. right now this value doesn't mean much except that any number larger than 0 is some kind of solid collision i've chosen 10 to mean very solid we can now update the if under the calls to fix point to confirm whether solid has been set to a value greater than zero this indicates that one or more of the above collision checks has indeed registered a collision we can run this to see the effect ah yes this is much better much better indeed collisions at his feet work extremely well as do the ones at his head good work if you've made it this far we are not going to worry about giving mario any defined width at present as to be honest he works pretty well without it we'll revisit this later our next move in developing this project will be to give our player a more platforming feel the scripts for movement will only get more complex so let's split up the code with custom blocks for handling player keyboard input make with me a new block named handle keys dash left right run without screen refresh this block is replacing the set speed x block in our move player script let's update this script to give the player a little acceleration make a new variable named key walk for all sprites and set it to the right arrow key take away the left arrow key then we will set speed x to speed x multiplied by 0.8 this simulates friction slowing the player down add to this key walk multiplied by two this will cause the player to accelerate in this direction give this a test oh nice the left and right movement feels much more natural and fluid next we'll add in some gravity and jumping make a new block named handle keys dash jump and run without screen refresh this will replace the set speed y block firstly let's handle the jump key wrap the set speed y in an if and use the key up arrow pressed as the trigger we'll set speed y to 14 for a nice quick upwards thrust now let's handle gravity so we'll change speed y by -2 accelerating our player downwards we'll place a cap on how fast he can fall using an if speed y is less than -22 then set speed y 2 minus 22 this way his downward speed will never exceed negative 22 pixels okay time for another test now this is feeling more real perhaps a little more flappy bird than mario but that's okay we will improve things no end going forwards what is important is that his collisions work well and do they well not as well as you may have hoped introducing variable speeds of movement has revealed an issue with how we fix a collision after it has occurred firstly after a collision we need to set the player's speed back to zero find and define fix collisions in direction script and see where we resolve a collision by changing the position back by negative at dx and dy insert an if else block after that and check for dx equaling zero if this is true then we have collided by moving up or down so set speed y to zero otherwise it was a sideways collision so set speed x to zero we can test this again it should now fix some of the oddness after a collision yep we do now see the player perfectly touching the floor after each jump but it almost looks like he's bouncing back on impact did you see that this is down to a second and more complex issue due to the way we move the player back out of a solid block after a collision see how we are just moving them back by the same amount they moved in this does ensure the player will be out of the collision but it often results in them ending up quite far from the wall still we instead need to find out the smallest amount to move the player back to get them free of the collision now if we were using sprite touching level sensing blocks we would do this by moving the player a pixel at a time away from the wall until they were no longer touching it we could do a similar thing looping the fixed collision point blocks but for a tile based game it's much more efficient and dare i say fun to use a little maths first make two new variables named fix dx for this sprite only and fix d y for this sprite only at the start of the define fix collisions in direction script set these new variables to the input variables dx and dy this is so that we can make use of them later now we'll remove the change x change y from the script for the time being now scroll to the define fixed point collision script we are going to need another two variables so make a mod x for this sprite only and a mod y also for this sprite only we'll set them to the side here using the x and y input variables set mod x to x modulus 32. and mod y to y modulus 32 look at this diagram notice how this point has collided with a tile block to push this point out of the tile we need to know how far the point is from the next grid line mod to the rescue the distance from previous grid line to the point y is calculated using y mod 32 therefore to move the collision point upwards out of this block we just need to move by the remainder of the tile's height that is 32 subtract y mod 32 we can code this directly after setting mod x and mod y add an if fixed d y is less than zero this checks that the player was moving downwards then here we go change y by 32 subtract our mod y variable just as we described we've only coded this for one direction but it's a great one to test oh yes falling onto the ground works like a dream i'm well pleased with how that looks colliding to the left is just a reflection of the down collision so add an if fixed dx is less than zero then change x by 32 subtract our mod x variable up and right are a little different look at this diagram this time we've collided from the right we are simply overlapping by the distance from the last grid line that is x mod 32 but because we are moving to the left you must negate this amount that would be zero minus x mod 32 however it just turns out that because we always round our numbers down when we're working with tiles moving by this much would not take us fully out of the collision to do so we must subtract a tiny little bit more minus 0.01 should do so drag in and if fixed dy is greater than zero and then change y by minus 0.01 subtract mod y this will move us down by mod y and a small amount extra lastly add an if fixed dx is greater than zero then change x by minus 0.01 subtract mod x and with that we are seriously done launch the project again with the green flag and confirm that all the collisions are working just the way we intended and yes they are amazing job the great thing about tile games is that although the initial complexity can be a little off-putting once you have the engine in place things get very exciting very quickly i'm really excited to complete the basic platforming scripts and add some player animation and then see where we go from there what would you like to see next perhaps off screen enemies the level designer or should we go deeper and add drop through and sloping platforms why not drop me a comment under the video with this scratch engine the world is seriously our oyster if you've enjoyed this tutorial then please smash the like button don't forget to subscribe to the channel to avoid missing any next exciting videos until then scratch on guys
Info
Channel: griffpatch
Views: 122,648
Rating: undefined out of 5
Keywords: Scratch, Scratch3, Griffpatch, Tutorial, Tile, Tilemap, Scrolling, Platformer, List, Code, Game
Id: ZJ7q3jLRSWs
Channel Id: undefined
Length: 24min 56sec (1496 seconds)
Published: Mon Mar 01 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.