Nathan’s Game Dev Blog Part 3 – The Code
Herein lies the chronicle of my attempts to learn how to make a game from scratch. I have three goals: First, to provide a place to record my thought process, experience, milestones, and pitfalls on my way to making my first “shippable” game. Second, to share knowledge and experience for others to learn. Third, to provide motivation. Please comment and share if you like what I have written ~Nathan
Rubber, Meet Code
Here is my code.
The room rm_main doesn’t have any code beyond the properties in the GUI.
There are three sprites: spr_pipe, spr_mario, spr_floor. (No code)
Par_wall is the first object, and it only has to exist. There is no code; obj_pipe and obj_floor will share par_wall as their parent. That’s it.
Obj_floor similarly has no code associated with it; it is simply checked as solid. The is a generic sprite associated with it, but it is hidden behind the background object, which has a lower depth.
obj_pipe has a creation event (not pictured), which says “move -2 pixels every frame.” This means that when the instance is created, it will begin moving from Right to left. The pictured DnD (Drag ‘n Drop) step event checks the X variable of the object, and says “If the X variable (the location of the pipe) is off screen on the left, destroy it”
Here’s the DnD code for obj_pipe_generator. The create instance that isn’t pictured only sets Alarm[0] to 120, which in a 60fps game, is about 2 seconds. Since create instance occurs only when the room is created, this gives a short 2 second pause before the first pipe is created.
The pictured code is another DnD snippet. You can see that in the main window that it first creates an instance of the obj_pipe object, then resets Alarm[0] to 140, which is 140 frames, which is a little over 2 seconds. So, a little over every 2 seconds a new pipe is created.
To the right is the dialog box for the Create Instance code that occurs when the alarm triggers. In this code, you can see that the X value is the constant (680, just off the right side of the screen). The Y value has the function “floor(random(600))+100”. This is two functions, so I’ll break them down:
- random() – this provides a random number (including decimals) between 0 and whatever the argument is
- floor() – This rounds a number down to the nearest whole number
So you can see that the function will return a whole number between 0 and 600, then adds 100 to it. what this does is place the center of the pipe object (where the gap is) somewhere between the top and the bottom of the screen without going off the edge, or under the floor.
Last up is obj_player. This is by far the most complex object in the game, so I’ll cover each of the components separately. Here’s the whole object:
Ok, you can see the checkboxes and other various properties. Obj_mario is visible, solid, and uses spr_mario. Let’s go through each of the events:
Create Event
The Create event does two things. First, it uses the Execute Code event to declare some variables:
grv = 0; <– the Gravity variable
vsp = 0; <– vsp is the Vertical Speed variable
image_speed = .1; <– this is a special variable covering animation
preGame = 1; <– sets the pre-game to true
Ok, so since none of this stuff has appeared before, it’s not going to have any effect on the game until we get to the step event. But before we get there, the Create event does the second thing, which is to set Alarm[0] for 60. This just means that nothing else is going to happen with obj_mario for 1 second.
One other thing to note is that Game Maker has pre-defined variables for things like movement. But I am building the gravity mechanic from scratch, so at the moment these do nothing.
Alarm[0] Event
Once 60 steps have gone by, Alarm[0] will execute. There is one tiny snippet of code, that only sets two variables:
grv = .4;
preGame = 0;
This doesn’t do anything yet that you can see, but when we get to the Step Event, you will see how these numbers come into play. Basically, setting the grv variable t .4, we will begin to pull Mario down a little faster every frame. PreGame being set to 0 will allow the player control over Mario’s jumping/flapping.
Press ‘R’ Key
I’m saving the Step Event for last, since it is the largest piece of code. The “Press ‘R’ Key” event is a simple DnD command. If I press the ‘r’ key, the game will reset.
Step Event
Here is Mario’s Step Event code. Remember, this code gets executed every frame (or ‘step’), from the moment the object is created, which is the second the game is started.
keyJump = keyboard_check_pressed(vk_space); if(keyJump) { if(preGame == 1) { vsp = 0; } else { vsp =-7; } } //any collision if place_meeting(x,y,par_wall) { vsp=0; background_hspeed[0] = 0; background_hspeed[1] = 0; all.speed = 0; grv = 0; obj_mario.image_speed = 0; } vsp += grv; y += vsp;
I’m going to go over this assuming you know how if/then statements work.
KeyJump = keyboard_check_pressed(vk_space);
This inserts the function keyboard_check_pressed() into a variable that can be checked. Keyboard_check_pressed() checks to see if a key has been pressed during that frame. This is slightly different from keyboard_check_direct(), which checks to see if the button is being held down; this would trigger the if events every frame that the button his held down, not just when it is pressed.
vk_space is a special variable; it always refers to the spacebar.
Ok so the first IF statement checks to see if the spacebar has been pressed. Here’s where the preGame variable comes into play. Before the alarm goes off, so for the first 120 frames, preGame is set to 1. if preGame is set to 1, then vsp is set to 0. The vsp variable will be used at the end of this code to set Mario’s movement. Once alarm[0] goes off, the code in Alarm[0] sets preGame to 0, so the IF statement set vsp to -7.
Next up, collision. place_meeting(x,y,par_wall) checks obj_mario’s position, and if any part of mario is touching any other par_wall object instance, then the following code will execute. vsp will be set to 0, grv will be set to 0, and the background movements will be set to 0. After I added this code, I found the special variable all.speed, which covers anything using the special speed variables (like the backgrounds), but won’t affect my vsp and grv variables, so I have to set them to 0 separately. Obj_mario.image_speed is another special variable, which defines the animation speed for mario. Setting it to 0 basically turns off Mario’s animation. To the player, this looks like when mario touches a pipe or the floor, the whole game stops. This isn’t ideal, since it is essentially the same as the game freezing since there’s no game over message or sound; if the player doesn’t know to hit the ‘r’ key to reset the game, they will think the game has frozen. There is also a memory leak in that obj_pipe_generator is still creating a new pipe every 2 seconds just offscreen. If you let the game go on in this state, eventually it will break.
Finally, the movement. There are two aspects to the movement. First, vsp += grv. Remember that grv is our “gravity” variable, and we have it set during gameplay to .4. this short line makes it so that every frame, the vsp adds the grv value to it’s total. If the vsp value is 0 (like at the very beginning), after this line of code is run, then the vsp value will be 0.4. After another frame runs (assuming the player doesn’t press any keys), the vsp value will be 0.8. Another frame, and it will be 1.2, and so on. The next line will show how this affects the player.
y+=vsp. First off, Y is a special variable that defines the obj_mario location. so, if obj_mario’s Y position is 490 (the middle of the screen vertically), then the Y value is 490. So, when you add vsp to y, then obj_mario’s Y value will become 490.4, aka obj_mario will move down the screen by half a pixel. the next frame, vsp will have gravity added again, so obj_mario’s Y will be 490.4 + 0.8; the frame after that it will be 491.2 + 1.2; after that it will be 492.4 + 1.6; then 494 + 2.0. You can see that every frame that the player doesn’t press a key, grv will compound on the vsp variable, which means that obj_mario will move farther down each frame, which creates a sense of speeding up, or falling faster the longer obj_mario falls. I love the simplicity of this mechanic.
Ok, lastly, there’s the scenario where the player presses the spacebar. When this happens, the vsp is set to -15. So, when we get to the point of adding grv to vsp, vsp is -15, so it will be -14.6 after we add grv. Then, when this value is added to obj_mario’s position, it will go from, say 490 to 484.4, which in one frame will be a relatively fast upward movement. Immediately afterward in the next frame, the keyboard_check_pressed() variable will not be true (even if the spacebar is still being held down). From the previous frame, vsp will be -14.6. we will add grv to this, so it will become -14.2; the frame after it will be -13.8, then -13.4, then -13, etc, until vsp again reaches 0. This behavior will look like Mario jumping fast, then slowing to a peak. At that point, vsp will become positive again, and Mario will begin falling again, going faster the longer the player waits to hit the spacebar again.
And that’s it.
What’s Next
This took way more words than I expected, but I think it was worthwhile. I have a short list of things I want to add before I move on to my next mini project, and they will be the focus of the next 1-3 articles. These are:
- Add a jumping sound
- Change the animation speed when the player jump/flaps
- Add background sound
- Add a death animation and sound
- Add a score
- Add a game over screen with high scores
- Add an intro screen
And that’s it! After that I’ll strike out again on a top-down maze game. My goal is to learn a new method of movement (up/down/left/right), enemy objects with varied behavior, persistence, multi-room gameplay and/or views, and basic level design.
Stay tuned!