2d game engine workflow
TRANSCRIPT
Luis Vazquez Workflow Document
1
2D Game Engine – Level Design Workflow
Player Sprite and Object
To begin, I had to create a sprite to use as the visual element of the player character in game. To do that, I first
used the ‘create sprite’ option from the drop down menu of the project screen of Game Maker, as so:
This brings up this window:
I did not already have a sprite to use, so I selected ‘Edit Sprite’, which allows me to create a new sprite from
scratch. The designated dimensions of the new sprite are 32x32 pixels, which in the program creates a new
window:
Luis Vazquez Workflow Document
2
This is the sprite editor, where you can create and edit sprites. I zoomed in to the image (the image starts at
100% zoom, which is too small to accurately work from.
I started to make the player character (which I decided was to be a space ship with a steampunk theme) by
choosing two colours from the palette on the right of the window to choose two colours that I would make the
‘hull’ of the ship from. Using the darker colour, I made an outline of the shape of the ship, and filled it with the
lighter colour.
Luis Vazquez Workflow Document
3
From there I adjusted the colours of the ship and added new ones. I wanted the ship to look less ‘flat’ so I used
the opacity slider to approximately 20%, and applied the darker and lighter colours over each other in varying
amounts to give a slightly 3D look to the sprite.
Then I added light blue sections in a similar fashion, choosing a lighter and darker colour and using opacity to
create a gradient from the centre to the edge of the object.
From here, I made some adjustments to the sprite, notably that once I felt I had finished with the design of the
sprite I used ‘Transform – Rotate’ to turn the sprite 90 degrees. This is because the game I was making was a
side – scrolling shooter, not a vertical scrolling shooter, so the sprite needed to be oriented correctly. I was
also more comfortable designing ships from a vertical angle.
Luis Vazquez Workflow Document
4
With the sprite complete and saved, I go back to this window, where I make some changes to the properties of
the sprite. I change the name to ‘player_spr’ to signify that it’s the player sprite, so there’s no confusion later. I
also change the origin of the sprite (the location of the sprite that any actions related to the sprite originates
from) to the center of the sprite, using the ‘Center’ button.
With the sprite complete, now I needed to make an object to apply the sprite to. Similarly to the sprite, I
create the object by using dropdown menu – Create Object. This brings up an object property window. I edit
the name to ‘player_1’ and change the sprite used for the object to the ‘player_spr’ sprite made earlier.
I also edit the checkboxes to make the object visible and solid (so that it can collide with objects and interact
with objects such as enemy projectiles, which I’ll add later). I make sure that the object does not ‘Use Physics’
because the game takes place in an environment with no gravity.
Now I want the player object to be able to move, so I need to add and ‘event’ and an ‘action’. I click on ‘Add
Event’ and it comes up a small menu, from which I choose ‘Step – step’ (A step is an action occurs every frame
of the game).
Luis Vazquez Workflow Document
5
That creates an event. Now I need an action to trigger from that event. Rather than using the default actions
listed on the menu on the right of the window, I go to the Control tab and click and drag an icon to create an
empty code file.
Now I need to write the code that allows the object to move when I press a particular key. In this case, I want
to use the standard WASD configuration for the movement of the object. I separate each section of code with
‘comments’ (text prefaced with /// that marks the text as not being part of the code) to mark out which parts
of the code do what.
Each direction uses a common code line – ‘if keyboard_check(ord(“”)). This means that the game checks
whether or not a specific key (an uppercase letter or relevant symbol placed in the speech marks) is being
pressed.
The next code line tells the game to move the object in a particular distance in the XY coordinate system if that
key is pressed, seen in this screenshot:
Luis Vazquez Workflow Document
6
Rooms
With a functioning player object with visible sprite, I now want to test the object in-engine to make sure that it
is working correctly, and that there is no issue with the coding. However, I first need to create a ‘room’ so that
the object can exist in a game space.
Creating a room is similar to creating a new object or sprite, with right clicking on the drop-down menu and
clicking ‘create room’. Doing so creates this window:
Luis Vazquez Workflow Document
7
For now, I just want a simple room, so I just adjust a few settings. I enter the settings tab, and set the name of
the room to “room1”, and adjust the width and height of the room to be 1024x576 pixels. I then go to the
background tab, and change the colour of ‘background0’ to be black.
With this, when the game starts up it will take place in 1024x576 black room. That will be the limit of the
player can see or interact with when they control the game. I now need to place the player object into the
room, which is done by going to the objects tab, selecting the player object, and then clicking on a place in the
room. It is worth noting that when you click on the room it makes an individual object with the same
properties and coding, so it is possible to create multiples of the player object, while I only want one.
Now I can start up the game by pressing the ‘Run’ button, found on the project screen, seen here:
Luis Vazquez Workflow Document
8
When you click on Run, it brings up this window:
This is the game as it currently is, with the player object moving with the coded WASD keys to move up, down,
left and right. There are no problems, so I close down the game and continue with the project.
Luis Vazquez Workflow Document
9
Setting Movement Limitations
When testing the game, I noticed that the borders of the window of the game are not necessarily the
constraints of it; the player object can move out of the boundaries of the window just by using the movement
scripting. Therefore, I need to make it so that the player object is stopped at or before the edges of the game
room.
To do this, I go back to the player_1 object and its movement scripting, and I introduce new code, separate
from the WASD movement scripts. They all follow the formula (if (x/y) (</>)= value {(x/y)=value}). This means
that the object will stop when they reach the distance that equals a value in a particular direction. For example
if it is set as (if x <= 32 {x=32}) then if the player object tries to move closer than 32 pixels to the left edge of
the screen, then it will stop at 32 pixels from the edge of that side.
Backgrounds and Parallax Scrolling
Now I am to add a moving background to the game, giving it the illusion of movement. Outside of Game
Maker, I use Adobe Photoshop to edit images I found on the internet to create appropriately sized images that
I can apply directly to the resolution of the background (1024x576).
Luis Vazquez Workflow Document
10
Once I have the image I can now apply it. I next create a background in Game Maker, which creates this
window.
I click on Edit Background which brings up the pixel grid based image editor, and I use the ‘open’ function to
load in the image I have edited.
Luis Vazquez Workflow Document
11
This loads the image into the file, which also adjusts the canvas size to fit the appropriate resolution.
Once that is done, I accept the changes to the background and I save the image. Now I need to change ‘room1’
so that it uses this image as its background.
I open the ‘room1’ properties window and go to the backgrounds tab. The backmost background, ‘Background
0’, had previously been set as a flat colour, so I uncheck ‘Draw background colour’. Then I open the image drop
down menu and select the background image I edited, named ‘space1’.
Luis Vazquez Workflow Document
12
Now I want the background to scroll horizontally as I play, so I go further down the options and the window
and go to the ‘Hor. Speed’ text box. This sets how fast the image scrolls to the left or right. I input -6 as the
value for this box, so that it moves from right to left.
Now I want to add another background element that will move independently of the first background, which
will help to add a sense of depth to the background as the game plays.
Luis Vazquez Workflow Document
13
Similar to before, I edit an image in Adobe Photoshop to an appropriate resolution, this time of shooting stars
that will ‘fly’ across the screen. This time, however, I cut away the black space of the image to create an alpha
channel, so that images can be seen below this one.
Applying this image is very similar to applying the first image (create background, edit background, open
image, save, rename the background element to ‘stars1’), although there is a difference, in that when I open
the image in the editor, I need to checkbox ‘remove background’. What this does is apply the alpha channel to
the image, which will allow me to overlay this image over other background images in the engine.
As before, I open ‘room1’ and select the image as Background 1, which will appear to be ‘in front’ of the
previous background, Background 0. I also give the image a ‘Hor. Speed’ value of -8, so that it will move in the
same direction as Background 0, but will move faster.
Luis Vazquez Workflow Document
14
Particle Systems and Creation
Now I am to create a particle system to recreate the idea of flames beings shot out by the exhausts of the
spaceship; the first part to accomplishing this to create the actual sprite that will be used in the game. Making
the sprite is the same process as making any other sprite – the only notable quality about this sprite is that it is
very small, at 8x8 pixels.
Luis Vazquez Workflow Document
15
Next, the particle system needs an object to be emitted from. I created an object in the same way I created the
player object and named the object ‘jet’. Then, in order to make the object emit particles, I need to give it
code. I create a ‘step – step’ event and give it a code action.
Now I need to input the code for the engine to use. When fully written, it appears as this:
The codes ‘part_system_create’ and ‘part_type_create’ define terms to be used as the particle system and
elements of the particle system, respectively.
‘part_type_sprite’ defines the sprite to be emitted as a particle, whether it will be animated, and whether the
animation (if any) will have animation effects such as random – an effect which means that the frames of the
animation do not play in a consecutive order.
‘part_type_size’ determines the possible sizes of the sprite, from maximum to minimum, and has a function to
change the size of the sprite over time.
Luis Vazquez Workflow Document
16
‘part_type_life’ defines for how many frames the particle exists.
‘part_type_gravity’ determines how the particle moves when it is created, defines how much it moves, and the
direction that it moves in. The ‘random_range’ function allows the engine to select randomly from any value
between two given values.
‘part_type_alpha’ determines how transparent any given emitted particle is.
‘part_system_depth’ changes whether it appears ‘over’ or ‘under’ other objects. In this case the particles are
set to appear ‘under’ the player objects depth.
‘part_particles_create’ defines the place in the game world where the particles will be created. By using the
‘player.x’ and ‘player.y’ values, the object will follow the player object and emit from the same relative
position.
With the ‘jet’ object coded, I now need to apply the emitter to the player_1 object so that the particles will be
emitted in game. I open up the player_1 properties window, and I add an event, but this time a ‘create’ event.
A create event is one that is applied to the object as soon as it is created in game. I then add a code action.
I have also meanwhile created two copies of the jet object – jet2 and jet3 – to correspond with the visual
element of the player sprite I am using, because there are three exhausts in the visuals. They are exact copies
of the ‘jet’ object, but with adjusted x and y values.
Luis Vazquez Workflow Document
17
‘Instance_create’ creates the specified objects at the x and y coordinates provided in the code. In this case, it
does not actually matter where the particle emitters are created because the particles are emitted at a
separately defined location to the emitters.
In game, this is how the emitters appear:
Luis Vazquez Workflow Document
18
Player Projectiles and Sound
So now I am going to create a projectile for the player object to ‘shoot’ from itself, and attach sound to the
projectile that plays when it is created.
The first part, as with the other visual elements of the game is to create a sprite for the projectile object.
Notably, this object will have a modified collision mask, so that it can only collide with other objects that touch
it at the ‘tip’ of its sprite, so that objects colliding into its back or sides aren’t affected. This is mainly for
balance reasons, such as that an enemy hitting a projectile from the side shouldn’t necessarily destroy that
enemy.
To modify the collision mask, I go to the sprite properties and select ‘modify mask’ which brings up the
window below. I select ‘manual’ bounding box and I adjust the settings to have the hit box cover the entire
‘tip’ of the sprite.
Luis Vazquez Workflow Document
19
Next I need a sound that’ll play when the projectile is shot. I first need to ‘create’ a sound entity, like other in
engine entities, it is created by right clicking the relevant category and selecting ‘create ___’ in this case sound.
This opens up a window like this:
I rename the entity to ‘projectile1_sound’ and use the ‘load from file’ function to search on the computer’s
hard drive for a sound to use in this entity. I use a sound file I made for a previous task for this purpose. Once
that’s done I close and save the sound entity.
Now I need an object to attach the sprite to, and to have the player object spawn whenever the ‘shoot’ key is
pressed, and to play the projectile sound from. First I create the object and apply the sprite to it, and then I
create two event scripts, a ‘create’ action, and a ‘step'
In the create event I add a coded action, and input this code, which is for the movement of the object when it
spawns and to play the sound attributed to it:
‘hspeed’ (or ‘Horizontal Speed’) determines how fast it moves on the x plane.
Luis Vazquez Workflow Document
20
‘audio_play_sound’ plays the sound, determines its ‘priority’ respectively of other sounds, and whether it plays
on a loop.
The ‘step’ action is a coded action to destroy any instance of the object when it goes off screen. This is the
code in question:
Now to make the player object fire the projectile, I open the player_object properties window and open the
code file for movement, and input this code:
‘if keyboard_check_pressed(vk_space)’ makes so that when the space bar is pressed – and only when it is
pressed, not when it is held down – it performs an appropriate action.
‘instance_create’ creates the specified object, and chooses its x and y starting coordinates (x and y are relative
to the player object).
Luis Vazquez Workflow Document
21
In game, this is how the projectiles appear:
Animated Sprites and Enemies
Now I want to create an enemy that I can combat in the game.
The first step to creating an enemy is to create the sprite that will be used as the visual element of the enemy
object. Unlike previous sprites, I intend to make this enemy sprite animated, to add a bit of visual flair to the
aesthetic.
Creating an animated sprite is similar to making a stationary one, the only difference being that multiple
images are used in sequence to create the animation.
These are the sprites I created, in the order of sequence:
Luis Vazquez Workflow Document
22
Once I have completed the animation, I save the sprites, center the origin of the sprite and modify the collision
mask. In this case, I want the glowing orb to be the point of interaction for the enemy sprite so I modify the
mask to cover the orb.
So now I need to make two objects, the enemy object and a ‘system’ object that will use code to spawn the
enemies into the game.
First is the enemy object. This is functionally the same as making every other object; the only difference is that
because the sprite is animated, I want to set the speed of the animation, with ‘image_speed = 0.5’, which will
slow down the animation to be at half the speed of the levels native speed.
The ‘system’ object is an object without a sprite that can be placed anywhere in the game ‘room’, because its
purpose is to carry code that the game will execute. In this case there are two events to be created, a ‘create’
event action and an ‘alarm’ event action.
This is the create action.
‘alarm[x] = y’ sets the time at which the first ‘alarm’ will be activated. An alarm in Game Maker is an event that
occurs at a specified time in game, and this function sets the time of the first activation for my purpose.
Luis Vazquez Workflow Document
23
This is the coded action attached to the ‘alarm’ event. This code spawns the enemy objects into the game
‘room’ and then resets the alarm event that triggers the spawner.
‘randomise()’ is a function that sets the values following it to have a completely random result i.e. the
placement of the enemy spawns will be different each time they trigger, even when starting up the game
multiple times.
Enemy Destruction and Explosion Particles
Firstly, I create the sprites to be used as the explosion effect, which I create in the sprite editor as before:
Luis Vazquez Workflow Document
24
Then I created an explosion object and created scripts attached to that object so that it a) carries out its
animation when the enemy object is destroyed, b) ends immediately and c) plays a sound when it is created.
For this object, that involves three ‘events’ – a create, an alarm, and a step event – with a page of code for
each.
This is the code for the create event.
Alarm[1] = 5 sets the object so that the event set as Alarm 1 will trigger five frames after the object is created.
Audio_play_sound plays the designated sound when the object is created.
The alarm event only consists of one line of code – which is instance_destroy. So when the above alarm
triggers after five frames, the instance of the object will be destroyed.
Luis Vazquez Workflow Document
25
The step event code is for a particle system, similar to the one used for the thrusters of the player
ship.
The only remaining step before the enemy destruction and explosion functions is two independent collision
events between the player’s projectile and the enemy object.
For the projectile:
This is so when the projectile collides with the enemy object, it is destroyed.
For the object:
Luis Vazquez Workflow Document
26
This makes it so that when the enemy object collides with the projectile, it is changed into the explosion
object.
In game, the enemy destruction appears like this:
Enemy Projectiles
Making the enemies fire projectiles is mostly the same as making the player object fire projectiles, but with
two key differences. The enemy needs to fire towards a moving point (the x/y coordinate of the player) and
needs to fire without player input.
Luis Vazquez Workflow Document
27
This code is for a create event, so the projectile moves towards where the player was at the point of creation
of the instance.
This code is attached to an alarm event, so each time the enemy fires a projectile the alarm to fire another
projectile is reset.
Health System + Player Destruction
Now I need to add a ‘failure state’ for the player: a situation where the player can be described as having failed
the game. In order to do this I need to add a health system, complete with a visual representation of health (in
this case a health bar) and an explosion effect to accompany when the player dies.
Luis Vazquez Workflow Document
28
To create the health system, it requires some amount of coding across a number of objects already established
in the project, including the System and Player_1 objects. The codes for the system are as follows:
This creates the global variable for the shield (aka the health) of the player. The reason a global variable is
needed is because if the variable is just set as a normal variable, then the variable will not exist outside of the
object it is created in, and therefore it can’t interact between multiple objects as we need it to.
This code also sets the starting life of the player in an arbitrary number, here it is 100.
This code is attached to the ‘collide’ event, so whenever the player collides with an enemy projectile they take
an amount of damage – so with this number, when the player is hit five times, their health will be at 0.
This code makes it so that when the player ‘dies’ then the instance of the player_1 object, and the jet particle
systems attached to it, are changed into an instance of the player_explosion particle, ending the game.
The last part of this health system is to ‘draw’ the health bar so that it is visible in game. It is done in this case
using code attached to the system object:
The health bar has three parts – the outline, the background, and the visual representation of health (that
moves based on the amount of health the player has.
In game, the health bar appears like this:
Luis Vazquez Workflow Document
29
The explosion particle system for the player is mostly the same as the explosion particle system for the enemy
objects, with the only major differences being the sprites and sounds used for that system. In game, it appears
like this:
Score System
Now I am to add a score system to the game: which involves a series of code that will make and modify an
established global variable, the points number, to create a visual representation of the sum of the player’s
actions.
First, I need to ‘create’ a usable font. This involves right clicking on the ‘fonts’ drop-down menu, selecting
‘create font’ and then choosing a font and appropriate modifications, including colour, bolding/italics, and size.
Now, I create the global variable in the system object, with the code-
‘global.var points;
points = 0;’
then, I create another code for the ‘draw’ event, containing:
Luis Vazquez Workflow Document
30
After that, the only remaining part of the score system is for the enemies to produce points when they are
destroyed. This is done by adding the following code to the enemy object’s collide event:
This adds a point whenever the enemy is destroyed.
In game, this is how the point system appears:
Adding a Second Enemy
Now I want to add a second enemy, which will feature different movement, shooting and spawning patterns.
The process is the same as adding the first enemy, though there are a few differences in the coding of the
second enemy object, particularly in the second enemy’s projectile.
Unlike the first enemy’s projectile, the second enemy fires in a straight line horizontally. The projectile also has
a slight delay before it fires, via use of the alarm function.
The alarm event features this code:
Which causes the projectile to move at a much greater speed.
In game the second enemy looks like this, with its projectile:
Luis Vazquez Workflow Document
31
Adding Health Pickups
As an additional feature to the second enemy, I want them to drop ‘health pickups’ when they are destroyed,
so that the player can continue playing by actively taking risks by shooting enemies to sustain themselves.
In a sense, the health pickup is very similar to a projectile, though it has some differences in this case.
Firstly, the object for the pickup needs to be spawned when a particular enemy is destroyed. This is
accomplished by adding a ‘create instance’ event to the coding of the destruction of the enemy in question.
The code for this is as such:
Now I want the object to follow the player constantly, to ensure that they acquire it as otherwise the
opportunity to gain health would pass by too quickly. So I create a step event and enter into it this code:
The only remaining part of this system is for colliding with the pickup object to heal the player. This is
accomplished on the player object, creating a collide event, and putting in this code;
The if statement section of the code makes it so that, if gaining life from this object would cause the player’s
life total to go over 100, it is reduced to 100 instead.
Secondary Weapon + Overheating
I am now interested in creating a second weapon for the player to use, which will fire faster than the player’s
primary weapon but will have limited usage. Creating the weapon is functionally the same as making the
original weapon, but with different sprites and a different line of code for the ‘fire’ function as seen here:
This makes it so that the engine continually checks whether or not the applied key is being pressed, and
activates the function if it is.
Now I want to implement the overheat system, which involves several steps. The first is to create the global
variables for the system, overheat and canfire.
Luis Vazquez Workflow Document
32
When the system is complete, this code will mean that the player starts with ‘no’ overheat, and can fire the
secondary weapon.
Then the player object needs this code, for the overall overheat system and applying it to the secondary
weapon fire function:
This code makes it so that when the variable ‘overheat’ has a value, it will decrease continually over time, so
that the weapon doesn’t overheat once and become entirely unusable for the rest of the play session, and also
so that when the overheat reaches its maximum value it becomes unusable until overheat reaches a value of 0
again.
This code is expanded from the secondary weapon fire function from earlier. The additional code makes it so
that the player can only fire the secondary weapon when canfire is 1. It also increases the value of overheat by
4 per shot.
Luis Vazquez Workflow Document
33
This code makes the value of overheat decrease over time (and faster when canfire is 0), and also prevents the
value of overheat from going below 0, so that the amount of time the secondary weapon can be fired is
consistent.
The overheat system is complete, and the only remaining step is to create a visual element to give the player
information about the overheat system, which I decided to do by adding a ‘overheat bar’ beneath the health
bar, done with this code:
In game, the secondary weapon and overheat system look like this:
Music
Adding music is simple and only requires two unique steps compared to adding other sounds into the game.
The first is to make the music loop, so that it repeats during gameplay, done with:
Luis Vazquez Workflow Document
34
The second step is to make it so that when the game ends, the music is stopped.
I did this by attaching this function to the player explosion object, which only appears when the player has lost
the game:
Title & Start Screen
Now I intend to add a ‘title’ or ‘splash’ screen, which the player will see when they start up the game via the
executable file that I will create later.
The first part of creating the title screen is to create a background image, done similarly to anything else made
in the image editor, with one notable difference – the use of text.
The text tool uses the overall colour selection system, and has a separate menu to select font, as well as text
effects such as italics or bold. Using the text tool looks like this:
Luis Vazquez Workflow Document
35
The completed title screen looks like this:
Now I need to actually put the screen in the game. This involves creating a new room, reorganising the room
layout so that the title screen comes first, and then adding a function so that when the player presses space,
the player moves from the title screen into gameplay.
To do this, I created a ‘keypress’ object, whose sole function is to check for space being pressed, and then
moving on to the game afterwards.
Luis Vazquez Workflow Document
36
Creating an Executable File
Now I have completed the game and need to export the game as an executable file that a person can activate
and play the game that I have made. This is done by selecting from the drop down menus ‘File > Create
Application’. From there I choose a name and save location, and the .exe file is created at that location.