Anda di halaman 1dari 30

Intro:

Hello and welcome to this Construct 2 Course series for the creation of the game Jetpack Rush.
My name is George Femic and I am a professional video game developer. I have been developing video
games for more than 9 years.
I have mostly worked on Flash, mobile and HTML5 games. I am an experienced programmer and
designer and I am highly proficient in Actionscript 3.0, C# and Unity, Construct 2, Object Oriented
Programming, video game design, math and testing.
I started working as a programmer intern in a local game development company and I now work as a
freelancer and under the name GGames.

Lecture 1
Hello and welcome to the first Lecture of this Construct 2 Course for the creation of the game Jetpack
Rush.
In this Course series you will learn how to create a professional quality HTML5 game from scratch. It will
be a cross-platform browser game compatible with desktop and mobile devices.
Construct 2 is a great tool for creating games without having to write any code. It uses a powerful event
sheet system for programming.
This series will cover the Construct 2 editor, assets, event sheets, variables, logic, functions, event flow,
mathematical equations and everything else that is needed to develop Jetpack Rush.
--Gameplay
Jetpack Rush is a casual arcade game where the objective is to score as many points as possible.
The player can be controlled using the keyboard, mouse or touch control. By navigating the player, the
user needs to collect as many gems as possible, while avoiding the enemies. The games speed is
progressive and flows through 10 waves.
At the end of the game the player is awarded a 3 star rating based on their performance.
The game also features 10 achievements which the player can unlock.
--C2
In this Lecture we will go through the basic set-up for this game. You will learn how to set the project,
layout and margin size and import sprites and animations.
To begin, create a new project in Construct 2. Go to project properties and set the project size to 720,
400. The project size is the base resolution of the entire game. The optimal embed size is usually this
resolution. The size of the game will always scale proportionately to the size of the browser window.
Click anywhere on the layout to go back to the layout properties and set the size of the layout to
870x400 and the margins to 720x400. The size of the layout is larger than its margins, because in this
game the whole level will cover more than 1 screen. The solid border which envelopes the white
rectangle is the entire visible layout, while the dashed and transparent border represents the margins of
the layout.
Rename the layout to Game and its event sheets to Game events.
Next, we will import the background objects. [Importing, Names: HillsBack2, HillsBack1, HillsFront]
Set the position of HillsBack2 to 239, 339. This object should be behind the other hill objects. [Setting
depth on the same layer]

HillsBack1 should be positioned at 625, 339 and HillsFront should be positioned at 456, 348.
Create a new layer called Player. [Selecting layer], [locking, visibility of layers]
[Importing player animations: Default, Hit] [25, 56 origin] [448, 240] [Player].
The origin point always appears at the X and Y position of the object. If a rotation is done, the object
rotates around that point and when an image is mirrored or flipped, it is in relation to that point.
---------------------------------------Create a new layer called Gems. [import gem frames] [Name: Gem]
Place this object outside the borders of the layout. We will create all of the gems procedurally, through
the event sheets, so we do not need any gems inside the layout at the beginning of the game.
There needs to be at least 1 instance placed within or outside the borders of each layout where we need
to use that type of object. If there isnt an instance and we try to create a new one, Construct will
generate an error.
Create a new layer called Enemies. [import enemy anims: Appear[34, 38], Fly[36, 51]] [Call Enemy]
As these 2 initial objects will not be used at the beginning, we can destroy them when the layout starts.
Go to the event sheets for this layout and create a folder called OnLoad. [Add an On start of layout
event]. This event only occurs when the layout is loaded.
[Action destroy Gem] [Action destroy Enemy]-----------------------------------------Next, create a new layer called HUD. Set its parallax values to 0, 0. This will keep the objects on this
layout in a constant position, regardless of scrolling. This is perfect for HUD or User Interface elements in
games with an active camera.
We will now import the current wave indicator, which is composed of 4 objects.
[Import wave indicator assets Left Origin: WaveHudBack, WaveHudFill, WaveHudText] [Order of depth]
[Origin] [17, 30] [Text: 107, 31]
[Insert a new Text Object] [Name: WaveText, Pos: 77, 17, Font: Arial 18 bold, Text: 1]
Text objects can hold and display a string of characters, which can be altered. This particular text object
will hold the number of the wave the user has reached.------------------------------------------[import score sprite: 633, 33, ScoreHud] [Text object 597, 18 ScoreText Arial 18 bold, Text: 0]
We have now imported all of the core assets for this game. ---You have learned--This concludes the first Lecture for this Course series. We have now set up the basic objects in the game
and are ready to begin with the programming.

Lecture 2 Player Movement


Hello and thank you for watching Lecture 2 of this Construct 2 Course series for Jetpack Rush.
In the previous Lecture we covered the basic set up of the game.
In this Lecture we will program the player Object to move around the screen. You will learn about
Keyboard events, object position control, framerate independence, Sprite mirroring, variables, touch
events and math functions. ([448, 240] player pos)
First, go to the on-start event and add a new action. [Scroll to player action]
This will cause the game view to center around the Player object. We will also use this when moving the
player.
Next, create a folder called Loop and add an Every Tick event. This event is triggered continuously on
every frame during the game.
Add an empty condition to this event.
Create another folder called PlayerMovement and place it inside this condition.
Conditions are responsible for the flow control in the logic. If a condition is true, its inner blocks and
actions are executed. Otherwise the program skips to the section after the condition block.
------------------------------------------Next, create a variable called PlayerMovedWithKeyboard. Inside the empty condition, set its value to 0.
This variable will get the value of 1 whenever the player uses the keyboard to control the character.
[play animation Default ;spd 17] This will cause the players flying animation to loop constantly at
the speed of 17.
Create a constant called PLAYER_SPEED and give it a value of X.
The difference between variables and constants is that a variables value can change at any time, while a
constants can not change. Variables are placeholders for values and are very useful for programming
the logic of the game, as well as holding certain values such as the Players score.
Add an event inside the PlayerMOvement folder - >[Left Arrow is Down].
Add an action -> [Set player X to Player.X PLAYER_SPEED * dt]
X is a built-in variable for Sprite objects. Its value is used to determine the horizontal position of the
objects, while the Y variable is used for the vertical position.
dt is a variable which stands for delta time. The value of this variable depends on the framerate of the
game, so it can be used to make all additions and multiplications of values frame rate independent.

