© Lee Stemkoski and Evan Leider 2017

LEE STEMKOSKI and Evan Leider, Game Development with Construct 2, 10.1007/978-1-4842-2784-8_9

9. Spell Shooter

Lee Stemkoski and Evan Leider2

(1)DEPT OF MATH & CS, ADELPHI UNIVERSITY DEPT OF MATH & CS, Garden City, New York, USA

(2)NY, USA

In this chapter, you will be creating a top-down shooter game called Spell Shooter, shown in Figure 9-1, inspired by classic top-down shooters such as Gauntlet .

A434545_1_En_9_Fig1_HTML.jpg
Figure 9-1. The Spell Shooter game

Introduction

In Spell Shooter, the player controls a wizard whose goal is to use his magical powers to banish evil creatures. The wizard shoots magical balls of energy, and if a creature is hit, that creature is destroyed. After a shot is fired, there is a “recharging period ,” which is a 1-second delay until the next shot is able to be fired; this gameplay mechanic is used to motivate players to carefully line up their shots. (If there were no such limitation in place, the average player might instead simply fire shots as quickly as possible, hoping that some will hit their target.) The creatures randomly run between smokelike vortices, where they will hide for a short amount of time before running to the next. The game world is large, and the player will most likely need to move around the area to locate some of the creatures. (To reduce this difficulty, one of the optional side quests explains how to implement a creature-locating compass spell.) Once the creatures are all destroyed, the player wins the game.

The wizard has eight-direction movement, controlled by the keyboard; for the convenience of the player, either the arrow keys or the W/A/S/D keys (or the E/S/D/F keys, for an international audience) can be used. Shots are aimed using the mouse and fired by clicking a mouse button. The user interface contains a progress bar that indicates when it is possible to fire the next shot. There is also a text display that shows how many creatures are left in the area. The optional compass spell, mentioned earlier, is activated when the spacebar is pressed, and a directional indicator fades in and out around the player.

This project uses many behaviors: 8-Direction, Scroll to, Bound to layout, Bullet, Destroy outside layout, Fade, and Sine. Animations will be created from individual image files, as well as from spritesheets. Functions used include random, floor, and choose. New material includes the game mechanic of using the mouse to aim the player, creating variables for instances (as opposed to global variables), and the logic involved in making sprites navigate along a path.

To begin, download the zip file containing the graphics for this chapter from the book web site. In the layout properties, set the layout Name to Main, and set Size to 1600, 1200. As you have in previous projects, set up three layers named Background, Main, and UI. In the project properties, change the window Size to 800, 600 (and change the Name and Author properties as you like). Since the game world (layout size) is larger than the window size, it is important to stop the UI layer from scrolling off-screen (as you did in Chapter 7), and therefore you need to change the UI layer property Parallax to 0,0. In the layout area, create a TiledBackground named Background, using the image background.jpg, and position and resize the object so that it covers the entire layout area. Change its Layer property to Background. Your layout should appear as shown in Figure 9-2.

A434545_1_En_9_Fig2_HTML.jpg
Figure 9-2. The starting layout with a TiledBackground

Player Setup and Mouselook

In this section, you will set up the wizard object and the mouse-based controls for aiming. In the layout, set the active layer to Main. Create a new sprite named Wizard. In the Animation frames image editor window, right-click and select the option to import animation frames from individual files (as you did in Chapter 5). Add the image files wizard-1.png, wizard-2.png, and wizard-3.png and delete the default empty frame. Change the animation properties Speed to 8, Loop to Yes, and Ping-Pong to Yes. When you’re finished, close the image editor windows. In the layout area, change the wizard Size to 48,48, and position it in the center of the layout. Add the behavior 8-Direction and change the property Set angle to No. (This will be particularly important, as the wizard should be able to move in one direction while facing a different direction.) Also add the behaviors Scroll to and Bound to layout.

Next, you will create some events that enable the player to use the W/A/S/D keys for movement, if desired, just as you did in Chapter 5. First, add a Keyboard object to the project. In the event sheet, create a new event with the condition Keyboard - Key is Down, and set Key to W. Add the action Wizard - 8-Direction: Simulate Control, and select Up from the list. Create additional events for the remaining keys and associated controls. When you are finished, these events should appear as in Figure 9-3. Test your game to check that when you hold each of the W/A/S/D keys, the wizard moves in the corresponding direction.

