In this lesson, you will create a top-down racing game in GameMaker. Instead of the car immediately moving at full speed, it will gradually accelerate, slow down using friction, and steer around a race track.
By the end of this lesson, you should be able to:
| Requirement | Description |
|---|---|
| Player Car | A car controlled by the keyboard. |
| Acceleration | The car gradually speeds up. |
| Braking | The car can slow down and reverse. |
| Steering | The car turns left and right. |
| Friction | The car gradually slows when the accelerator is released. |
| Maximum Speed | The car cannot accelerate forever. |
| Race Track | A visible area for the player to drive. |
| Checkpoints | At least four checkpoints. |
| Checkpoint Order | Checkpoints must be reached in the correct order. |
| Lap Counter | The game keeps track of completed laps. |
Create a new GameMaker project named:
PX_lastname_Top-DownRacing
Create the following assets:
spr_car
obj_car
spr_checkpoint
obj_checkpoint
spr_wall
obj_wall
rm_race
Create a sprite named:
spr_car
The car should be viewed from above. A simple rectangle is fine.
Set the sprite origin to:
Middle Center
Create an object named:
obj_car
Assign spr_car to the object.
Add a Create Event to obj_car.
car_speed = 0;
acceleration = 0.15;
brake_power = 0.20;
max_speed = 6;
max_reverse = -2;
friction = 0.05;
turn_speed = 3;
next_checkpoint = 0;
lap = 0;
| Variable | Purpose |
|---|---|
| car_speed | Current speed of the car. |
| acceleration | How quickly the car speeds up. |
| brake_power | How quickly the car slows down. |
| max_speed | Maximum forward speed. |
| max_reverse | Maximum reverse speed. |
| friction | Natural slowing of the car. |
| turn_speed | How quickly the car turns. |
| next_checkpoint | The checkpoint the player must reach next. |
| lap | The number of completed laps. |
Add a Step Event to obj_car.
if (keyboard_check(vk_up))
{
car_speed += acceleration;
}
Holding the Up Arrow gradually increases the car's speed.
if (keyboard_check(vk_down))
{
car_speed -= brake_power;
}
The Down Arrow slows the car. If the player continues holding Down, the car can move backward.
car_speed = clamp(car_speed, max_reverse, max_speed);
The clamp() function keeps a value between a minimum and maximum.
Minimum = -2
Maximum = 6
if (!keyboard_check(vk_up) && !keyboard_check(vk_down))
{
if (car_speed > 0)
{
car_speed -= friction;
car_speed = max(car_speed, 0);
}
if (car_speed < 0)
{
car_speed += friction;
car_speed = min(car_speed, 0);
}
}
Release the accelerator. The car should gradually slow down instead of stopping instantly.
if (abs(car_speed) > 0.1)
{
if (keyboard_check(vk_left))
{
image_angle += turn_speed;
}
if (keyboard_check(vk_right))
{
image_angle -= turn_speed;
}
}
The car can turn only when it is moving. This makes the controls feel more like a real vehicle.
x += lengthdir_x(car_speed, image_angle);
y += lengthdir_y(car_speed, image_angle);
These functions use the direction of the car to calculate horizontal and vertical movement.
// ACCELERATE
if (keyboard_check(vk_up))
{
car_speed += acceleration;
}
// BRAKE / REVERSE
if (keyboard_check(vk_down))
{
car_speed -= brake_power;
}
// LIMIT SPEED
car_speed = clamp(car_speed, max_reverse, max_speed);
// FRICTION
if (!keyboard_check(vk_up) && !keyboard_check(vk_down))
{
if (car_speed > 0)
{
car_speed -= friction;
car_speed = max(car_speed, 0);
}
if (car_speed < 0)
{
car_speed += friction;
car_speed = min(car_speed, 0);
}
}
// STEERING
if (abs(car_speed) > 0.1)
{
if (keyboard_check(vk_left))
{
image_angle += turn_speed;
}
if (keyboard_check(vk_right))
{
image_angle -= turn_speed;
}
}
// MOVE
x += lengthdir_x(car_speed, image_angle);
y += lengthdir_y(car_speed, image_angle);
Place obj_car inside:
rm_race
Run the game and test the controls.
Demonstrate that your car:
Create your race track inside rm_race.
You can use:
The track should form a complete circuit.
+-----------------------+
| |
| +-----------+ |
| | | |
| | | |
| +-----------+ |
| |
+-----------------------+
Create:
spr_checkpoint
A checkpoint can be a rectangle placed across the road.
Create:
obj_checkpoint
Add a Create Event:
checkpoint_number = 0;
Each checkpoint should have a different number.
Checkpoint 0
Checkpoint 1
Checkpoint 2
Checkpoint 3
Starting Line = 0
Checkpoint 1 = 1
Checkpoint 2 = 2
Checkpoint 3 = 3
The player should drive through them in this order:
0 -> 1 -> 2 -> 3 -> 0
In obj_car, add a Collision Event with obj_checkpoint.
if (other.checkpoint_number == next_checkpoint)
{
next_checkpoint += 1;
}
The car only accepts the correct checkpoint.
If you have four checkpoints numbered 0 through 3, use:
if (other.checkpoint_number == next_checkpoint)
{
next_checkpoint += 1;
if (next_checkpoint >= 4)
{
next_checkpoint = 0;
lap += 1;
}
}
When the player reaches all four checkpoints, the lap counter increases.
Add a Draw GUI Event to obj_car.
draw_text(20, 20, "Lap: " + string(lap));
draw_text(20, 50, "Next Checkpoint: " + string(next_checkpoint));
draw_text(20, 80, "Speed: " + string(round(car_speed)));
Your game should display information similar to:
Lap: 2
Next Checkpoint: 3
Speed: 5
Make steering depend on the speed of the car.
var steering_amount = turn_speed * abs(car_speed / max_speed);
if (keyboard_check(vk_left))
{
image_angle += steering_amount;
}
if (keyboard_check(vk_right))
{
image_angle -= steering_amount;
}
Create:
obj_wall
Place walls around the edge of your race track.
When the car hits a wall:
car_speed *= -0.3;
This reduces the speed and creates a small bounce.
Create grass or another off-road area.
When the player leaves the road, reduce the car's speed.
car_speed *= 0.95;
Create a timer variable:
race_time = 0;
Increase the timer every Step:
race_time += 1 / room_speed;
Display the timer:
draw_text(20, 110,
"Time: " + string_format(race_time, 0, 2));
total_laps = 3;
Check:
if (lap >= total_laps)
Display:
RACE COMPLETE!
clamp()?After completing the basic game, try adding one or more advanced features:
Run your completed game and demonstrate one complete lap. Your teacher should be able to see acceleration, steering, checkpoint detection, and the lap counter working.