(For more resources related to this topic, see here.)
In order to realize these goals, in this article, we'll be doing the following:
- Displaying a countdown timer on the screen
- Configuring fonts
- Creating a game attribute to count lives
- Using graphics to display information
- Counting collected actors
- Keeping track of the levels
Prior to continuing with the development of our game, let's take a little time out to review what we have achieved so far, and also to consider some of the features that our game will need before it can be published.
A review of our progress
The gameplay mechanics are now complete; we have a controllable character in the form of a monkey, and we have some platforms for the monkey to jump on and traverse the scene.
We have also introduced some enemy actors, the croc and the snake, and we have Aztec statues falling from the sky to create obstacles for the monkey. Finally, we have the fruit, all of which must be collected by the monkey in order to successfully complete the level.
With regards to the scoring elements of the game, we're currently keeping track of a countdown timer (displayed in the debug console), which causes the scene to completely restart when the monkey runs out of time. When the monkey collides with an enemy actor, the scene is not reloaded, but the monkey is sent back to its starting point in the scene, and the timer continues to countdown.
Planning ahead – what else does our game need?
With the gameplay mechanics working, we need to consider what our players will expect to happen when they have completed the task of collecting all the fruits. As mentioned in the introduction to this article, our plan is to create additional, more difficult levels for the player to complete!
We also need to consider what will happen when the game is over; either when the player has succeeded in collecting all the fruits, or when the player has failed to collect the fruits in the allocated time. The solution that we'll be implementing in this game is to display a message to advise the player of their success or failure, and to provide options for the player to either return to the main menu, or if the task was completed successfully, continue to the next level within the game.
We need to implement a structure so that the game can keep track of information, such as how many lives the player has left and which level of the game is currently being played.
Let's put some information on the screen so that our players can keep track of the countdown timer.
Displaying a countdown timer on the screen
We created a new scene behavior called Score Management, which contains the Decrement Countdown event, shown as follows:
Currently, as we can see in the previous screenshot, this event decrements the Countdown attribute by a value of 1, every second.
We also have a debug print instruction that displays the current value of Countdown in the debug console to help us, as game developers, keep track of the countdown. However, players of the game cannot see the debug console, so we need to provide an alternative means of displaying the amount of time that the player has to complete the level.
Let's see how we can display that information on the screen for players of our game.
Time for action – displaying the countdown timer on the screen
- Ensure that the Score Management scene behavior is visible: click on the Dashboard tab, select Scene Behaviors, and double-click on the Score Management icon in the main panel.
- Click + Add Event | Basics | When Drawing.
- Double-click on the title of the new Drawing event, and rename it to Display Countdown.
- Click on the Drawing section button in the instruction block palette.
- Drag a draw text anything at (x: 0 y: 0) block into the orange when drawing event block in the main panel.
- Enter the number 10 into the x: textbox and also enter 10 into the y: textbox.
- Click on the drop-down arrow in the textbox after draw text and select Text | Basics. Then click on the text & text block.
- In the first textbox in green, … & … block, enter the text COUNTDOWN: (all uppercase, followed by a colon).
- In the second textbox, after the & symbol, click on the drop-down arrow and select Basics, then click on the anything as text block.
- Click on the drop-down arrow in the … as text block, and select Number | Attributes | Countdown.
- Ensure that the new Display Countdown event looks like the following screenshot:
- Test the game.
What just happened?
When the game is played, we can now see in the upper-left corner of the screen, a countdown timer that represents the value of the Countdown attribute as it is decremented each second.
First, we created a new Drawing event, which we renamed to Display Countdown, and then we added a draw text anything at (x: 0 y: 0) block, which is used to display the specified text in the required location on the screen.
We set both the x: and y: coordinates for displaying the drawn text to 10 pixels, that is, 10 pixels from the left-hand side of the screen, and 10 pixels from the top of the screen.
The next task was to add some text blocks that enabled us to display an appropriate message along with the value of the Countdown attribute. The text & text block enables us to concatenate, or join together, two separate pieces of text. The Countdown attribute is a number, so we used the anything as text block to convert the value of the Countdown attribute to text to ensure that it will be displayed correctly when the game is being played.
In practice, we could have just located the Countdown attribute block in the Attributes section of the palette, and then dragged it straight into the text & text block. However, it is best practice to correctly convert attributes to the appropriate type, as required by the instruction block. In our case, the number attribute is being converted to text because it is being used in the text concatenation instruction block. If we needed to use a text value in a calculation, we would convert it to a number using an anything as number block.
We can see, when testing the game, that the font we have used is not very interesting; it's a basic font that doesn't really suit the style of the game!
Stencyl allows us to specify our own fonts, so our next step is to import a font to use in our game.
Time for action – specifying a font for use in our game
Before proceeding with the following steps, we need to locate the fonts-of-afrika\Afritubu.TTF file.
Place the file in a location where it can easily be located, and continue with the following steps:
- In the Dashboard tab, click on Fonts.
- In the main panel, click on the box containing the words This game contains no Fonts. Click here to create one.
- In the Name textbox of the Create New… dialog box, type HUD Font and click on the Create button.
- In the left-hand panel, click on the Choose… button next to the Font selector.
- Locate the file Afritubu.TTF and double-click on it to open it.
- Note that the main panel shows a sample of the new font.
- In the left-hand panel, change the Size option to 25.
- Important: save the game!
- Return to the Display Countdown event in the Score Management scene behavior.
- In the instruction block palette, click on the Drawing section button and then the Styles category button.
- Drag the set current font to Font block above the draw text block in the when drawing event.
- Click on the Font option in the set current font to Font block, and select Choose Font from the pop-up menu.
- Double-click on the HUD Font icon in the Choose a Font… dialog box.
- Test the game. Observe the countdown timer at the upper-left corner of the game.
What just happened?
We can see that the countdown timer is now being displayed using the new font that we have imported into Stencyl, as shown in the following screenshot:
The first step was to create a new blank font in the Stencyl dashboard and to give it a name (we chose HUD Font), and then we imported the font file from a folder on our hard disk.
Once we had imported the font file, we could see a sample of the font in the main panel. We then increased the size of the font using the Size option in the left-hand panel. That's all we needed to do in order to import and configure a new font in Stencyl! However, before progressing, we saved the game to ensure that the newly imported font will be available for the next steps.
With our new font ready to use, we needed to apply it to our countdown text in the Display Countdown behavior. So, we opened up the behavior and inserted the set current font to Font style block. The final step was to specify which font we wanted to use, by clicking on the Font option in the font style block, and choosing the new font, HUD Font, which we configured in the earlier steps.
Heads-Up Display (HUD) is often used in games to describe either text or graphics that is overlaid on the main game graphics to provide the player with useful information.
Using font files in Stencyl
Stencyl can use any TrueType font that we have available on our hard disk (files with the extension TTF); many thousands of fonts are available to download from the Internet free of charge, so it's usually possible to find a font that suits the style of any game that we might be developing. Fonts are often subject to copyright, so be careful to read any licensing agreements that are provided with the font file, and only download font files from reliable sources.
Have a go hero
When we imported the font into Stencyl, we specified a new font size of 25, but it is a straightforward process to modify further aspects of the font style, such as the color and other effects.
Click on the HUD Font tab to view the font settings (or reopen the Font Editor from the Dashboards tab) and experiment with the font size, color, and other effects to find an appropriate style for the game. Take this opportunity to learn more about the different effects that are available, referring to Stencyl's online help if required.
Remember to test the game to ensure that any changes are effective and the text is not difficult to read!
Creating a game attribute to count lives
Currently, our game never ends. As soon as the countdown reaches zero, the scene is restarted, or when the monkey collides with an enemy actor, the monkey is repositioned at the starting point in the scene. There is no way for our players to lose the game! In some genres of game, the player will never be completely eliminated; effectively, the same game is played forever. But in a platform game such as ours, the player typically will have a limited number of chances or lives to complete the required task.
In order to resolve our problem of having a never-ending game, we need to keep track of the number of lives available to our player. So let's start to implement that feature right now by creating a game attribute called Lives!
Time for action – creating a Lives game attribute
- Click on the Settings icon on the Stencyl toolbar at the top of the screen.
- In the left-hand panel of the Game Settings dialog box, click on the Attributes option.
- Click on the green Create New button.
- In the Name textbox, type Lives.
- In the Category textbox, change the word Default to Scoring.
- In the Type section, ensure that the currently selected option is Number.
- Change Initial Value to 3.
- Click on OK to confirm the configuration.
- We'll leave the Game Settings dialog box open, so that we can take a closer look.
What just happened?
We have created a new game attribute called Lives. If we look at the rightmost panel of the Game Settings dialog box that we left open on the screen, we can see that we have created a new heading entitled SCORING, and underneath the heading, there is a label icon entitled Lives, as shown in the following screenshot:
The Lives item is a new game attribute that can store a number. The category name of SCORING that we created is not used within the game. We can't access it with the instruction blocks; it is there purely as a memory aid for the game developer when working with game attributes. When many game attributes are used in a game, it can become difficult to remember exactly what they are for, so being able to place them under specific headings can be helpful.
Using game attributes
The attributes we have used so far, such as the Countdown attribute that we created in the Score Management behavior, lose their values as soon as a different scene is loaded, or when the current scene is reloaded. Some game developers may refer to these attributes as local called Lives, so let's attributes, because they belong to the behavior in which they were created. Losing its value is fine when the attribute is just being used within the current scene; for example, we don't need to keep track of the countdown timer outside of the Jungle scene, because the countdown is reset each time the scene is loaded.
However, sometimes we need to keep track of values across several scenes within a game, and this is when game attributes become very useful.
Game attributes work in a very similar manner to local attributes. They store values that can be accessed and modified, but the main difference is that game attributes keep their values even when a different scene is loaded. Currently, the issue of losing attribute values when a scene is reloaded is not important to us, because our game only has one scene. However, when our players succeed in collecting all the fruits, we want the next level to be started without resetting the number of lives. So we need the number of lives to be remembered when the next scene is loaded.
We've created a game attribute called Lives, so let's put it to good use.
Time for action – decrementing the number of lives
- If the Game Settings dialog box is still open, click on OK to close it.
- Open the Manage Player Collisions actor behavior.
- Click on the Collides with Enemies event in the left-hand panel.
- Click on the Attributes section button in the palette.
- Click on the Game Attributes category button.
- Locate the purple set Lives to 0 block under the Number Setters subcategory and drag it into the orange when event so that it appears above the red trigger event RestartLevel in behavior Health for Self block.
- Click on the drop-down arrow in the set Lives to … block and select 0 - 0 in the Math section.
- In the left textbox of the … - … block, click on the drop-down arrow and select Game Attributes | Lives.
- In the right-hand textbox, enter the digit 1.
- Locate the print anything block in the Flow section of the palette, under the Debug category, and drag it below the set Lives to Lives – 1 block.
- In the print … block, click on the drop-down arrow and select Text | Basics | text & text.
- In the first empty textbox, type Lives remaining: (including the colon).
- Click on the drop-down arrow in the second textbox and select Basics | anything as text.
- In the … as text block, click on the drop-down arrow and select Number | Game Attributes | Lives.
- Ensure that the Collides with Enemies event looks like the following screenshot:
- Test the game; make the monkey collide with an enemy actor, such as the croc, and watch the debug console!
What just happened?
We have modified the Collides with Enemies event in the Manage Player Collisions behavior so that it decrements the number of lives by one when the monkey collides with an enemy actor, and the new value of Lives is shown in the debug console.
This was achieved by using the purple game attribute setter and getter blocks to set the value of the Lives game attribute to its current value minus one. For example, if the value of Lives is 3 when the event occurs, Lives will be set to 3 minus 1, which is 2!
The print … block was then used to display a message in the console, advising how many lives the player has remaining. We used the text & text block to join the text Lives remaining: together with the current value of the Lives game attribute. The anything as text block converts the numeric value of Lives to text to ensure that it will display correctly.
Currently, the value of the Lives attribute will continue to decrease below 0, and the monkey will always be repositioned at its starting point. So our next task is to make something happen when the value of the Lives game attribute reaches 0!
No more click-by-click steps!
From this point onwards, click-by-click steps to modify behaviors and to locate and place each instruction block will not be specified! Instead, an overview of the steps will be provided, and a screenshot of the completed event will be shown towards the end of each Time for action section.
The search facility, at the top of the instruction block palette, can be used to locate the required instruction block; simply click on the search box and type any part of the text that appears in the required block, then press the Enter key on the keyboard to display all the matching blocks in the block palette.
Time for action – detecting when Lives reaches zero
- Create a new scene called Game Over — Select the Dashboard tab, select Scenes, and then select Click here to create a new Scene. Leave all the settings at their default configuration and click on OK.
- Close the tab for the newly created scene.
- Open the Manage Player Collisions behavior and click on the Collides with Enemies event to display the event's instruction blocks.
- Insert a new if block under the existing print block.
- Modify the if block to if Lives < 0.
- Move the existing block, trigger event RestartLevel in behavior Health for Self into the if Lives > 0 block.
- Insert an otherwise block below the if Lives > 0 block.
- Insert a switch to Scene and Crossfade for 0 secs block inside the otherwise block.
- Click on the Scene option in the new block, then click on Choose Scene and select the Game Over scene.
- Change the secs textbox to 0 (zero).
- Ensure that our modified Collides with Enemies event now looks like the following screenshot:
- Test the game; make the monkey run into an enemy actor, such as the croc, three times.
What just happened?
We have modified the Collides with Enemies event so that the value of the Lives game attribute is tested after it has been decremented, and the game will switch to the Game Over scene if the number of lives remaining is less than zero.
If the value of Lives is greater than zero, the RestartLevel event in the monkey's Health behavior is triggered. However, if the value of Lives is not greater than zero, the instruction in the otherwise block will be executed, and this switches to the (currently blank) Game Over scene that we have created.
If we review all the instructions in the completed Collides with Enemies event, and write them in English, the statement will be:
When the monkey collides with an enemy, reduce the value of Lives by one and print the new value to the debug console. Then, if the value of Lives is more than zero, trigger the RestartLevel event in the monkey's Health behavior, otherwise switch to the Game Over scene.
Before continuing, we should note that the Game Over scene has been created as a temporary measure to ensure that as we are in the process of developing the game, it's immediately clear to us (the developer) that the monkey has run out of lives.
Have a go hero
- Change the Countdown attribute value to 30 — open the Jungle scene, click on the Behaviors button, then select the Score Management behavior in the left panel to see the attributes for this behavior.
The following tasks in this Have a go hero session are optional — failure to attempt them will not affect future tutorials, but it is a great opportunity to put some of our newly learned skills to practice!
In the section, Time for action – displaying the countdown timer on the screen, we learned how to display the value of the countdown timer on the screen during gameplay.
Using the skills that we have acquired in this article, try to complete the following tasks:
- Update the Score Management behavior to display the number of lives at the upper-right corner of the screen, by adding some new instruction blocks to the Display Counter event.
- Rename the Display Counter event to Display HUD.
- Remove the print Countdown block from the Decrement Countdown event also found in the Score Management behavior.
Right-click on the instruction block and review the options available in the pop-up menu!
- Remove the print Lives remaining: & Lives as text instruction block from the Collides with Enemies event in the Manage Player Collisions behavior.
Removing debug instructions
Why did we remove the debug print … blocks in the previous Have a go hero session? Originally, we added the debug blocks to assist us in monitoring the values of the Countdown attribute and Lives game attribute during the development process. Now that we have updated the game to display the required information on the screen, the debug blocks are redundant!
While it would not necessarily cause a problem to leave the debug blocks where they are, it is best practice to remove any instruction blocks that are no longer in use. Also, during development, excessive use of debug print blocks can have an impact on the performance of the game; so it's a good idea to remove them as soon as is practical.
Using graphics to display information
We are currently displaying two on-screen pieces of information for players of our game: the countdown timer and the number of lives available. However, providing too much textual information for players can be distracting for them, so we need to find an alternative method of displaying some of the information that the player needs during gameplay.
Rather than using text to advise the player how much time they have remaining to complete the level, we're going to display a timer bar on the screen.
Time for action – displaying a timer bar
- Open the Score Management scene behavior and click on the Display HUD event.
- In the when drawing event, right-click on the blue block that draws the text for the countdown timer and select Activate / Deactivate from the pop-up menu. Note that the block becomes faded.
- Locate the draw rect at (x: 0 y: 0) with (w: 0 h: 0) instruction block in the palette, and insert it at the bottom of the when drawing event.
- Click on the draw option in the newly inserted block and change it to fill.
- Set both the x: and y: textboxes to 10.
- Set the width (w:) to Countdown x 10.
- Set the height (h:) to 10.
- Ensure that the draw text … block and the fill rect at … block in the Display HUD event appear as shown in the following screenshot (the draw text LIVES: … block may look different if the earlier Have a go hero section was attempted):
- Test the game!
What just happened?
We have created a timer bar that displays the amount of time remaining for the player to collect the fruit, and the timer bar reduces in size with the countdown!
First, in the Display HUD event we deactivated, or disabled, the block that was drawing the textual countdown message, because we no longer want the text message to be displayed on the screen.
The next step was to insert a draw rect … block that was configured to create a filled rectangle at the upper-left corner of the screen and with a width equal to the value of the Countdown timer multiplied by 10. If we had not multiplied the value of the countdown by 10, the timer bar would be very small and difficult to see (try it)!
We'll be making some improvements to the timer bar later in this article.
Activating and deactivating instruction blocks
When we deactivate an instruction block, as we did in the Display HUD event, it no longer functions; it's completely ignored! However, the block remains in place, but is shown slightly faded, and if required, it can easily be reenabled by right-clicking on it and selecting the Activate / Deactivate option.
Being able to activate and deactivate instruction blocks without deleting them is a useful feature — it enables us to try out new instructions, such as our timer bar, without having to completely remove blocks that we might want to use in the future. If, for example, we decided that we didn't want to use the timer bar, we could deactivate it and reactivate the draw text … block!
Deactivated instruction blocks have no impact on the performance of a game; they are completely ignored during the game compilation process.
Have a go hero
The tasks in this Have a go hero session are optional; failure to attempt them will not affect future tutorials.
Referring to Stencyl's online help if required at www.stencyl.com/help/, try to make the following improvements to the timer bar:
- Specify a more visually appealing color for the rectangle
- Make it thicker (height) so that it is easier to see when playing the game
- Consider drawing a black border (known as a stroke) around the rectangle
- Try to make the timer bar reduce in size smoothly, rather than in big steps
Ask an independent tester for feedback about the changes and then modify the bar based on the feedback.
To view suggested modifications together with comments, review the Display HUD event in the downloadable files that accompany this article.
Counting collected actors
With the number of lives being monitored and displayed for the player, and the timer bar in place, we now need to create some instructions that will enable our game to keep track of how many of the fruit actors have been collected, and to carry out the appropriate action when there is no fruit left to collect.
Time for action – counting the fruit
- Open the Score Management scene behavior and create a new number attribute (not a game attribute) with the configuration shown in the following screenshot (in the block palette, click on Attributes, and then click on Create an Attribute…).
- Add a new when created event and rename it to Initialize Fruit Required.
- Add the required instruction blocks to the new when created event, so the Initialize Fruit Required event appears as shown in the following screenshot, carefully checking the numbers and text in each of the blocks' textboxes:
- Note that the red of group block in the set actor value … block cannot be found in the palette; it has been dragged into place from the orange for each … of group Collectibles block.
- Test the game and look for the Fruit required message in the debug console.
What just happened?
Before we can create the instructions to determine if all the fruit have been collected, we need to know how many fruit actors there are to collect. So we have created a new event that stores that information for us in a number attribute called Fruit Required and displays it in the debug console.
We have created a for each … of group Collectibles block. This very useful looping block will repeat the instructions placed inside it for each member of the specified group that can be found in the current scene. We have specified the Collectibles group, and the instruction that we have placed inside the new loop is increment Fruit Required by 1. When the loop has completed, the value of the Fruit Required attribute is displayed in the debug console using a print … block. When constructing new events, it's good practice to insert print … blocks so we can be confident that the instructions achieve the results that we are expecting. When we are happy that the results are as expected, perhaps after carrying out further testing, we can remove the debug printing from our event.
We have also introduced a new type of block that can set a value for an actor; in this case, we have set actor value Collected for … of group to false. This block ensures that each of the fruit actors has a value of Collected that is set to false each time the scene is loaded; remember that this instruction is inside the for each … loopso it is being carried out for every Collectible group member in the current scene.
Where did the actor's Collected value come from? Well, we just invented it! The set actor value … block allows us to create an arbitrary value for an actor at any time. We can also retrieve that value at any time with a corresponding get actor value … block, and we'll be doing just that when we check to see if a fruit actor has been collected in the next section, Time for action – detecting when all the fruit are collected.
Translating our instructions into English, results in the following statement:
For each actor in the Collectibles group, that can be found in this scene, add the value 1 to the Fruit Required attribute and also set the actor's Collected value to false. Finally, print the result in the debug console.
Note that the print … block has been placed after the for each … loop, so the message will not be printed for each fruit actor; it will appear just once, after the loop has completed!
If we wish to prove to ourselves that the loop is counting correctly, we can edit the Jungle scene and add as many fruit actors as we wish. When we test the game, we can see that the number of fruit actors in the scene is correctly displayed in the debug console. We have designed a flexible set of instructions that can be used in any scene with any number of fruit actors, and which does not require us (as the game designer) to manually configure the number of fruit actors to be collected in that scene! Once again, we have made life easier for our future selves!
Now that we have the attribute containing the number of fruit to be collected at the start of the scene, we can create the instructions that will respond when the player has successfully collected them all.
Time for action – detecting when all fruits have been collected
- Create a new scene called Level Completed, with a Background Color of yellow. Leave all the other settings at their default configuration.
- Close the tab for the newly created scene.
- Return to the Score Management scene behavior, and create a new custom event by clicking on + Add Event | Advanced | Custom Event.
- In the left-hand panel, rename the custom event to Fruit Collected.
- Add the required instruction blocks to the new Fruit Collected event, so it appears as shown in the following screenshot, again carefully checking the parameters in each of the text boxes:
- Note that there is no space in the when FruitCollected happens custom event name.
- Save the game and open the Manage Player Collisions actor behavior.
- Modify the Collides with Collectibles event so it appears as shown in the following screenshot. The changes are listed in the subsequent steps:
- A new if get actor value Collected for … of group = false block has been inserted.
- The existing blocks have been moved into the new if … block.
- A set actor value Collected for … of group to true block has been inserted above the grow … block.
- A trigger event FruitCollected in behavior Score Management for this scene block has been inserted above the do after 0.5 seconds block.
- An if … of group is alive block has been inserted into the do after 0.5 seconds block, and the existing kill … of group block has been moved inside the newly added if … block.
- Test the game; collect several pieces of fruit, but not all of them!
- Examine the contents of the debug console; it may be necessary to scroll the console horizontally to read the messages.
- Continue to test the game, but this time collect all the fruit actors.
What just happened?
We have created a new Fruit Collected event in the Score Management scene behavior, which switches to a new scene when all the fruit actors have been collected, and we have also modified the Collides with Collectibles event in the Manage Player Collisions actor behavior in order to count how many pieces of fruit remain to be collected.
When testing the game we can see that, each time a piece of fruit is collected, the new value of the Fruit Required attribute is displayed in the debug console, and when all the fruit actors have been collected, the yellow Level Completed scene is displayed.
The first step was to create a blank Level Completed scene, which will be switched to when all the fruit actors have been collected. As with the Game Over scene that we created earlier in this article, it is a temporary scene that enables us to easily determine when the task of collecting the fruit has been completed successfully for testing purposes.
We then created a new custom event called Fruit Collected in the Score Management scene behavior. This custom event waits for the FruitCollected event trigger to occur, and when that trigger is received, the Fruit Required attribute is decremented by 1 and its new value is displayed in the debug console. A test is then carried out to determine if the value of the Fruit Required attribute is equal to zero, and if it is equal to zero, the bright yellow, temporary Level Completed scene will be displayed!
Our final task was to modify the Collides with Collectibles event in the Manage Player Collisions actor behavior. We inserted an if… block to test the collectible actor's Collected value; remember that we initialized this value to false in the previous section, Time for action – counting the fruit. If the Collected value for the fruit actor is still false, then it hasn't been collected yet, and the instructions contained within the if … block will be carried out. Firstly, the fruit actor's Collected value is set to false, which ensures that this event cannot occur again for the same piece of fruit. Next, the FruitCollected custom event in the Score Management scene behavior is triggered. Following that, the do after 0.5 seconds block is executed, and the fruit actor will be killed.
We have also added an if … of group is alive check that is carried out before the collectible actor is killed. Because we are killing the actor after a delay of 0.5 seconds, it's good practice to ensure that the actor still exists before we try to kill it! In some games, it may be possible for the actor to be killed by other means during that very short 0.5 second delay, and if we try to kill an actor that does not exist, a runtime error may occur, that is, an error that happens while the game is being played. This may result in a technical error message being displayed to the player, and the game cannot continue; this is extremely frustrating for players, and they are unlikely to try to play our game again!
Preventing multiple collisions from being detected
A very common problem experienced by game designers, who are new to Stencyl, occurs when a collision between two actors is repeatedly detected. When two actors collide, all collision events that have been created with the purpose of responding to that collision will be triggered repeatedly until the collision stops occurring, that is, when the two actors are no longer touching. If, for example, we need to update the value of an attribute when a collision occurs, the attribute might be updated dozens or even hundreds of times in only a few seconds!
In our game, we want collisions between the monkey actor and any single fruit actor to cause only a single update to the Fruit Required attribute. This is why we created the actor value Collected for each fruit actor, and this value is initialized to be false, not collected, by the Initialize Fruit Required event in the Score Management scene behavior. When the Collides with Collectibles event in Manage Player Collisions actor behavior is triggered, a test is carried out to determine if the fruit actor has already been collected, and if it has been collected, no further instructions are carried out. If we did not have this test, then the FruitCollected custom event would be triggered numerous times, and therefore the Fruit Required attribute would be decremented numerous times, causing the value of the Fruit Required attribute to reach zero almost instantly; all because the monkey collided with a single fruit actor!
Using a Boolean value of True or False to carry out a test in this manner is often referred to by developers as using a flag or Boolean flag.
Note that, rather than utilizing an actor value to record whether or not a fruit actor has been collected, we could have created a new attribute and initialized and updated the attribute in the same way that we initialized and updated the actor value. However, this would have required more effort to configure, and there is no perceptible impact on performance when using actor values in this manner. Some Stencyl users never use actor values (preferring to always use attributes instead), however, this is purely a matter of preference and it is at the discretion of the game designer which method to use.
In order to demonstrate what happens when the actor value Collected is not used to determine whether or not a fruit actor has been collected, we can simply deactivate the set actor value Collected for … of group to true instruction block in the Collides with Collectibles event. After deactivating the block, run the game with the debug console open, and allow the monkey to collide with a single fruit actor. The Fruit Required attribute will instantly be decremented multiple times, causing the level to be completed after colliding with only one fruit actor!
Remember to reactivate the set actor value … block before continuing!
Keeping track of the levels
As discussed in the introduction to this article, we're going to be adding an additional level to our game, so we'll need a method for keeping track of a player's progress through the game's levels.
Time for action – adding a game attribute to record the level
- Create a new number game attribute called Level, with the configuration shown in the following screenshot:
- Save the game.
What just happened?
We have created a new game attribute called Level, which will be used to record the current level of the game.
A game attribute is being used here, because we need to access this value in other scenes within our game; local attributes have their values reset whenever a scene is loaded, whereas game attributes' values are retained regardless of whether or not a different scene has been loaded.
Fixing the never-ending game!
We've finished designing and creating the gameplay for the Monkey Run game, and the scoring behaviors are almost complete. However, there is an anomaly with the management of the Lives game attribute. The monkey correctly loses a life when it collides with an enemy actor, but currently, when the countdown expires, the monkey is simply repositioned at the start of the level, and the countdown starts again from the beginning!
If we leave the game as it is, the player will have an unlimited number of attempts to complete the level — that's not much of a challenge!
Have a go hero
- (Recommended) In the Countdown expired event, which is found in the Health actor behavior, modify the test for the countdown so that it checks for the countdown timer being exactly equal to zero, rather than the current test, which is for the Countdown attribute being less than 1. We only want the ShowAngel event to be triggered once when the countdown equals exactly zero!
- (Recommended) Update the game so that the Show Angel event manages the complete process of losing a life, that is, either when a collision occurs between the monkey and an enemy, or when the countdown timer expires. A single event should deduct a life and restart the level.
- (Optional) If we look carefully, we can see that the countdown timer bar starts to grow backwards when the player runs out of time! Update the Display HUD event in the Score Management scene behavior, so that the timer bar is only drawn when the countdown is greater than zero.
There are many different ways to implement the above modifications, so take some time and plan the recommended modifications!
Test the game thoroughly to ensure that the lives are reduced correctly and the level restarts as expected, when the monkey collides with the enemy, and when the countdown expires. It would certainly be a good idea to review the download file for this session, compare it with your own solutions, and review each event carefully, along with the accompanying comment blocks. There are some useful tips in the example file, so do take the time to have a look!
Although our game doesn't look vastly different from when we started this article, we have made some very important changes.
First, we implemented a text display to show the countdown timer, so that players of our game can see how much time they have remaining to complete the level. We also imported and configured a font and used the new font to make the countdown display more visually appealing.
We then implemented a system of tracking the number of lives that the player has left, and this was our first introduction to learning how game attributes can store information that can be carried across scenes.
The most visible change that we implemented in this article was to introduce a timer bar that reduces in size as the countdown decreases. Although very few instruction blocks were required to create the timer bar, the results are very effective, and are less distracting for the player than having to repeatedly look to the top of the screen to read a text display.
The main challenge for players of our game is to collect all the fruit actors in the allocated time, so we created an initialization event to count the number of fruit actors in the scene. Again, this event has been designed to be reusable, as it will always correctly count the fruit actors in any scene. We also implemented the instructions to test when there are no more fruit actors to be collected, so the player can be taken to the next level in the game when they have completed the challenge. A very important skill that we learned while implementing these instructions was to use actor values as Boolean flags to ensure that collisions are counted only once.
Finally, we created a new game attribute to keep track of our players' progress through the different levels in the game
Resources for Article :
- Introduction to Game Development Using Unity 3D [Article]
- 2D game development with Monkey [Article]
- Getting Started with GameSalad [Article]