We should now set the value of PlayerMovedWithKeyboard to 1.


Add another action and [set the player to mirrored]. When an objects image is mirrored, it appears
inverted on the horizontal axis. This is useful for making the character face a certain direction.
------------------------------------------Next, add an else event and add another condition to it. This time we will check if the right arrow is
down.
An else event occurs when the previous condition it is linked to is not met.
The block of actions here is almost identical. The only difference is that the players X position will now
be increased and the image will not be mirrored.
We will now add another condition block in the PlayerMovement folder. The condition will check if the
Up arrow key is pressed. The block of actions here is very similar. We will now move the player on the Y
axis and there will be no need to mirror or unmirror the sprite.
Add an else event and a condition for the down arrow. Similar actions apply here.
------------------------------------------(Coordinate diagram)
When the value of X is lowered, the object moves towards the left. When it is increased it moves
towards the right.
For the Y axis, lowering the value makes the object move up and increasing it makes it move down.
------------------------------------------Next, we will check for mouse and touch input.
Add another condition and check if PlayerMovedWithKeyboard equals to 0.
[Import touch object]
We now need to check if the users mouse button is down or if they are touching the screen. [is in
touch]
Create a constant called MIN_TOUCH_DIST and give it a value of 7. This value will determine the
minimum distance between the touch location and the players position in order for movement to
occur.
Add another condition in the following block [test if distance(Player.X, Player.Y, Touch.X, Touch.Y) >
MIN_TOUCH_DIST].