A434545_1_En_9_Fig3_HTML.jpg
Figure 9-3. Events for changing the 8-Direction controls, wizard animation playback, and mouselook

As it stands, the wizard’s animation continues, even when the wizard is not moving. Next, you will create events to start and stop the wizard animation at the appropriate times. First, create a new event with the condition Wizard - 8-Direction: Is moving, and add the action Wizard - Set animation, with Animation set to "Default". Next, you need to stop the animation when the wizard is not moving. You could do this with an event that has an inverted Is moving condition, as you did in Chapter 4, but instead, you will use the newly learned Else condition, which has the same effect in this situation. Create a new event with the condition System - Else, and add the action Wizard - Animation: Stop. Since the Else event is directly below the Is moving event, this event will activate exactly when the wizard is not moving. These events are also shown in Figure 9-3.

Finally, you will implement the game mechanic that causes the wizard to face in the direction of the mouse; this is often referred to as mouselook. This control scheme is common in first-person and top-down shooter games. First, add a Mouse object to the project. In the event sheet, create a new event with the condition System - Every tick, and then add the action Wizard - Rotate toward position, setting Degrees to 10,1 setting X to Mouse.X, and setting Y to Mouse.Y. When you are finished, this event should appear as in Figure 9-3. Save and test your game to check that when you move your mouse cursor around the game’s window, the wizard rotates and faces toward the location of the mouse cursor.

Creatures and Vortices

In this section, you will add the enemy creatures that the wizard is attempting to destroy and the vortices that these creatures run between (although the actually movement won’t be implemented until the following section).

In the layout, create a new sprite named Creature. In the Animation frames window, import the frames from the sprite strip named monster.png, which has eight horizontal cells and one vertical cell. The animation frames need to be facing right to be aligned with the default angle of motion for the Bullet behavior, so the frames must be rotated to the right. To rotate all the animation frames by 90 degrees clockwise at once, hold Shift on your keyboard, and click the Rotate 90° clockwise button at the top of the Edit image window, as displayed in Figure 9-4. Each Creature frame should now be facing right. Set the animation properties Speed to 12, Loop to Yes, and Ping-pong to Yes. When you are finished, close the image editor. Add the Bullet behavior and change Speed to 300. Also, add the Fade behavior and set Active at start to No.

A434545_1_En_9_Fig4_HTML.jpg
Figure 9-4. Rotating the animation frames in the image editor

Next, create a new sprite named Vortex. These sprites will be the locations that the Creatures move toward. In the Animation frames window, import the frames from the sprite strip named smoke.png, which has six horizontal cells and five vertical cells. Set the animation properties Speed to 30 and Loop to Yes. When you are finished, close the image editor. In the layout, change the size of the Vortex object to 160,160, and add the behavior Sine to the Vortex sprite. In the Sine behavior properties, set Movement to Size, Period to 4, and Magnitude to 32. This will give the Vortex sprite a pulsing effect.

Create five additional instances each of the Creature and Vortex objects, and spread them across the layout, as shown in Figure 9-5.

A434545_1_En_9_Fig5_HTML.jpg
Figure 9-5. Creature and Vortex instances spaced around the layout

Instance Variables and Waypoint Logic

Next, you will set up the project so that the creatures randomly move between the vortices. For this to work, there needs to be a way to distinguish between the instances of the Vortex object and for each creature to keep track of which vortex it should be moving toward. Variables are an ideal way to store this information. Each instance needs to store its own related data, however, and thus global variables are not an optimal way to keep track of this information. Instead, Construct 2 allows you to create instance variables, which are variables that are associated to an object, where each instance can store and access its own values. Each instance effectively has its own copy of the variable, which it can then change at will. In what follows, you will create an instance variable for the Vortex objects named ID, which will serve as a unique identifier, and an instance variable for the Creature objects named Target, which will store the ID number of the vortex toward which it will be moving.

First, click the Vortex object in the object panel, and in the Properties panel, click the blue text Instance variables. The Vortex: Instance variables window will appear, containing space for local values to be stored, shown on the left side of Figure 9-6. Add a new instance variable by clicking the + icon. Name it ID, set Type to Number, set Initial value to 0, and set Description to Unique identification number. Click OK and return to the layout editor. Your new instance variable should appear as shown on the right side of Figure 9-6. Click the Creature object in the object panel, repeat this process to create an instance variable named Target, and set Description to ID of the Vortex to move towards.

