Introduction To Game Design & Programming in GameMaker Studio 2
Page 17
if position_meeting(mouse_x,mouse_y,id) && mouse_check_button_released(mb_left)//if mouse pressed over button
{
if my_level-1>=global.level//check local vaible against level
{
show_message("locked");
}
else
{
show_message("unlocked");
/// @description Goto room
room_goto(room_level_1);
}
}
if my_level-1>=global.level//check local vaible against level
{
image_index=0;//set image index
}
else
{
image_index=1;
}
Add similar code for the other buttons, changing the room_level_1 to room_level_2, room_level_3, and room_level_4, accordingly.
An example project is in the folder for this appendix.
If you save and test, you will see the game starts with level 1 and 2 unlocked. In appendix 18 you will learn how to save and load level values so they present when a game is started.
Basic Projects
• A) Create a splash screen and place an object with a sprite animation. Set it to go to the next room 5 seconds after the animation has ended. (use code or animation end event to check for animation ending)
• B) Create a menu room with background music with a button for it to go to an instructions room (with button to return to menu room).
Advanced Project
• C) Create an object that becomes unlocked only if user types in a password on the keyboard. Make the password “bacon.” Display visibly whether the object is locked or unlocked.
Appendix 16 Random
Randomization can be used for a lot of things:
Choosing a random sound effect
Spawning an enemy at a random location
Adding diversity to your game
Selecting an effect to use
Making AI move / change direction
Choose an attack from a selection
Choose a random sound effect / backing music
Move an object to a new location
A static game with the exact same pattern of movement doesn’t have much replay value. This type of game can be memorized. Using randomness in your games to create variety in game play greatly increases the game replay value.
Strictly speaking there is no such thing as a true random number on a regular PC, but it can be simulated and approximated for game play.
For the purposes of making games easier to create and test, GameMaker Studio 2 will always generate the same random numbers each time a game is played. For example, if in your game you rolled a dice 5 times and got 5 3 1 6 3 2, the next time you played from the Studio IDE you’d also get 5 3 1 6 3 2. Depending on your game you may want different numbers each time when testing, so remember that a final executable will not display this behavior. To do this, use randomize(), which only needs to be called once at the start of the game.
For example, in the Create Event of an object in your splash screen you may have:
randomize();
Then in your game you may have:
starting_x=irandom(800);
starting_y=irandom(400);
Now each time the game is run, starting_x and starting_y will have different random values. Randomness can be used for such things as the following:
An example of a random function:
attack=choose(1, 1, 1, 2, 2, 3);
This will choose a number at random. There will be a 50%(3/6) chance of getting a '1,' a 33%(2/6) chance of getting a '2,' and a 17%(1/6) chance of getting a '3’. Weigthed randomoness like the above code is a common feature in a lot of games.
You can also use other things as well as numbers: for example, objects, sounds, colours:
music_track=choose(snd_track_1, snd_track_2, snd_track_3);
text_colour=choose(c_green, c_red, c_blue); spawn_enemy=choose(obj_enemy_1, obj_enemy_2);
You can create a real random number:
number=random(50);
This will choose a random number between 0 and 50 exclusive, with decimal places.
An example of a value returned by the random() function: 44.7768221937 (which may contain more digits than this).
If you are generating real numbers with decimals, the following is useful; however floor is generally used for randomized values:
floor(4.2) would return 4
ceil(4.2) would return 5
round (4.2) would return 4
A method more suited to most applications, as it creates whole integers is:
number=irandom(50);
This will choose a whole number integer between 0 and 50 inclusive.
An example of this value is 38.
You can also choose a whole random integer number between values, for example, between 40 and 50 inclusive:
irandom_range(40, 50);
There may be times that you want the randomization to be the same each time, even when the game has been compiled to the final executable for distribution: for example, when you have a randomly generated level. To achieve this, you can use the following function:
random_set_seed(number);
If you want a random outcome each time.
Note: This should be placed just before any deterministic results are generated.
Basic Projects
• A) Play a random sound every time the player presses the spacebar.
• B) Make an object jump to a random position, no closer than 50 pixels near the edge of the window, when clicked with the mouse.
• C) Make an object move randomly around the room without going off of the edges. Make it change direction every 5 seconds. If it meets edge of room, make it change direction away from the edge.
Advanced Project
• D) Create a lottery game that chooses six different numbers between 1 and 49. Display them in ascending order, inside a circle. If the number is between 1 and 9 make the circle white, 10-19 blue, 20-29 green, 30-39 red, 40-49 yellow.
Appendix 17 AI
Most casual games involve a player and some form of computer AI (Artificial Intelligence). Basically an AI object will interact with what’s onscreen and what the player does. For example, in a top-down game the AI object may move toward the player avoiding other objects and shoot a bullet toward the player if they’re within a certain range. Usually in the first few levels of a game the AI object will be more forgiving to the player, but higher levels may make the AI more aggressive.
Some of the functions the AI may have:
Move toward player
Fire a bullet / missile toward player
Decide which card to play next
Punch the player if they’re not blocking
In most cases you’ll be checking whether a variable equals some number, or if a function is true or false – and use this to create the illusion of AI.
This starts with a very basic AI and progressively makes it more intelligent.
We’ll create a basic AI system that makes an enemy move toward the player, if there is a direct line of sight. Start a new project.
Create three new objects, obj_wall, obj_player, and obj_enemy and assign a sprite for each, each 32x32 in size..
Place the following code in the Step Event of obj_player. This code will allow the player to move so long as it does not collide in the direction it is traveling into an obj_wall instance:
/// @description movement
hor=4*(keyboard_check(vk_right)-keyboard_check(vk_left));
vert=4*(keyboard_check(vk_down)-keyboard_check(vk_up));
if !position_meeting(x+hor+(sign(hor)*16),y,obj_wall)
{
x+=hor;
}
if !position_meeting(x,y+vert+(sign(vert)*16),obj_wall)
{
y+=vert;
}
The above code will check that there is not a wall in the direction that the player wants to move, if there isn
’t then it will move. That is all for this object. Create a basic room and check that the player cannot move through the walls, as shown in Figure A_17_1:
Figure A_17_1: Room for testing
A project file for this, example_1, is in the resources folder for this appendix.
Open up object obj_enemy and put the following code in a Create Event. This will create a flag that can be changed and tested upon, with true if it has a direct line of sight to the player, or false otherwise:
/// @description Set Flag
can_see=false;
In the Step Event of this object put:
//if there is a direct line of sight between the player and the enemy then set can_see to
true, otherwise false
if (collision_line(x, y, obj_player.x, obj_player.y,
obj_wall, true,false))!=noone
{
can_see=false;
} else
{
can_see=true;
}
if can_see
{
mp_potential_step( obj_player.x, obj_player.y, 2, true);
}
collision_line returns whether an imaginary line between it and the player instance collides with an instance of obj_wall. It returns false if it collides with obj_wall.
mp_potential_step( obj_player.x, obj_player.y, 2, true); moves the object 2 pixels towards the
player for each frame.
Finally create a Draw Event for this object with the following code:
draw_self();
if can_see
{
draw_line(x, y, obj_player.x, obj_player.y);
}
This will draw its own sprite, and a line between itself and player if can_see is true.
Place one instance of obj_enemy in the room and test. It will look like that in Figure A_17_2:
Figure A_17_2: Showing room being played
Load snd_ouch from the resources of this appendix.
Place the following in obj_enemy with a Collision Event with obj_player:
/// @description On collision
audio_play_sound(snd_ouch,1,false);
instance_destroy();
The above code will play the sound on collision with the player instance, then destroy itself.
Instead of playing a sound you could do things such as removing a life or making a graphical effect.
example_2 in the resources folder shows has the progress so far.
Next create an sprite spr_bullet which is 8x8 in size. Assign to an object obj_bullet.
Put this code in a Collision Event with obj_player:
/// @description On collision
audio_play_sound(snd_ouch,1,false);
instance_destroy();
Change the Step Event for obj_enemy to:
//if there is a direct line of sight between the player and the enemy then set can_see to true, otherwise false
if (collision_line(x, y, obj_player.x, obj_player.y,
obj_wall, true,false))!=noone
{
can_see=false;
} else
{
can_see=true;
}
if can_see
{
mp_potential_step( obj_player.x, obj_player.y, 2, true);
timer++;
} else
{
timer=0;
}
if timer==10
{
bullet=instance_create_layer(x,y,"Instances",obj_bullet);
bullet.direction=point_direction(x,y,obj_player.x,obj_player.y);
bullet.speed=5;
timer=0;
}
This change will make the variable timer count up if it can see the player instance. If it reaches 10 it will create a bullet instance and reset the timer. If the player is hidden, the timer will be set to 0.
You can now save and test the game. An example project example_3 is in the resources folder.
This next part continues on from the previous example; do not start a new project.
Create an object, obj_food and assign a 32x32 sprite to it.
In a Collision Event with obj_player put:
/// @description Jump to random position
score++;
x=irandom(800);
y=irandom(400);
while(!place_free(x,y))
{
x=irandom(800);
y=irandom(400);
}
Place 3 instances of obj_food in the room and save an test this. There is an example in folder, example_3.
If it collides with the player it will award a point and find a new free location.
Change the Collision Event code of obj_bullet with obj_player to: /// @description On collision
audio_play_sound(snd_ouch,1,false);
score--;
instance_destroy();
Finally create an object obj_score, and place the following in the Draw Event (or Draw GUI Event):
draw_text(100,50,"Player:"+string(score));
Place one instance of this object in the room.
You can now save and test.
An example project example_4 is in the resources folder.
Basic Projects
• A) Create a control object that moves randomly left and right across the top of the window, wrapping as needed. It creates a bomb every 5 seconds that then falls toward the bottom. Player gets a point for every one collected. Player can only move left and right at the bottom of the screen, without being able to leave the window. Use the control object to draw the score in the top left of the window, remembering to set a font, drawing style, and colour.
• B) Make a movable player object (using arrow keys) and a static enemy object. Make the enemy shoot at the player, getting faster as the player gets closer. Prevent the player from leaving the window. Ensure the bullet gets destroyed when leaving the room; use room_width & room_height for this.
(See distance_to_object in the help file).
Advanced Projects
• C) Create an enemy that changes direction every 5 seconds to move away from the player, and wraps around the room if it goes off of the edge.
Appendix 18 INI Files
With casual games that people may only play for a few minutes at a time, the ability to store the player’s progress is a required feature. Initialization or INI files provide an easy way to save and load data.
With INI files you can pretty much save any data, but the main ones you’re most likely to save are these:
Player’s name
Health
Score
Lives
High Score
Distance traveled
Enemies killed
Player cash
INI files involve two main elements:
[section] and key=data
A simple ini file would look like this:
[player]
top_score=100
name="Bob"
You can save this as an INI file (use a text editor and save as savedata.ini) and add it to the included files on the project tree. You can do this by right-clicking on Included Files and selecting Create Included File.
Note: On most exports it is not required to include an INI as an included file. This is not the case in HTML5, in which you must include one.
To load data from this file you can use:
ini_open("savedata.ini");
global.top_score=ini_read_real("player","top_score",0); global.player_name=ini_read_string("player","name","");
ini_close();
What the above code does:
Looks for a file named savedata.ini
Sets the variable global.top_score to the value stored in the INI file. If the file or section and key do not exist it sets global.top_score to a default value, in this case 0 (the value after the last ,).
Sets the variable global.player_name to the value stored in the INI file. If the file or section and key do not exist it sets global.player_name to a default value, in this case "" (th
e value after the last ,).
It then closes the open INI file.
You can also write variables to an INI file. For example:
ini_open("savedata.ini");
ini_write_real("level_section", "level", global.level);
ini_write_real("distance_section" ,"distance", global.distance);
ini_close();
This will store the current values of global.level and global.distance. If the values were 3 and 287, then the created INI file would look like this:
[level_section]
level=3
[distance_section]
distance=287
ini_read_real() and ini_write_real() work with real numbers. ini_read_string() and ini_write_string() work with strings.
Note: It is standard practice to close the INI file immediately after you have saved or loaded data.
Basic Projects
• A) Create two rooms, room_splash and room_game. Create an object for room_ splash that loads any data from an INI file to two global variables and takes the player to room_game. If no INI file is present, set the starting location the value of each to 100. Make this object clickable to go to room_game. Create a movable object for room_game, which starts in the position stored in the INI file. Pressing X saves the location to the INI file and restarts the game.
• B) Create a counter that keeps track of how many keypresses of space the player makes in total, and save/load the value of this counter to keep track of presses over multiple games. Use a splash screen with an object to load from the INI file. Show the presses amount on screen. Allow pressing X to save value and restart.
Advanced Project
• C) Create an object that takes in five people’s names, ages, and favorite food. Display this data on screen. When the game is restarted, and an INI file exists, give the option to display the current INI file or enter new data. Create a splash and main room as required. Allow pressing of X to restart. This example should use arrays, which haven’t been taught yet; this project is for the more adventurous.
Appendix 19 Effects
Eye candy is quite important in modern graphical games. Your backgrounds, sprites, and buttons need to be of high quality in a finished game. You can also create an assortment of graphical effects using the built-in effects function. The advantage of using the inbuilt effects is they are easy to program and update if required. In its most basic form you can create an effect using (“ef” designates effect):