------------------------------------------(Distance diagram)
Distance is a mathematical function which calculates the distance between 2 points represented by X
and Y coordinates.
The player will move faster if the touch location is further away from the Players position and slower if
it is nearby. This can be achieved with 1 action.
Create a constant called MIN_MOVEMENT_SPEED and give it a value of X. This will be the minimum
player movement speed. Create another constant called PLAYER_SPEED_DIST_DIVIDER and give it the
value of X.
Add an action for the Player object -> [Move] [max(MIN_MOVEMENT_SPEED * dt, distance(Player.X,
Player.Y, Touch.X, Touch.Y) / PLAYER_SPEED_DIST_DIVIER * dt)
Angle: angle(Player.X, Player.Y, Touch.X, Touch.Y)
------------------------------------------The way this all works is that the distance between the player and the touch location is divided by a
constant. This makes the players movement speed proportionate to this distance.
Max is a mathematical function which gives the highest of its 2 parameters. The parameters are divided
by a coma and are used as entry inputs for the function. Based on these values, the function calculates
the appropriate return value.
This way, the minimum movement speed is the value of MIN_MOVEMENT_SPEED * dt.
[Angle diagram]
The angle function is a mathematical function which returns the angle between 2 points.
------------------------------------------Create a new constant called MIN_DIST_TO_FACE_DIR and give it a value of 10.
Add another condition nested inside our previous block [abs(Player.X Touch.X) >
MIN_DIST_TO_FACE_DIR]
Abs is a mathematical function which returns the positive value of its parameter. If a value is negative, it
returns the equivalent positive value of it.
This allows us to check if the horizontal distance between the touch location and the player is large
enough to cause the player to turn left or right.

Add another condition here and check [Touch.X < Player.X]. If this condition is true, then the player is to
the right of the touch location and should be facing left. [Set mirrored]
Add an else block and [Set not mirrored], for when the player should face right.
Add an empty block within the touch event. Action [Scroll to Player]
Add an else event on the scope of the PlayerMovedWithKeyboard = 0 condition. [Scroll to Player]
Within the general scope of the player movement group, add 4 empty conditions.
These conditions will check if the players position is outside the imaginary borders of the game map.
If the X or Y value is lower than the minimum border value, or higher than the maximum border value,
we will set the players position to that value.
[Values X: 23, 831; Y: 63, 357]

//Testing game
This concludes Lecture 2 of this Course. We learned how to program a basic game mechanic, by using
events, conditional control, variables, object properties and mathematical functions.
In the next Lecture, we will introduce parallax backgrounds, functions and arrays.

Lecture 3 Parallax backgrounds, arrays and timers


Hello and thank you for watching Lecture 3 of this Construct 2 Course series for Jetpack Rush.
In the previous Lecture we covered the character movement mechanics.
In this Lecture we will cover parallax backgrounds, functions and arrays.
Parallax backgrounds are composed of several sections. Each section moves at a different speed, thus
giving the illusion of a 3D environment. Most games use horizontal scrolling for parallax backgrounds,
but in this game it will not depend on the scrolling. It will depend on the vertical position of the player
and the sections of the background will move at different speeds on the Y axis.
With parallax scrolling, objects which are closer to the screen move faster, while ones which are further
away move slower.

We will need to create 3 variables, which will hold the starting Y positions of the 3 background sections.
[Hills1StartingY HillsFront, Hills2StartingY HillsBack1, Hills3StartingY HillsBack2]
[Start event set to corresponding values]
We will use a function to reposition these objects. Functions are a set of actions which occur when the
function is called. They can also have parameters and return values. Parameters are the function inputs
and they can be assigned different values whenever the function is called. Return values are values
which the function returns as its output. For example, in the previous Lecture, we used a function called
distance. Its parameters are the coordinates of 2 points: X1, Y1, X2 and Y2. Its return value is the
distance between those points.
To use custom functions, we need to [Import Function object]
[Create a folder called Functions]
[Create a folder inside Functions called Parallax]
[Add function event Parallax]
We will now set the Y position of each hill object.
[HillsFront SetY = Hills1StartingY + (400 Player.Y) / 20]
[HillsBack1 SetY = Hills2StartingY + (400 Player.Y) / 50]
[HillsBack2 SetY = Hills3StartingY + (400 Player.Y) / 100]

As you can see, the Y position of the hills is their base position with an addition proportionate to the
Players position. Each addition is divided by a certain amount for each hill, making them move at
different speeds.
[Call Parallax function in PlayerMovement folder] [Call Parallax function in Start function]
--Test game-As you can see, the game now has parallax scrolling. The HillsFront object moves at the fastest rate,
while the HillsBack2 object moves the slowest.
Next, we will initialize a few arrays which will hold values for the game. -----Array chart----Arrays are a type of objects, which hold a collection of values. Each of the values is accessible using an
index number. The index numbers start at 0.
[Create preloader layer place at top of layouts folder] [Insert array objects: WaveTimerResets,
GemTimerResets, EnemyTimerResets, EnemyExtraSpeeds, MaxGemSpeeds]
Each of these arrays will have 10 values, for each of the waves in the game. We will use these values in
the next few Lectures.
All of the arrays which have Timer in their name will have their values used as timer values. We will use
delta time for timer countdowns, so the values we will assign now will approximately be equal to that
many seconds.
[On start event] [Create folder Array initialization] [Create folders for each of the arrays]
[WaveTimerResets: 0.9, 1.2, 1.5, 2, 2.8, 3.7, 4.5, 5.5, 7, 7.8]
[GemTimerResets: 0.1, 0.05, 0.05, 0.04, 0.034, 0.025, 0.025, 0.015, 0, 0]
[EnemyTimerResets: 10000, 10000, 10000, 1.42, 1.2, 1.1. 0.7, 0.5, 5]
[EnemyExtraSpeeds: 0, 0, 0, 0, 0, 0, 6 = 100, 7 = 100, 8 = 200, 9 = 300]
[MaxGemSpeeds: 120, 140, 155, 180, 180, 180, 210, 210, 245, 300]
[Blank event Go to layout game]
For now, we can have the preloader layout instantly switch to the Game layout, for quick testing.
The game will always need to be started from the Preloader layout, in order to initialize the array values.
This concludes Lecture 3 of this Course. We learned how to create a parallax background, functions and
arrays.
In the next Lecture, we will introduce the progressive wave system.

Lecture 4 Progressive wave system and data saving


Hello and thank you for watching Lecture 4 of this Construct 2 Course series for Jetpack Rush.
In the previous Lecture we covered parallax backgrounds, functions and arrays.
In this Lecture we will create the progressive wave system and cover data saving. You will also learn
about timers, accessing array values and percentage calculation.
Each wave will last a certain amount of time. The amount of time for each wave is stored in the
WaveTimerResets array. These values can be easily altered. Feel free to experiment with different
values for each wave. The same can be done for almost all values in the game.
To begin, create 2 variables: TimerNextWave and Wave.
The waves will be indexed starting from 0. So when the Wave variable is equal to 0, the displayed Wave
will be 1. The last wave will be marked as 9 in the event sheets, but as 10 for the player.
Indexing the waves this way will make accessing our array values more easily.
[Start -> TimerNextWave = WaveTimerResets.At(0); Wave = 0]
We have now assigned the first value of the array WaveTimerResets to the variable we just created.
By using the At function of an array we get a certain value from that array, based on the parameter.
Since the indexes of arrays start at 0, in this case we are getting the first value.
Variables which will have Timer in their name will be used as timers. They will allow for certain things to
occur after a specified period of time.
[Folder Waves]
[Condition TimerNextWave > 0] -> [Set TimerNextWave to TimerNextWave dt]
By deducting delta time from our timer variable, we are making the timers countdown framerate
independent, lasting 1 second multiplied by the amount of the timer.
[Set width of WaveBartFront to 179 / 100 * (TimerNextWave / (WaveTimerResets.At(Wave) / 100))]
Each time the timer for the current wave goes down, we need to update the HUD wave bar.
This bar represents the percentage of time that is left in the current wave.
[Percentage diagram]
Its maximum width, for 100% time left is 179. That is why we divide this value by 100 to get the amount
for 1%. We then multiply it with the percentile amount of TimerNextWave, as compared to
WaveTimerResets value with the index of the current wave.

10

[Else]
This block will occur when the timer drops to less than or equal to 0.
[Condition Wave < 9] ->
[Set Wave to Wave + 1];
[Set WaveText.Text to str(Wave + 1)];
[Set width of BarFront to 179]
[Set TimerNextWave to WaveTimerResets.At(Wave)
If the wave is lower than 9, which represents the final, 10th Wave, the Wave will get increased by 1 and
the Wave Text number will be updated. Str is a function used for converting a number to a string. A
string is a value type comprised of characters and numbers.
We will also set the width of the front wave bar to its Max size, as a new wave will begin.
The Wave timer is also reset to the appropriate value from the WaveTimerResets array. The Wave
variable is increased by 1 before the other actions, because we need to set the timer to the new waves
amount and the wave display text to the new wave index.
[Else block]
This block will occur when the last wave has finished.
We will fill this section later to redirect the user to the end screen.
----------------------[Preloader layout]
[Import WebStorage] WebStorage is an object used for saving and loading data.
[Var TimesFinished, TotalGems, LocalHighscore]
[Local key exists] => [Val = int(WebStorage.LocalValue(key))]
Int is used for converting a string value to a number.
This concludes Lecture 4 of this Course. We learned how to create a progressive wave system, progress
bar and timers. Feel free to practice your new skills by creating things with what you have learned so far.
In the next Lecture, we will introduce procedural gem generation and program the gems.

11

Lecture 5 - Gems
Hello and thank you for watching Lecture 5 of this Construct 2 Course series for Jetpack Rush.
In the previous Lecture we covered the progressive waves system, timers and percentile calculation.
In this Lecture we will add procedural gem generation and program the gems. We will cover instance
variables, rotation, random values and visual effects.
We will use some of the array values from Lecture 2.
[Var TimerNextGem] [Start -> TimerNextGem = 0]
This timer variable will serve as a countdown for creating a new gem.
[Folder NewGems] [Blank Subevent -> TimerNextGem > 0 ?] -> [Set TimerNextGem to TNG dt]
[else block] This block will occur when the timer has reached 0.
[Gem instance variables: RotationDirection = 1, Speed, RotSpeed, Collected = 0, Scale = 1]
Instance variables are variables which belong to an individual instance of an object. Different instances
can have different values for these variables.
We will create a function for creating new gems. Functions are useful for tasks which need to be
repeated and for managing larger chunks of events and actions.
[Function Folder NewGem] [on NewGem]
[Create object Gem on Layer Gem at ViewportLeft(0) + random(1) * 720, 20]
This will create a new Gem instance. The X position will have a random value between ViewportLeft(0)
and ViewportLeft(0) + 720. ViewPortLeft(0) is the position of the left corner of the screen, relative to the
camera. Its parameter determines which layer we need. In this case any of the layers, other than the
HUD one will do. By using this function, we can make sure that the gems spawn in the players field of
view.
Random is a mathematical function which returns a random number between 0 and its parameter.
[Gem] [Set opacity to 0]
An objects opacity value determines its transparency. At 0, the object is invisible and at 100 it is fully
visible and non-transparent.
Next, we need to make gems have variety. Each gem will be assigned a random color, starting angle,
rotation direction, rotation speed and falling speed.
[Set animation frame to round(random(4))]

12

This action will set the gems animation frame to anywhere between 0 and 4. Animation frame indexes
start with 0 and since the gems have 5 frames, the last frame will be indexed as 4.
Round is a mathematical function which returns the nearest rounded value of its parameter. For
example, if we have 3.7, the rounded value of this number would be 4.
[Stop animation] We dont want the gems animation to be playing, as we only need individual frames.
[Set angle to random(360)] This will set the gems initial rotation to anywhere between 0 and 360
degrees.
[Set RotationDirection to -1 + round(random(1)) * 2]
This action will set RotationDirection to either -1 or 1. The way it works is that we assign the rounded
value of random(1) multiplied by 2 to the number -1. The rounded value is either 0 or 1. If it is 0, we get
-1 and if it is 1, 2 gets assigned to -1 and we get 1.
[Constant GEM_MAX_ROT_SPEED = 220]
[Set RotSpeed to GEM_MAX_ROT_SPEED * max(random(1), 0.25)]
This will set the gems rotation speed to a value between 0.25 times the max rotation speed and the
max rotation speed.
-----------------------------------------[Constant MIN_GEM_SPEED = 80]
[Set Speed to
max(MIN_GEM_SPEED + Wave * 5, MaxGemSpeeds.At(Wave) * max(0.2, random(1))) ]
The speed of the gem is set to a value of the array MaxGemSpeeds based on the current wave,
multiplied by a random number between 0.2 and 1. If this value is lower than the first parameter, it is
set to MIN_GEM_SPEED plus the current wave multiplied by 5.
[Back at else block] -> [random(1) <= 0.5 Or Wave = 9?] -> [Call NewItem]; [Set TimerNextGem=arr(w)]
This will ensure that a new gem is created whenever the timer has finished counting down and we get a
random value lower than or equal to 5, or if the player is on the last wave.
After the gem is created, we also reset the gem timer.
Next, we need to program the gem behaviours.
[Folder GemsLoop]
[For each Gem]

13

A for each block is a type of control block, which loops through every instance of a certain type of
object. This entire cycle is done during 1 frame of the game. This is very useful for managing multiple
instances of an object.
[Set angle to Gem.Angle + Gem.RotSpeed * Gem.RotationDirection * dt]
This will cause the gems angle to increase or decrease by its rotational speed, based on its
RotationDirection variable. We multiply this value by deltatime to make it framerate independent.
[Set Y to Gem.Y + Gem.Speed * dt] This will cause the gem to move downwards on the vertical axis.
[If Y >= 430 ?] => [Destroy] This will destroy a gem instance if it has passed the entire screen. It is an
important practice to destroy or recycle objects which are not used anymore.
[Game layout -> Var Score; Start -> Set Score to 0] [Var GemsCollected; Set to 0]
[Function folder Increase Score] [On IncreaseScore]
=> [Set Score to Score + 100] ; [Score text = str(score)] ; [GemsCollected += 1]
[Gem Scope -> Collected = 0 ?] This block will occur if the player has not yet collected the current gem.
[Opacity < 100 ?] -> [Set opacity to Gem.Opacity + 100 * dt]
Each gem start out at 0 Opacity. This action cause the gem to become fully visible over a short period of
time.
[Player is animation Default playing] This checks if the players current animation is the default one.
The player should not be able to collect gems when hit by an enemy.
[On collision with player] This event triggers when a gem collides with the Player
[Set collected to 1] ; [Call IncreaseScore] ; [TotalGems += 1]
[Else on Collected = 0 scope] The else block will occur if the gem has been collected by the player. This
block of actions will make the gem disappear with a programmed animation.
[Set Scale to Gem.Scale + 3.3 * dt] [Set scale to Gem.Scale]
This will increase the gems size by a certain value on each frame. The default Scale value in Construct 2
can not be accessed directly, so we need to have a helper instance variable, which we called Scale.
[Opacity > 10?] Set opacity to Gem.Opacity 200 * dt] [Else] [Destroy];
This will cause the gem to slowly disappear and destroy it when it is nearly invisible. These 2 effects
combine for an interesting disappearance animation.
[Waves block -> Waves < 9 block] [ For 0 to 7 + Wave ] => [New item]

14

A for loop is a cycle of repeated actions. The number of cycles depends on the start and end index. This
block will cause several gems to spawn at the beginning of each wave.
[Test]
This concludes Lecture 5 of this Course. We learned how to create a procedural object generator,
randomize objects and use visual effects.
In the next Lecture, we will add the enemies.

15

Lecture 6 - Enemies
Hello and thank you for watching Lecture 6 of this Construct 2 Course series for Jetpack Rush.
In the previous Lecture we covered procedural gem generation, gem behaviors, randomization and
visual effects.
In this Lecture we will cover the enemy generation, behaviors and player hit state.
The enemies will appear after wave 3, at random locations and certain intervals. After a short
appearance animation, they will move aim for the Player and start moving in that direction. If the Player
is hit by an Enemy, they will not be able to collect gems while the Hit animation is playing.
To begin, create a variable called TimerNextEnemy. [Start -> TimerNextEnemy =
EnemyTimerResets.At(Wave)]
This timer will serve as a countdown for creating new enemy instances. Its reset values are the values of
the Array from Lecture 2 called EnemyTimerResets.
[Constant ENEMY_MIN_Y = 100; ENEMY_MAX_Y_ADDITION = 200; MIN_ENEMY_PLAYER_DIST = 200]
The first constant will denote the lowest possible starting position of an enemy. While the second one
will be the maximum addition to this value. The third constant is the minimum distance an enemy can
spawn away from the player.
[NewEnemies Folder] [Wave > 2 ?] Enemies will only spawn after wave 3.
[Enemy.Count = 0 ?] Count gives us the number of instances of a certain object which are
currently present in the layout.
[TimerNextEnemy > 0 ?] => [Set TimerNextEnemy to TimerNextEnemy dt
[Else] => [Create Enemy on layer Enemies at
(ViewportLeft(0) + 80 + random(1) * 560,
ENEMY_MIN_Y + random(1) * ENEMY_MAX_Y_ADDITION)
[TimerNextEnemy = ETR.At(Wave)] [Set animation to Appear] [Set anim speed to 17]
This will set the current animation for the enemy to Appear. The animation speed denotes how fast the
animation will play.
[distance(Player.X, Player.Y, Enemy.X, Enemy.Y) < MIN_ENEMY_PLAYER_DIST ?]
[Player.X ViewportLeft(0) > 360 ?] => [Set X to 50 + ViewportLeft(0)]
[else] => [Set X to 680 + ViewPortRight(0) 50]

16

These 2 blocks occur if the distance between the Enemy and the Player is lower than the minimum
amount specified by the constant value of MIN_ENEMY_PLAYER_DIST. We check to see if the player is
closer to the left or right side of the screen. Based on this, we set the enemys position near the edge of
the opposite side of the screen. This ensures that the enemy is at a good distance from the player.
[Instance variables: FlyingAngle, HitPlayer, FlyingSpeed]
FlyingAngle will be the angle at which the enemy will move after it appears. HitPlayer will be equal to 1
when an enemy hits a player. FlyingSpeed will be the enemys movement speed.
[Folder EnemiesLoop]
[Is Fly playing] => [Move Enemy.FlyingSpeed * dt at angle Enemy.FlyingAngle] ; [Set animation to Fly]
This will cause the enemy to move in the specified direction. We will also set the animation to Fly, so
that it keeps looping.
[HitPlayer = 0 ?]
[On collision with Player event] => [HitPlayer = 1]
This block sets the value of HitPlayer to 1, when an enemy collides with the Player for the first time.
---------------------------------------[Var TimesHit; Start set to 0]
This value will keep track of how many times the player has gotten hit during the current game session.
-------------------------------------------------------[Function folder HitPlayer => On HitPlayer] =>
[Score = max(0, Score 500)] This will cause the score to get deducted by 500, while limiting its lowest
possible value to 0.
[Score text = str(Score)] [Player set anim to Hit] [Speed = 17] [TimersHit += 1]
--Back to collision block
[Call HitPlayer]
[Else on HitPlayer = 0]
This block will occur if the enemy has hit the player. It will disappear over a short period of time.
[Opacity > 10 ?] => [Set opacity to Enemy.Opacity 1000* dt] [else] => [Destroy]

17

[Same scope as Else] [Is outside layout] => [Destroy] This will destroy the enemy if it is outside the
layout, which will always happen if the player is not hit by it.
[Else on main scope] This scope will occur if the enemy is still appearing.
[Animationframe = 7 ?] => [Set anim to Fly]
=> [Set FlyingAngle = ang(e.x, e.y, p.x. p.y)] ;
=>[Set FlyingSpeed to ENEMY_MIN_SPEED + EnemyExtraSpeeds.At(Wave) * max(0.2, random(1)];
This will set the enemys speed variable to the minimum speed with an addition of a random percentage
of the current waves extra speed.
[cos(Enemy.FlyingAngle) < 0 ?] -Cos diagram--This will check if the Enemy is moving
towards the left.
[Set Mirrored]
[Else] => [Set not mirred]
[Delete player anim actions]
[Folder PlayerAnim]
[Is Hit playing ?]
[Animation frame = 18 ?] => Set animation to Default
This will ensure that when the players hit animation finishes playing, the players animation will switch
to the default one.
[Else] => [Set animation to Default] ; [Speed 17];
This concludes Lecture 6 of this Course. We learned how to create another game mechanic and
determine if an angle is facing towards the left or right side on the X axis.
In the next Lecture, we will create the End Screen and pre-game intro.

18

Lecture 7 End Screen and pre-game intro


Hello and thank you for watching Lecture 7 of this Construct 2 Course series for Jetpack Rush.
In the previous Lecture we covered the enemy generation and behaviors, as well as the Players hit
state.
In this Lecture we will cover the end screen and pre-game intro. You will learn how to make an advanced
Star Rating effect.
[Duplicate game layout] [Delete objects] [2 layers]
[Import EndScreen: 360, 187]
[TextObject TxtFinalScore: 161, 122; Arial 16 bold; Opacity: 70]
[TxtFinalGemsCollected: 154, 160]
[TxtFinalGotHit: 175, 196]
All of these text objects will display certain statistics for the game session the player finished.
[Import MenuButton 363, 367]
[Import Star Blank and Full, outside of layout] [Variables: Index, StartedAnimation]
We will create 3 instances of this object to display the players performance rating. The player can have
1 full star, 2 full stars or 3 full stars. The full stars need to be aligned on the left side. Each of the stars
will appear with the proper animation, after the previous star has finished appearing.
[Create event sheet and set it to the layout]
Blank event: [TimesFinished += 1] ; [Set local key JRTG to totalgems; JRTF to timesFinished]
[Score > LocalHighscore ?] : [Set localhighscore to Score] ; [Set key JRHS to str(lochighscore)
[Var StarsRollIndex] This variable will keep track of which star should appear and play its animation.
[Constants STARS_X_SPACE = 40, STARS_START_X = 320, STARS_Y = 173,
SCORE_REQUIREMENT_3_STARS = 35000, SCORE_REQUIREMENT_2_STARS = 29500,
SCORE_REQUIREMENT_1_STAR = 20000]
[Folder EndScreenInit] [On start of layout]
=> [TxtFinalScore.text = str(Score)] ; [TxtFinalGemsCollected.text = str(GemsCollected)] ;
[TxtFinalGotHit.text = str(TimesHit)]
[Star Destroy] [StarRollIndex = 0]

19

[Local var StarsEarned = 0] A local variable only exists within the block it is created in. This is perfect for
temporary variables.
[Folder StarsEarned]
We will now check how the users score compares to the score requirements for each rating.
[Score >= SCORE_REQUIREMENT_3 ?] => [StarsEarned = 3]
[Else Score >= SR2 ?] => [StarsEarned = 2]
[Else Score >= SR1 ?] => [StarsEarned = 1]
[Else] => [StarsEarned = 0]
[Folder StarsInit]
[For 0 to 2] => Create object Star on Layer 2 at STARS_START_X + loopindex * STARS_X_SPACE, STARS_Y
For each new star, the loop index increases by 1. Since we are multiplying this with the STARS_X_SPACE
constant as an addition to the base x position, each next star will appear to the right of the previous
one.
[StarsEarned > loopindex + 1]
This checks if the current star should be filled, depending on its index and the stars the player has
earned.
=> [Set animation to Full]
[else] => [Anim to Blank]
[loopindex = 0] [Set StartedAnimation to 1]
The first star needs to play its animation immediately.
[else] [Stop animation] The rest of the stars should remain invisible.
[Block] => [Set star index to loopindex] ; [Speed 20]
[EndLoop folder] [Every Tick]
[StarsRolling folder]
[StarsRollIndex < 2 ?]
[For each Star]
[Index = StarsRollIndex ?]

20

[AnimationFrame = 7 ?] => [StarsRollIndex += 1]


When a star finishes playing its appearance animation, the next star needs to start appearing.
[Else]
[Animation frame = 0 && StartedAnim = 0]
=> [Start animation from beginning] [StartedAnim = 1] [Speed = 20]
[Game layout Waves folder empty else -> Go to layout End]
--Test how it looks
--Back in Game layout
We will now create the pre-game instructions screen
[Import Ready anim] [Anchor 1: 147, 224; Rest: 148, 128] [Anim2 Go 72,78 anchor] [Name: ReadyGo]
[Import instructions anim PreGameInstructions]
[OnStart] => [Set ReadyGo anim speed to 15]
[Var TimerStartGame] [Set to 1]
[Empty block -> TimerStartGame <= 0 ?]
This will ensure that the game begins after this timer ends.
[else] => [Set TimerStartGame to TimerStartGame dt]
[TimerStartGame <= 0 ?] [Set anim to Go]
After the timer is over, we will need to fade out the ReadyGo and PreGameInstructions objects.
[GoFade folder]
[Opacity > 10 ?] => [ReadyGo.Opacity = 2 * 100 * dt] [Set instr op to rg.op]
[else] [Destroy both]
This concludes Lecture 7 of this Course. We learned how to create an advanced star rating effect and a
pre-game instructions screen.
In the next Lecture, we will learn how to create menus.

21

Lecture 8 Menus
Hello and thank you for watching Lecture 8 of this Construct 2 Course series for Jetpack Rush.
In the previous Lecture we covered the end screen and pre-game intro.
In this Lecture we will cover the creation of all game menus.
We will begin by creating and setting up all of the menu layouts.
[Duplicate end screen] [Delete objects] [New event sheet]
[Insert a layer between the 2 layers]
[Import MenuForeground 357, 310] [Import Title 362, 70]
[In top layer]
[Import PlayButton 359, 225] [HelpButton 359, 290] [TrophiesButton 359, 352]
[Import EraseSaveDataButton 58,240] [HighscoresButton 58,291] [CreditsButton 58,339]
[Duplicate end screen Help] [Delete objects] [New event sheet]
[Insert menu button at 363, 367]
[Import HelpScreen 363, 185]
[Duplicate Help Credits] [Delete HelpScreen] [Same event sheet]
[Import Credits 363, 185]
[Duplicate Help Trophies] [Delete HelpScreen] [New event sheet]
[Import TrophiesScreen - 360, 181]
[Duplicate Help Highscores] [Delete HelpScreen] [New event sheet]
[Import Local 366, 254]
[TextObject TxtLocalHs 295, 267 ArialBold 14]
[Preloader events] [Go to Menu instead of Game]

Next, we will program all of the menus.


We will start with the Main Menu.

22

[Menu events]
[Folder MenuOnStart] [On Start of layout]
[Stop animation of each button]
Every button will stay on its first animation frame, until it is tapped or clicked. When it is tapped or click,
its animation will switch to the second frame. When the mouse button is released, or the user raises
their finger from the touch screen, all menu buttons will switch to the first animation frame.
[Folder MenuOnTouchStart]
[On any touch start]
[Is touching for each button] => [Set animation frame to 1]
[Folder MenuOnTouchEnd]
[On any touch end]
[Is touching Button && AnimationFrame = 1 for all buttons ?] => Action for each button
[Blank subevent]
This subevent will be used later when adding sounds to the game.
[Blank subevent in main scope] => [Set animationframe to 0 for every button]
[Highscores]
[Trophies]
[Credits]
[Help]
[End]
This concludes Lecture 8 of this Course. We learned how to create menu buttons for the game.
In the next Lecture, we will learn how to add trophies to the game.

23

Lecture 9 Trophies
Hello and thank you for watching Lecture 9 of this Construct 2 Course series for Jetpack Rush.
In the previous Lecture we covered the games menus.
In this Lecture we will cover trophies.
[Trophies layout]
[Import Trophy object]
[Preloader]
[Array TrophiesEarned] This array will have 10 values, each denoting whether a particular trophy has
been earned or not. A value of 0 will indicate that the player has not unlocked the trophy, while a value
of 1 will indicate that the player has done so.
[Start event Folder TrophiesStorageLoad]
--For each trophy:-[Local key TrX exists ?] => [Set TrophiesEarned at X to int(WebStorage.LocalValue(TrX))]
This will assign the saved WebStorage value of Tr0 to the arrays first value, if the value exists.
[else] => [Set value at X to 0] Otherwise, if there is no save data, the arrays value is set to 0.
[Trophies layout]
[Layer Trophies on top]
We will need to procedurally create the 10 trophies in the layout. For the Trophy positions, we will use
constants:
[Const: TROPHIES_Y_SPACE = 132, TROPHIES_Y1 = 100, TROPHIES_X_SPACE = 119, TROPHIES_X1 = 124]

24

[On start of layout]


[For 0 to 9]
[Create Trophy on Trophies at
(TROPHIES_X1 + ((loopindex < 5) ? loopindex : (loopindex 5)) * TROPHIES_X_SPACE,
TROPHIES_Y1 + ((loopindex < 5) ? 0 : TROPHIES_Y_SPACE))
The question mark operator is the ternary operator. If the condition before it is true, the first expression
is assigned. Otherwise the expression after the colon is assigned.
We use this conditional expression to check if the Trophy should be in the first or second row. The First 5
trophies, indexed 0 to 4 belong to the first row, while the other ones are in the second row.
[Stop animation]
[TrophiesEarned Array at loopindex = 0 ?]
=> [Trophy set animation frame to 0]
This block checks if the trophy at the current index has been earned. If it has not, the animation frame
will be set to the first one, where the trophy holder is blank.
[else] => [Set animation frame to loopindex + 1]
If the trophy has been earned, we will set its animation frame to the trophys appropriate image.
Next, we will add a trophy pop up in the game layout. A trophy will appear whenever the player earns
one.
[Insert Trophy object at 68, 97]
[Import TrophyEarned at 18, 140]
[Game events]
[TrophyEarnedID variable] This variable will keep track of which trophy has been earned last.
[Start event] => [Trophy stop anim] ; [Trophy set invisible] ; [TrophyEarned set invisible]
[Functions]
[EarnTrophy -> On EarnTrophy]
=> [Set visible Trophy and TrophyEarned , Set opacity to 100]

25

Next, we will need to check if all Trophies except the last one have been earned. If this is the case, the
player will receive the final trophy.
[Local number LoopContinue = 1]
[for 0 to 9]
[loopindex < 9]
[Trophy earned value at loopindex = 1] => [LoopContinue = 0]
If a trophy other than the last one has not been earned, the loop will be interrupted in the final block.
[else]
[LoopContinue = 1 ?] => [Set TrophyEarnedID to 9]; [Ar[9] = 1] ; [Local key Tr9 = 1]
[Empty block] => [Set Trophy animation frame to TrophyEarnedID + 1]
[Empty block]
This empty block will be used later when we add sounds to the game.
We also need to fade out and destroy any Trophy object that is created.
[Loop -> Folder TrophyPopUp]
[Trophy is visible ?]
[Opacity > 10 ?] => [Opacity -= max(0.2, (100 Trophy.Opacity) * dt); [Op for txt]
[else] => [Set Trophy and TrophyEarned invisible]
Now we need to program each trophys earning conditions.
Lets begin with the first, 6th, 7th and 8th trophies. The conditions for the first 3 are to collect 1, 30 and
195 gems in one game. The condition for the last one is to collect a total of 1500 gems in more game
sessions.

26

[Gem loop On Collision with Player]


[Trophy[0] = 0?] => [Trophy[0] = 1 ; Local key Tr0 = 1 ; TrophyEarnedID = 0; EarnTrophy()]
[Trophy[1] = 0?]
[GemsCollected >= 30 ?] => [T[5] = 1 ; Tr5 = 1 ; TEID = 5; EarnTrophy() ]
[Trophy[6] = 0?]
[GemsCollected >= 195 ?] => [T[6] = 1; Tr6 = 1 ; TEID = 6; EarnTrophy() ]
[Trophy[7] = 0?]
[TotalGems >= 1500 ?] => [T[7] = 1 ; Tr7 = 1 ; TEID = 7 ; EarnTrophy() ]
Next, we will set the conditions for Trophy number 5, which is earned when the player reaches the 5th
Wave, which is indexed as 4.
[Waves folder below For section]
[Tr[4] = 0 ?]
[Wave = 4 ?] => [Tr[4] = 1 ; Tr4 = 1; TEID = 4; EarnTrophy()]
The rest of the trophies can only be earned during the end screen.
[End screen]
[Copy Trophy function and Loop]
[Start below StarsInit Folder TrophiesEndScreen]
[Tr[1] = 0? ]
[StarsEarned >= 1 ?] => [Tr[1] = 1; Tr1 = 1, TEID = 1; EarnTrophy()]
[For 2 and 3 stars]
[Tr[8] = 0 ?]
[TimesFinished >= 10] => [Tr[8] = 1; Tr8 = 1, TEID = 8; EarnTrophy()]
This concludes Lecture 9 of this Course. We learned how to create a Trophy or Achievement system.
In the next Lecture, we will learn how to add sounds and music and wrap up the game.

27

Lecture 10 Sounds and wrap up


Hello and thank you for watching Lecture 10 of this Construct 2 Course series for Jetpack Rush.
In the previous Lecture we covered the trophies.
In this Lecture we will cover sounds and wrap up the game.
[Preloader events]
[Var Sound = 1, Music = 1]
When Sound or Music equals to 1, the sound or music is enabled. Otherwise it is disabled.
[Import sounds and bgm]
[Menu]
[Import Music Icon]: 36, 379
The first frame will be used when the music is turned off, while the second one will be used when it is
turned on.
[Import Sound Icon]: 76, 378
The sound and music icons will not have frames for when they are clicked or touched. Instead, we will
change their opacity. 80 will be the Opacity when they are not touched and 100 will be the Opacity
when they are touched.
[On start of layout] : [Music Set Animation Frame to Music; Sound Set animation frame to Sound]
[Stop animation]
[Set opacity to 80]
[Touch start event] [Is touching music ?] => [Set opacity to 100]
[Is touching sound ?] => [Set opacity to 100]
[Touch end event]
[Is touching music icon and Opacity = 100]
[Sound = 1] => [Play menu sound]
[Music = 0 ?] => [Music = 1]; [Play bgm at 0 db tag bgm]
[Else] => [Music = 0] ; [Stop bgm]

28

[blank subevent] => [Set animation frame to Music]


[Same for Sound button]
[Play menu sound for all buttons]
[Rest of menu layouts sound for buttons]
[Trophy function] [-7db]
[Variable TimerLastScoreSoundPlayed] [Set to 0]
[Constant TLSSP_RESET = 0.05]
This variable will be used as a timer for playing the score sound, since the player will be collecting a lot
of gems consecutively.
[TLSSP folder]
[TimerLastScoreSoundPlayer > 0 ?] => TimerLastScoreSoundPlayer -= dt
[Gems Sound = 1 condition & TimerLSSound <= 0] => [Play scoresound -17db;TimerLSSP = TLSSP_RESET]
[Hit player function]
[Play sound Get Hit at volume -7db]
[End events]
[Start] => [Stop all] ; [If sound = 1 => Play end sound at -10db]
[Trophy sound -7db]
[Back button Play bgm]
-Preloader layout preload sounds
-Copy bg, import: Loading-360, 360; BarBack/Front: 250, 372
[Var TimerPreloader = 1.5] [Everytick countdown
Bar width = 222/100*((1.5/TimerPreloader) / (1.5 / 100)) ]
-----Test game---This concludes Lecture 10 of this Course.

29

Ending:
We learned how to create a full featured casual game which is suitable for commercial use. The game
works on both desktop and mobile devices.
Throughout this tutorial we covered assets, objects, variables, logic, loops, game mechanics, functions,
mathematical calculations and a lot more.
I hope that this Course has helped you in learning Construct 2 game development. Practice your skills
and make great games!
Thank you for watching.

30