A434545_1_En_9_Fig6_HTML.jpg
Figure 9-6. Adding a new instance variable to the Vortex object

In the layout editor, you can now set the value of the ID variables for the vortex instances (the creatures’ target values will be set with an event described in a later section). Click a single vortex in the layout, and in the Properties panel, set the value of ID to 0. Click a different vortex, and set its ID value to 1. Repeat this process for each of the vortices in the layout until they each have one of the numbers from 0 to 5, as shown in Figure 9-7 (where text has been added in the figure to show the values for each instance).

A434545_1_En_9_Fig7_HTML.jpg
Figure 9-7. Setting up the ID instance variable for the vortices

Next, you will randomly set the Target values of the creatures at the beginning of the game. You could use the System condition On start of layout, but instead you will use the creature condition On created; this activates immediately for any creatures that are present at the beginning of the game and has the added advantage that if creatures are created later, their target values will also be set by this event. Create an event with the condition Creature - On created, and add the action Creature - Instance variables: Set value. Then set Instance variable to Target and Value to floor(random(Vortex.Count)). The floor function is used to round a decimal number to the nearest integer less than the number; for example, the expression floor(3.85) yields the number 3. It is necessary to round the random number since the vortex IDs are whole numbers, but the random function results in decimal values. Rounding down is important here since the largest vortex ID number will be one less than the total number of vortices, as the vortex numbering began at zero. When finished, this event should appear as in Figure 9-8.

A434545_1_En_9_Fig8_HTML.jpg
Figure 9-8. Event to give creatures random starting targets

You will also need to create an event that rotates a creature toward its intended target vortex. You will use the Rotate towards position action, just as you did for rotating the wizard toward the mouse position. However, identifying the associated pairs of creatures and vortices is somewhat complicated and requires understanding of the Construct event “filter” system.

In general, actions are applied to the set of instances that meet the criteria specified in the condition (or conditions), and in particular, if there are no restrictions in the conditions, then all the instances will be affected at the same time. This fact was implicit and straightforward in earlier projects, but because of the complexity of this project, a more detailed discussion is in order.

At first thought, the correct condition to use for this event appears to be Creature - Compare instance variable, while checking whether Target is equal to Vortex.ID. However, this condition is insufficient. When the condition is being checked, the Construct software checks each creature instance one by one, selects the subset of creature instances (which is called filtering) whose Target variables matches the expression Vortex.ID, and then applies the corresponding action (or actions) to this subset. What is unclear is which Vortex instance’s ID is being used for each of these comparisons. To clarify and correct the logic of this condition, you will use a System condition called For each, which effectively repeats an event once for each instance of the object.

With this understanding, you are ready to proceed. Create a new event with the condition System - Loops: For Each, and select Creature. Add the condition Vortex - Compare instance variable, and check whether ID is equal to Creature.Target . Finally, add the action Creature - Rotate toward position, set Degrees to 10, set X to Vortex.X, and set Y to Vortex.Y. The event should appear as shown in Figure 9-9.

A434545_1_En_9_Fig9_HTML.jpg
Figure 9-9. Event to set the creatures to rotate toward Vortex objects

Next, you will implement a set of actions that occur when each creature reaches its intended destination. The creatures should hide (turn invisible) and stop moving for a random amount of time, select a new target vortex, and then become visible and start moving again. Create a new event with the condition Creature - On collision with another object, and select Vortex. To verify that the creature has collided with its actual target (rather than a vortex that was simply in the way), you will add a second condition called Vortex - Compare instance variable, and (as before) check whether ID is equal to Creature.Target. Next, add the following actions:

  • Add Creature - Set visible, and set Visibility to Invisible.

  • Add Creature - Bullet: Set speed, and set Speed to 0.

  • Add System - Variables: Add to. For Variable, select Target, and for Value, enter choose(1,2).

  • Add System - Wait, and set Seconds to random(1,3).2

  • Add Creature - Set visible, and set Visibility to Visible.

  • Add Creature - Bullet: Set speed, and set Speed to 300.

