Questions
and Answers
for
Game Maker 3.3
Last Changed:
February 15, 2001
Many users of Game Maker have asked questions on
how to do certain things. The forum is the best place to do this. Here I
collect some of the questions and answers that are useful.
How to move to a particular cell (tile)?
How do I shoot towards an object?
How do I move towards another object?
How do I add gravity to my game?
How can I push objects around in my game?
How do I make an object invisible?
How do I make sure certain objects lie in
front of other objects?
How do I create a delay between shots?
How can I give an object multiple appearances?
Lives, Health, Score and Timers
How do I give the player multiple lives?
How do I give an object health and display it?
How can I make the game react to two
simultaneous key presses?
How can I make the game react only once to a
mouse press.
How can my game react to the joystick?
How do I show the score in the playing area and
not in the caption?
How do I create full-screen games?
How do I make a more fancy help screen?
Can I use mp3 sound files in my games?
How do I create a scrolling background?
Where do I find images and backgrounds?
Where do I find sounds and background music?
How can I do something with one instance of an
object instead of all?
Can I define functions in the programming
language?
How do I make an installer for my game?
How can I change the icon of a stand-alone
game?
Can I add a help file to my game?
How do I create a nice image when the game is
loading?
How do I link to a web site from within a
game?
How to pause a game while playing?
How do I let the player save the game and
continue later?
How do I make my games faster?
How do I place my object more precisely?
In what order are the events processed?
Here are some tips on
how to move objects around in particular ways.
In
platform games a standard feature is that characters can jump. Jumping is
actually not the problem, landing is. Also there is the problem with interfacing
the horizontal movement and the vertical movement. Here is a way to make a
reasonably natural jump. You can check out the platform game demo in the games
section of the web site. This only works in version 3.2 and later!
In the creation event of the person set the gravity in direction 270 (down) and
the amount to e.g. 1. This means that whenever the person is in free air it
will start falling down. We will use the space key for jumping. In the space
key event first check whether the position below the person contains a solid
object. To this end check whether the relative position (0,2) creates a
collision. In this case, set the motion to direction 90 (upwards) and speed to
e.g. 12. This creates the jump.
Now the
landing, and this is crucial. In the collision event put the following code:
{
move_contact();
}
This function moves
the person out of the object with which it collides. This guarantees that we
end exactly on the floor and not a little bit above it. Next we set the speed
to 0 to stop falling further.
For the horizontal motion, when the left key is pressed check whether relative
position (-4,0) is empty and if so, move there. Similar for the right key.
OK, now let us add
ladders. Ladders must be non-solid objects. You cannot jump while on a ladder
and you should not fall down. Also you should be able to jump when you are on
the top of the ladder. Use the ideas above and add the following.
In the space key event
first check whether at relative position (0,0) we meet a ladder. In this case
exit the event. If at relative position (0,2) we meet the ladder, we also jump.
In the up and down key event, check whether we are meeting a ladder at relative
position (0,2) and if so check whether the position we want to go to is free
and if so, go there. (We must check position (0,2) otherwise you can never go
down at the top of a ladder.)
Now the more difficult
part. In the step event we check whether we meet a ladder at relative position (0,0). In this case we set
the speed to 0. (W should not fall down anymore.) Also we check whether at
relative position (0,2) we meet the ladder and, if so we set the gravity to 0.
Otherwise we set it to 1.
That is all. B.t.w.
you can use the ladder object also to maker ropes you can hang on (also
horizontal below a floor).
To keep objects
aligned on the cell you might want to move to a particular cell, e.g. the
fourth cell in the third row. To do this use the "move to a position"
action and as (absolute) values use 3*cellsize and 2*cellsize. (Note that you
must subtract 1 from the numbers because the top left cell lies at position 0,0.)
In some game you want
to have one object, say a monster, shoot in the direction of another object,
say a person. This can be achieved by using the following piece of code in the
creation event of the bullet. (This only works in version 3.1 and later.)
{
move_towards(person.x,person.y,8);
}
8 is the speed. The monster
simply creates a bullet at its own position. (This assumes that bullet and
person have the same size. If not, you might have to change the position to
move towards a bit.)
Of course this only
works if you can shoot in arbitrary direction. In a maze you probably only want
to shoot horizontally or vertically. In this case you should determine the best
direction by checking whether the horizontal or vertical distance to the person
is larger. E.g. use the following code:
{
if (abs(person.x- x) < abs(person.y- y))
{ hdir = sign(person.x ? x); vdir = 0;}
else
{ vdir = sign(person.y ? y); hdir = 0;}
speed = 8;
}
We use the sign
function to set the appropriate direction to ?1 or +1.
See the answer above
on how to shoot towards a person.
Assume you want to add
gravity to your game. So objects should fall down. The speed with which they
fall should increase every step. First give the objects a downward direction
but, at the start, set the vertical speed to 0. Now set the gravity with
direction 270 and amount 0.25. When the object hits the floor it should either
set the vertical speed to 0 or reverse the vertical direction. Now whenever
there is no floor below an object, it will start falling down with increasing
speed. (See the Falling Balls demo for an example.) This works very well for
platform games.
In a number of games
you want one object to push another object. This can be achieved as follows.
Assume the pushing object is called person and the object to be pushed is call
block. Now in the meeting event of the block with the person (so not in the
meeting event of the person!) put the following code
{
newx = x + other.x - other.xprevious;
newy = y + other.y ? other.yprevious;
if is_free(newx,newy)
{
x = newx;
y = newy;
}
else
{
other.x = other.xprevious;
other.y = other.yprevious;
}
}
The reason this works is as follows. other.x -
other.xprevious is the amount the
other object, that is the person, moved in this step in the horizontal
direction. So we simply copy this motion for the block. Obviously with a test
whether this position is free. If the new position is not free we don't move
the block and we place the person back to its previous location.
For your particular game you might need to
change this a bit. For example, you might want to use an is_empty() test rather
than an is_free() test. You can also set the speed to that of the other object to
make the block keep moving.
Here are some tips on
making certain types of objects that you often need.
Teleporters are object
that move the player from one place to the other. They come in pairs. When the
main character in the game (or some other character) hits one of them, it
should be transferred to the other. There are two problems when creating
teleporters: how to find the other teleporter where the person must go to, and
how to avoid that the person moves immediately back again. Let me give an
example of how this can be done. We assume the person object is the one that
moves around (and that there is only one such object). Let there be two
instances of the object teleporter. In the creation event of the teleporter set
a variable canteleport to true. Put the following piece of code in the meeting
event of the teleporter and the person (it is easier to put it here!)
{
if (!canteleport) exit; // teleporter is not working
forall (teleporter)
{
if (!is_meeting(x,y,other)) // when it is the other one
{
other.x = x; // move the person
other.y = y;
canteleport = false; // make the teleporter not working
exit;
}
}
}
That is it. When the
teleporter is working we look at all teleporters to find one that does not
intersect the person. We put the person there and make that teleporter not
working. If you want to be able to use the teleporter later again you can use
the following piece of code in the step event of the teleporter:
{
if (!is_meeting(x,y,other))
{
canteleport = true;
}
}
So at the moment the
person moves off the teleporter it is made working again.
In some game you want
to have invisible objects, like switches that trigger something or invisible
wall that block your movement. Don't do this by giving an object no image!. An
object without an image has 0 size and won't generate collision or meeting events!
So you never know that something bumped into it. So give it an image that has
the right shape. Now in its creation event use the code
{
visible = false;
}
Or, even easier, use
the action to set a variable for this. That is all. Alternatively, you can put
the Exit action in the drawing event of the object. Once there is something in
the drawing event the image is no longer drawn.
In a number of cases,
you might want objects to move over other objects. Objects are drawn in the
order in which they are added to the room. So make sure that you add the
objects that should go on top last. If you create objects during the game, this
does not work. In this case you can use the variable image_depth. It indicates
the depth of the object. The object with smallest image_depth lies on top.
Default the image depth is 0. So to put something in front, give it a negative
image depth. You can cange the image depth using the action to set a variable.
Best do this in the creation event.
But what if you need
two objects on top of each other at the start? There is a very simple way to
solve this problem. In the Options menu in the room form, indicate that you
allow objects on top of each other. Now place them in the correct order in the
cell. (Make sure you switch of the option immediately once you are done because
you very easily make mistakes with this.
Sometimes you want
things to happen not too often. For example, when the player can shoot bullets,
you don?t want new bullets to appear in every step. You want a delay between
them. Here is a simple way to do this. Assume the object that does the shooting
is the person and that the object he shoots is a bullet. In the creation event
of the person put the following code
{
canshoot = true;
}
(You can also use the
action to set a variable for this.) In the alarm event for alarm0 put the same
piece of code. In the event that shoots the bullet, e.g. the event for the
space key, put the following code:
{
if (canshoot)
{
canshoot = false;
alarm0 = 10;
create(x,y,bullet);
}
}
So we only create a
bullet when we can shoot. At this moment canshoot is set to false. After 10
steps the alarm event will set it back to true, so another shot can be fired.
You can vary the value for alarm0 to get a different delay. B.t.w. you can also
do this without code, just using standard actions. Delays are useful for many
other things as well.
In some games you have
objects that should have a different appearance (image) in certain situations,
but should have the same behavior. For example, in Pacman, the image looks
different depending on the direction of motion. To this end you can create
multiple copies of the same object with a different image and for the rest the
same behavior, but this is a lot of work. Using the drawing event you can solve
this problem in a much easier way. You create separate objects with the
different images but without any behavior. There is just one active object. In
the drawing event put some code to draw the correct image, depending on the
situation. For example, for the Pacman game the drawing code could look as
follows:
{
if (hdir < 0)
draw_image(x,y,pacleft)
else if (hdir > 0)
draw_image(x,y,pacright)
else if (vdir < 0)
draw_image(x,y,pacup)
else if (vdir > 0)
draw_image(x,y,pacdown)
else draw_image(x,y,self);
}
If the image is not
animated, you can also use sub images for this and choose the right sub image
by setting the variable image_index (0
is the first image!).
Here are some tips
dealing with issues like lives, health, etc.
Sometimes you want to
give a player limited time. In this case you want to create some visible
counter. This is easy to do. Let us assume we want to give the player 1 minute,
that is, have a counter that counts down in seconds from 60 to 0.
Make an object called
e.g. countdown. In its creation event, set a variable called e.g. thecounter to
60. Set the normal alarm to gamespeed to make sure we get seconds. In the alarm
event check whether thecounter is equal to 0 (in this case we do something).
Otherwise set variable thecounter relative to -1 and again set the alarm to
gamespeed. If you want to draw the
counter, in the drawing event draw a text
'timer: ' +
string(thecounter)
And that is all.
Many games have
multiple lives. This can be achieved as follows. Create an object called e.g.
life_object. Make sure there is a copy of this object in every room. In its
creation event we set the number of lives to a particular value (but only in
the first room). For this we use a global variable global.lives:
{
if (room==1)
global.lives = 3;
}
You can also use
standard actions for this. In its drawing event draw the text
'Lives: ' +
string(global.lives)
Now when the person dies
you check whether global.lives is 0. If so, the game ends. Otherwise, decrease
global.lives. So you e.g. use the following code:
{
if (
global.lives == 0)
{
end_game();
}
else
{
global.lives -= 1;
// do
something. e.g. start the room again
goto_room(room);
}
}
To show the number of
lives in a nicer way, you give the life_object a nice image. Give it the
following code in the drawing event:
{
draw_text(x,y,'Lives:');
xx =
string_width('Lives:') + 10 + 24*global.lives;
while (xx
>= 0)
{
draw_image(xx,y,self);
xx -= 24;
}
}
This draws a number of
copies of the object next to each other, each representing a life.
Assume there
is some object (like the main object or an enemy) that you want to give a
certain health. The first thing is to give it a variable e.g. called health and
set it to 1 in the creation event using the " set variable" action.
Whenever something happens to the object, decrease a bit from the health. When
it becomes < 0 do something (e.g. end the game). You can also check this in
the step event of the object itself.
Now in the drawing event of the object first of all draw the image of the
object, using the appropriate action. Next put the following piece of code:
{
set_pen_color(c_green);
draw_line(x,y,x+32*health,y);
set_pen_color(c_red);
draw_line(x+32*health,y,x+32,y);
}
You might need to change the value of 32 and maybe change the y position. Also
you can change the pen width with set_pen_size(3) to make it a bit clearer.
Interaction with the
player is an important aspect of games.
Here are some tips.
When the player
presses e.g. the left and up key you might want to let the ball move diagonally
to the left top. From version 3.1 onwards this is extremely easy. In the
keyboard event for the up key set the y-position relative to e.g. ?8 and in the
keyboard event for the left key set the x-position relative to ?8. If the
player holds both keys, both things will happen. If you want the motion to
continue after the player releases the keys, in the up key event set the
variable vdir to ?1 using the action to set variables. In the left key event
set variable hdir to ?1.
Normally, mouse events
are generated as long as the player keeps the mouse button pressed. For
example, a simple way to cheat in the Catch the Dog game is to keep the mouse
button pressed while moving the mouse to the dog. To avoid this, in the Game
Options, switch of the continuous mouse events. Now the player will have to
release the mouse button and press it again.
Though this might not
be obvious, the program actually has joystick support. Movements of the
joystick create keyboard events <NUMPAD>1 to <NUMPAD>9 as in the
numeric keypad. The four buttons generate keyboard events for the letters A, B,
C and D. Let some object in your game react to these events and you are done.
You can actually use the joystick in the provided Pacman game.
Obviously, you want
your game to look as nice as possible. This involves first of all the use of
nice backgrounds and object images, preferably animated. Here are some other
issues.
Scores are normally
displayed in the window caption. If you want to make the layout of your game a
bit more fancy, you might prefer to put the score somewhere in the playing area
itself. This can be done as follows. First of all, in the options form,
indicate that the score should not be shown. Now make an object that is going
to display the score. Give it an icon to be able to place it when designing
rooms, but this is not important cause we are not going to draw it. Instead, in
the drawing event place an action to draw text. Use the following text:
'score: ' +
string(score)
Because it starts with
a quote it is interpreted as a formula. The function string converts the score
value to a string. That is all. You might want to choose a more fancy font,
size, style and color for it using a font action.
As you probably know
the player can switch from windowed games to full screen games using the
<F4> key. Full screen games tend to look more professional. You can
achieve this directly by checking the appropriate box in the options form. You
might also want to hide the cursor and the score, and use your own score object
as indicated above. Finally, make sure that your rooms have a proportion 4x3
such that they will fill the whole screen.
I can imagine that you
find the standard game help facility too boring for you game. To improve this,
make a special room, with e.g. a nice background picture for the help, and
maybe some moving objects on it. Let us assume this is room number 2. In the
Game options, uncheck the help key box. Now for some object in your game, e.g.
the controller if you have one, put the following piece of code in the event
for the F1 key
{
save_game('tempgame');
goto_room(2);
}
In the help room put a
special object that in its step event does something like:
{
if (lastkeypressed != 0)
load_game('tempgame');
}
That is all. When the
user pressed the F1 key the game situation is saved and the help room is shown.
When the player presses any key there, he is returned to the saved game
situation. (This works only in version 3.1 or later.)
Wouldn?t it be nice to
replace the dull cursor by some nice (animate) creation of your own? This is
very easy to achieve. Create an object with the right image. Make is non-solid
but active. In the create event put the following code:
{
show_cursor(false);
image_depth = -1000;
}
The first line makes
the normal cursor invisible (you can also do this in the options form). The
second line makes sure that the new cursor lies on top of everything else. In
the step event put the following piece of code:
{
x = mousex-16;
y = mousey-16;
}
This puts your mouse
image at the correct place (the ?16 works for a 32x32 image with the important
spot in the center. If you have a different sized image or want the hotspot of
the cursor to be somewhere else, change these values).
Finally, make sure
every room has one of your cursor objects in it. Best do this for full screen
games.
Games require images
and sounds. Here are some tips.
Yes you can although
the dialog boxes to add sounds and to make a list of background music don't
show the files by default. But you can always indicate that you want to see all
files and then pick the mp3 files. There are though a couple of things you
should be aware of. First of all, not all systems support the playback of mp3
files. In particular some older systems don't support it. Secondly, to play m3
files streaming audio is used. To this end DirectShow must me installed on the
computer (if not mp3 files are still played but with the limitations that only
one file can be played at a time, no sound effects are possible, and they
cannot be used together with midi files). Again, quite some people don't have
that. Finally, mp3 files must be decoded. This takes computer time slowing your
game down, in particular at the start of playing.
In summary I recommend
you to use mp3 files only if you don't want to distribute your games widely,
and only use them for long pieces of sound or music. Other wise, you better
convert them to wav files and use them instead.
Scrolling backgrounds
are a nice way of adding a feeling of motion to your games. You can use them to
e.g. have a plane fly forward while avoiding objects (and shooting other
planes), to have a car drive over a road, etc. Make sure some other objects
move with the same speed as the background, to increase the illusion. For
smooth scrolling, make sure the background picture can nicely be tiled. You can
also use a big background picture, e.g. a long road.
You can set the moving
speed when creating the room, but you can also control the speed during the
game using pieces of code. This makes it possible to e.g. leave an object in the
middle of the room but have the world move when you press an arrow key.
If you cannot find the
images or backgrounds you like in the
provided collections, the best way is to search the web. On the web huge
collections of free images, backgrounds, animations, etc, are available. To get
you started, here are some of the sites that store such material:
These sites again have
many further links.
If you cannot find the
sounds you like in the provided collections or you want some nice midi
background music, the best way is to search the web. On the web huge
collections of free sounds and midi files are available. To get you started,
here are some of the sites that store such material:
Wave Files:
Midi Files:
These sites again have
many further links.
Using variables and
code makes Game Maker much more powerful. It is really not difficult and
you are highly recommended to spend some time on it, in particular the use of
variables. here are some more advanced tips.
Sometimes you want to
have one instance of an object do something rather than all. For example, when
you hit a button one door should open or one bomb should explode. This is not
trivial because when you indicate an object in an action, the action applies to
all objects of thi stype. Let me demonstrate how to do this using the following
example: We have two objects called whiteball and redball. When the player
touches a red ball, a white ball should turn red. To this end put the following
piece of code in the meeting event:
{
forall (whiteball)
{
change(self,redball);
exit;
}
}
This changes the first white ball
into a red ball and then exits the code so the other white balls stay the same.
If you want a random white ball to turn red, you can do this as follows:
{
while (true)
{
forall (whiteball)
{
if (random(100)<1)
{
change(self,redball);
exit;
}
}
}
}
It loops forever until a white
ball is turned red (with a small chance) after which it exits. (You should
actually check whether there are any white balls otherwise the loop loops
forever.) A similar approach can be used in many other situations.
The built-in
programming language does not allow you to define functions. But there is a
trick to do it. Make an active, non-solid object called e.g. function_xxx. In
its creation event put the piece of code that you want to use as a function.
Also, put in it an action to kill itself. Now to call the function in another
piece of code, use
create(-100,-100,function_xxx);
That will do the
trick. When creating the object, the creation event is executed which contains
the code that you want to be executed. Because the creation events destroys the
object again it is immediately gone. You can pass parameters through global
variables.
You obviously want to
distribute your games once they are ready. Globally speaking there are three
ways to do this:
Here are some further
tips.
Most programs are
nowadays distributed with so-called installers. You execute some setup program
which installs the program on your computer. An item is added to the start menu
and there is also often an uninstaller to remove the program again.
Creating such an
installer is very easy. First of all you need to create a stand-alone version
of your game using the appropriate menu item in Game Maker. Next you
need an install creation program. Many such programs are available on the web
for free. Here are some of the more popular ones:
Each has its own way
of working so carefully check the doc.
You cannot do this
from within Game Maker. Instead you need a tool to change the resources
of the program after you created the stand-alone game. One such program is
called Resource Hacker. It is free and you can download it from http://www.rpi.net.au/~ajohnson/resourcehacker/.
(I did not try it and don't take any responsibility.)
The standard help
mechanism for games simply shows the information file you create. You might
though want to do something more serious, like showing a real help file or a
html file. This can be done as follows: Create the help file, e.g. game.hlp.
Place this file, together with the game.cnt file (if you have created that as
well) in the data folder fort he game. In the game options uncheck the line
"Let <F1> show the help file". Now make sure you have some
controller object in each room. In its <F1> keyboard event put the
following piece of code
{
shellexecute('game.hlp','');
}
And the file will be
shown. (Due to a bug in Game Maker version 3.0 this won't work for the
<F1> key except in the stand-alone version of the game but you can use
another key. This will be corrected in version 3.1.)
You can use exactly
the same approach for compiled html help files (*.chm) or html files (*.htm or
*.html) and actually any other file you want to show.
The program won't be
stopped if you do this. An easy way to achieve this is to pause the game, as
shown below. Alternatively, you can use the function execute() but in this case
you will have to do some more work in writing your own little program to
display the help file.
When you create a
stand-alone version of your game you might want to show some nice image while
the game is loading (rather than the boring default image. This is extremely
easy. Create an image and call it loadimage.bmp. Place it in the game_data
folder and you are done.
Here are some
miscellaneous tips and tricks.
To this end you can
use the function shellexecute(file,args) . This passed the file parameter with
the arguments to the shell. If the file type is known by the shell it performs
the associated open action. E.g. doc files typically open word, html files
typically open the browser, executables are executed, etc. You cannot wait for
it to finish. file and arg must be strings. The file must be located in the
game data. Note that this cannot be used to open a web page directly on a
particular site. You cannot give the routine a web address.
If you want to give the option to connect to a web site you can create a web
document that redirects to the page you want and place that in the _data
folder.
For example, use the following document which we name web.htm and place it in
the data folder for the game:
<HTML>
<HEAD>
<META HTTP-EQUIV="refresh" CONTENT="1;URL=http://www.cs.uu.nl/people/markov/">
<TITLE>Web page</TITLE>
</HEAD>
<BODY>
</BODY>
</HTML>
Now create a piece of code
{
shellexecute('web.htm','');
}
and that is all.
An easy way to do this
is to have some object in your game (e.g. the controller object or the main
character) have an event, e.g. for the P key that show a message. As message
text you can use "Game Pause.#Press OK to continue." (Note that the #
symbol means going to a new line.) As long as the message is shown, the game
will be paused.
From version 3.1
onwards this is extremely easy. First of all, the player can always do this
using the <F5> key for saving, and the <F6> key for loading. (You
can switch this off in the options form.) If you want to control it from your
game you simply use the following two pieces of code. To save the game use:
{
save_game('thegame');
}
And to load it use:
{
load_game('thegame');
}
You can obviously use
any other file name for saving and loading, you can even ask the player for a
file name.
People always like
their games to be as fast as possible. Here are some hints on how to achieve
this:
If you want to
position your objects more precisely in the room, set the cell size to half the
actual object size. Now you can place objects at many more places. (You can
also make objects partially overlap this way.)
In some cases it is
important to know the order in which the events in the game are being
processed. This order is as follows:
1.
Handle the alarm
events.
2.
Handle the
keyboard and mouse events.
3.
Handle the step
events.
4.
Set each active
object in its new position, based on speed and direction of motion.
5.
Handle the other
events.
6.
Handle the
collision events until no collisions occur anymore (when a collision occurs,
the object is put back into its previous position to let the event change the
motion after which it is moved again). If there is still a collision after the
number of tries indicated in the options form, the program gives up and leaves
the object at its previous position. (The default number of tries is 1 but this
can be changed in the options form.)
7.
Handle the
meeting events.