Note that some randomness was included when selecting the next target: by randomly choosing 1 or 2, the creature may either go to the next vortex in the sequence or go to the one after that. However, there are a limited number of possible target values; once the target value reaches the total number of vortices (Vortex.Count), the target number should “wrap around” and be reset to 0 or 1. To set this up, add a subevent with the condition Creature - Instance variables: Compare value, and check whether Target is greater than or equal to Vortex.Count. Then, add the action Creature - Instance variables: Set value, and set Target to choose(0,1). When you are finished, the events should appear as shown in Figure 9-10. Save and test your project, making sure that the enemies move randomly, as expected.

A434545_1_En_9_Fig10_HTML.jpg
Figure 9-10. The events that will cause the creatures to move and hide along a random path

Spell Shooting

In this section, you will create the spell-related game mechanics: the wizard will shoot a spell when a mouse button is clicked, and if the spell hits a creature, the creature will be destroyed. You will also implement the spell-charging delay described in the introduction of the chapter, as well as the charge progress bar and enemy count displayed in the user interface.

First, you need to add the spell object. Add a new sprite named Spell; in the Animation frames window, import animation frames from the sprite strip named swirling-yellow.png, which consists of four rows and five columns. Set the animation properties Speed to 30 and Loop to Yes. Close the image editor, and position the spell in the margins of the layout. Add the behavior Bullet, and change the bullet property Speed to 600. Also add the behavior Destroy outside layout. In the event sheet, create a new event with the condition Mouse - On click (keeping the default properties), add the action Wizard - Spawn another object, set Object to Spell, and set Layer to "Main". This event is shown in Figure 9-11.

A434545_1_En_9_Fig11_HTML.jpg
Figure 9-11. Events related to casting spells

Next, you will enable the player to destroy the creatures when they are hit by a spell. A sparklike special effect will be added as the creature fades out of existence. Add a new sprite named Spark; in the Animation frames window, add animation frames from the sprite strip named spark.png, which consists of four rows and four columns. Set the animation properties Speed to 16 and Loop to Yes. Close the image editor, position the spark in the margins of the layout, and add the behavior Fade (keeping the default properties). In the event sheet, create a new event with the condition Spell - On collision with another object, and select Creature. Also add the condition Creature - Is visible. Next, add the following actions:

  • Add Creature - Spawn another object, set Object to Spark, and set Layer to "Main".

  • Add Spell - Destroy.

  • Add Creature - Bullet: Set enabled, and choose Disabled.

  • Add Creature - Start fade.

This event is also shown in Figure 9-11. Save your project and run the layout; test that the wizard is able to shoot spells and that when they collide with a creature, a spark effect is generated, while the creature stops and fades away with the spark.

Spell Charge and User Interface

In this section, you will implement the spell-charging game mechanic and begin creating the user interface. After firing a spell, a bar graphic that indicates the amount of charge will shrink, and after it regrows to its normal size, the wizard will be able to shoot another spell.

First, add a new Text object named TextCharge to the project. Place it on the UI layer, and position it in the bottom-left corner of the game window (as indicated by the dashed lines in the layout). Since this object will be the label for the charge bar, change the default text to Charge:. To make the text easier to read, change the font to Arial, bold, size 24. By adding the drop shadow effect from previous chapters, the text will be easier to see with contrasting backgrounds. Duplicate the TextCharge object, move it a few pixels down and to the right, and then change the font color to yellow to match the Spell object and create a coordinated color scheme.

Next, add a new Sprite object named Chargeometer with the image chargeometer.png. When the chargeometer grows, it should grow from left to right. This can be accomplished by changing the width of the object, but first one modification must be made. When sprites are rotated or scaled, it is with respect to a special point called the origin; by default, this point is located at the center of the sprite. This makes sense for most situations because objects typically rotate around their center (rather than around a corner) or grow equally in all directions from the center. Since we want the sprite to grow from left to right, the origin point location must be changed. Double-click the chargeometer to open the image editor windows, and click the second icon from the bottom to open the Image Points window. Here, right-click the list entry named Origin, and in the pop-up window, click Quick assign and then Left, as shown in Figure 9-12. You should see the Origin point moved to the left of the image.

A434545_1_En_9_Fig12_HTML.jpg
Figure 9-12. Editing the Origin point location in the image points menu

When you are finished, close the image editor. Place the Chargeometer object on the UI layer, and position it in the bottom-left area of the game window, directly to the right of the TextCharge object from earlier. Your TextCharge and Chargeometer objects should appear as shown in Figure 9-13.

A434545_1_En_9_Fig13_HTML.jpg
Figure 9-13. The TextCharge and Chargeometer objects in the layout

For the chargeometer to return to its original width after being shrunk, its original size needs to be stored in a variable for later reference. Here, you can use a global variable (since there is only one instance of the chargeometer), but in theory, you could choose to use an instance variable instead. In the event sheet, right-click and add a global variable; set Name to OriginalWidth, with Initial Value set to 0. The value can be set when the game begins; create a new event with the condition System - On start of layout. Then create the action System - Variables: Set value, and set OriginalWidth to Chargeometer.Width.

Implementing the charging functionality requires a variety of additions to pre-existing events as well as the creation of entirely new events. First, to drain the charge, locate the event where the spell is spawned, and add the action Chargeometer - Set width, setting it to 0. To prevent the wizard from firing again before the charging period is finished, in the same event as before, add the condition Chargeometer - Compare width, and check whether it is equal to OriginalWidth. To continuously recharge the bar, you need to add a small fraction of its original width back during every tick. Since there is no Add width action, you can instead use the Set width action, setting the width to its current value plus a fraction of its original width. The fractional value you will use is the built-in Construct expression dt, which stands for “delta time” and stores the amount of time that passes during every tick. Typically, video games run at 60 frames per second, which means that each tick takes 1/60 of a second, and this is the value of dt. (The value of dt is automatically adjusted for games that run at slower rates.) Adding 1/60 of the width of the chargeometer back at a rate of 60 times per second means that the chargeometer will be restored to its original width in exactly one second. To set this up, locate the event with the condition Every tick, and to this event add the action Chargeometer - Set width, set to Chargeometer.Width + OriginalWidth * dt. Finally, to stop the charge bar from growing too large (larger than its original size), you need one more event. Create a new event with the condition Chargeometer - Compare width, and check whether it is greater than OriginalWidth; add the action Chargeometer - Set width, and set it to OriginalWidth. When you are finished, these events should appear as shown in Figure 9-14. Save and test your project to check that when you shoot, the chargeometer drains and recharges and that you can’t shoot again until the bar has returned to its original size.

A434545_1_En_9_Fig14_HTML.jpg
Figure 9-14. Events for draining and recharging the chargeometer

Score and Game Over

Currently, the wizard is able to shoot spells and destroy creatures. In this section, you will improve the user interface so that it keeps players aware of their progress: a Text object that displays the number of creatures remaining to destroy, and a “you win” message that appears once all the creatures have been destroyed.

First, add a new Sprite object named MessageWin with the image YouWin.png. Position it in the center of the game window, set its Layer to UI, and set Initial Visibility to Invisible. Also, add a new Text object named TextScore to the project. Set Layer to UI, and position it in the bottom-right corner of the game window. Change its default text to Creatures Remaining: 0, and change the font to Arial, bold, size 24. Set the Horizontal alignment property to Right. Duplicate the object, move it a few pixels down and to the right, and set the font color to red to match the creatures. The area of the layout corresponding to the game window (the top-left region) should appear similar to Figure 9-15.

A434545_1_En_9_Fig15_HTML.jpg
Figure 9-15. The new user interface in the layout

Next, locate the event with the condition Every tick, and add the action TextScore - Set text, set to "Creatures Remaining: " & Creature.Count. To configure the win message, create a new event with the condition System - Compare two values, set to check whether Creature.Count is equal to 0, and add the action MessageWin - Set visible. The events should appear as shown in Figure 9-16. Save and test your project; make sure that TextScore updates correctly and that your win message appears when you have destroyed all the creatures.

A434545_1_En_9_Fig16_HTML.jpg
Figure 9-16. Events for updating the score and displaying the win message

Congratulations! You have now finished implementing the core mechanics of the Spell Shooter game.

Side Quests

In this optional section, you will learn how to add a compass-like mechanic to your game to assist the player in locating creatures that are off-screen, as well as some suggested additional features to explore.

Adding a Radar

Currently, the player must move around the layout to find creatures. In this section, you will create a compass display that is pinned to the player and appears for a brief time when the player presses the spacebar. The compass image contains an arrow that will point in the direction of the nearest creature. Using this feature will simplify the game for the player, possibly reducing any feeling of frustration from the difficulty of locating the quick and randomly moving creatures.

First, add a new Sprite object named Compass with the image compass.png. Position it directly centered on the wizard, as shown in Figure 9-17. Add the behavior Fade, and change the properties Active at start to No and Destroy to No. Also add the behavior Pin.

A434545_1_En_9_Fig17_HTML.jpg
Figure 9-17. The compass object centered on the wizard

For the compass to fade in and out correctly, set its Opacity to 0, but don’t do this until after you have positioned the compass correctly (because you won’t be able to see it on the layout after you change this property). In addition, to pin the compass to the wizard, locate the event with the condition On start of layout, and add the action Compass - Pin to another object, setting Pin to to Wizard and setting Mode to Position only. Setting the mode correctly is particularly important in this case since you want the compass to be able to rotate independently from the wizard.

There is a condition you have not previously used before called Pick nearest/furthest. This condition selects a particular instance of an object based on its distance from a given point. Create a new event with the condition Creature - Size & Position: Pick nearest/furthest, set Which to nearest, and set X to Wizard.X and Y to Wizard.Y. Then add the action Compass - Rotate toward position, set Degrees to 10, set X to Creature.X, and set Y to Creature.Y.

Now that the compass rotation is configured, you are ready to create the event to display it. Keep in mind that, for the compass to work properly, it should be usable when there is at least one creature remaining. Create a new event with the condition Keyboard - On key pressed, and select the Space key. Add another condition called System - Compare two values, and set it to check whether Creature.Count is greater than 0. Add the action Compass - Set opacity to 100 and the action Compass - Start fade. The events should appear as shown in Figure 9-18.

A434545_1_En_9_Fig18_HTML.jpg
Figure 9-18. Events for rotating and displaying the compass

On Your Own

You can add plenty of other additions and features to Spell Shooter. As usual, it would be wise to add polish to this game with standard features such as menus, audio, and pause functionality. To add to the difficulty level, you could add a lose condition: the player may lose the game if the wizard gets hit by creatures a given number of times. Also, keep in mind what you learned in Chapter 8 when designing Rectangle Destroyer. You are now able to add spawnable items to any of your previous games! Such an item could be set to appear once every 10 seconds at a random position on the layout and fade out after 5 seconds have passed.

Here are some item ideas that would work well in Spell Shooter:

  • “SpeedUp” and “SpeedDown” items or obstacles that affect the wizard or creatures’ speeds as you did in the previous chapter

  • “Shrink” item that shrinks creatures, making them harder to vanquish

  • “Burst” spell item that shoots three spells at once

  • “Rapid” spell that takes less time to recharge

  • “CreatureNest” item that spawns more creatures if you touch them

You could also add a countdown timer, which adds a sense of urgency to the player’s quest to destroy all the creatures, and if the player doesn’t destroy all the creatures within the time limit, the player loses the game. With a timer in place, a ranking or rating system could be added that evaluates the player’s performance depending on how quickly the wizard vanquished the creatures.

Summary

In this chapter, you created the game Spell Shooter. You learned how to implement the mouselook game mechanic and combined it with traditional W/A/S/D-style controls to give the player the ability to shoot while moving around the screen. To create random movement patterns, you learned how to use instance variables and waypoint logic, together with the random and choose functions. To create more balanced gameplay, you implemented a rechargeable shooting mechanic. You also added a rotating compass feature to assist the player in locating difficult-to-find creatures. The “Side Quests” section discussed extra features such as a lose condition, items, a timer, and a rating system.

In the next chapter, you will leave the magical world of spells and creatures and instead shoot at enemy planes flying over the ocean as you create the game Airplane Assault.

Footnotes

1 Setting Degrees to 10 will result in a rotation rate of 600 degrees per second, provided that the program is running at 60 frames per second. To achieve more consistent performance across computers with lower frame rates, you could instead set this value to 600 * dt .

2 There is an alternative and more robust approach to queuing future actions for an object using the Timer object, which will be introduced in the next chapter.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset