Advertisement
  1. Game Development
  2. Game Design
Gamedevelopment

Test Your Observation Skills With an AS3 Difference Game

by
Difficulty:IntermediateLength:LongLanguages:

During this tutorial we create the core gameplay of a difference game. This includes all the main functionality and two levels to play around with. After this we will also add a main menu and an ending screen.

To summarize, we will be using two images: one with a clean background and one with all the differences. We create markers that determine the position and dimension of each difference and use BitmapData operations to copy this on the screen. Randomization will keep the gameplay interesting and increase replayability.


Step 1: Entrance Point to the Game

The entrance point of a game is the so called document class. In case your coding program of preference is Flash CS3, check out the article Quick Tip: How to Use a Document Class in Flash on how to set up the document class in detail. In case you're using FlashDevelop, create a new project and choose "AS3 Project".

In the source files you can find both the FlashDevelop project in the root folder (Difference game tutorial.as3proj) and a Flash CS3 .fla file (flashcs3game.fla) in the src folder.

The class Main (Main.as) will be our starting point and it looks like this:

The shown code is very basic and comes as a standard when creating a FlashDevelop project. The highlighted code is extra code that is added. We would like a quick way to access Stage. Stage is an object that holds numbers from the flash application like screen width and screen height and so forth. To make it easily accessible we make it a public static variable. To access stage in anywhere in the game we need to type Main.STAGE.


Step 2: Creating the Game Class

The Game class is what holds the game mechanics and is usually created after clicking on the "start game" button on the main menu. Since we don't have a main menu yet it will be created on load. Only one instance of Game can exist at a time and in this tutorial the Game class and all components that rely on it are placed in its own folder: "game".

Upon load of Game we would like three things to happen:

  • Add initial graphics
  • Add the gameloop
  • Set the level number to 1 and tell it to start

We will start by adding initial graphics. The other two steps will follow later on in this tutorial.

Game Class: Construct the Body

You can see the Game class in its smallest form. The function Game() is the constructor function. Inside this function we can place any code we would like to run directly after creating the class.

To add the initial graphics we are first building two containers to hold them: a top and a bottom layer. Splitting the graphics provides an easy way to keep the graphics seperated. This is useful when controlling the overlap of multiple graphics. For a difference game you could imagine that the level with the two screens and differences goes to the bottom layer, and that a counter saying how many differences are left and a mouse cursor goes to the top layer. To keep things organized, we place the necessary code in the function InitGraphics.

Game Class: Instantiation of the Class in Main

To instantiate the Game class and add it to the display list of Main we place the following code in the init function of Main:

Doing this will first initialize all the variables specified in Game and then call its constructor function.


Step 3: Adding and Exporting Graphics

We would like to add the graphics of our first level to the library of the Flash Authoring Tool, in this case Flash CS3 Professional. The engine we are going to make in this tutorial requires one image without any differences and one image with all the differences included. From the image with differences we will later copy the parts of that image that contain differences and place them over the normal image. Because only the differences are copied and the rest is untouched, you might as well remove the rest of the image to save some filespace (see the image below).


First we create two symbols that hold the graphics. Use Insert > New Symbol and create two symbols: gfx_level1 and gfx_leveldifference1. Also export these as shown below. For reasons explained in the next step it is important that all symbols used for level graphics are named correctly. We use the base class Sprite because the container will not need a timeline for animation. Inside these containers you could draw up the levels with vector graphics, or import some bitmap graphics and place them there.



Step 4: Creating the Level Class

Next up we are creating a primitive form of the Level class. The Level is what holds the two images that make up both sides of the screen. Here all the differences are added randomly distributed over both sides of the screen and are made clickable. An action like guessing a difference will cause a visual change in the Level class and a change in information in the Game class: the difference piece will fade out and the differences left counter reduces by one.

For now we will focus on adding code to the class constructor of Level. A parameter given to the Level class is _levelNumber. We save this value in the class locally.

Next we are obtaining the image data from the library through the command getDefinitionByName. Now it will become clear why it was important to give the symbols the correct export name. By using getDefinitionByName we can get the reference to a Class object and having this reference allows us to create a new instance of this class. As shown in last step we've used Sprite for our level graphics containers so new classRef as Sprite is necessary to create our Sprite object.

The function GetBitmapData turns your Sprite, which is given as a parameter, into a BitmapData object. First a clean bitmap is created that has the dimensions of Sprite. All pixels in it are the colour 0x00000000 which means they have alpha: 0, red:0, green:0, red:0, in other words a black invisible pixel. Using draw the Sprite is drawn on top of the bitmapdata. The BitmapData object gets returned.

So why would we want to have BitmapData and not just leave it as a Sprite? First off, the concept of copying one part of a picture to another is the most efficient way when using bitmapdata. With the function copyPixels to be precise, which is a very fast operation.
Secondly a bitmap is faster for the computer to draw than a vector image. Fading in an image will take more processing power when the image is a complex vector image than when it is a bitmap. Bitmap won't care how detailed the picture is.
And if you're worried about looks: it looks exactly the same provided that the user has not zoomed into the screen.

For reference, here is the full sourcecode of Level so far:


Step 5: Adding the startLevel Function to the Game Class

With this basic form of the Level class ready we can create a way to Level to be instantiated in Game. Instantiation of level will produce the two-sided screen graphics and user interaction. When a level is done, that instance will be removed, and a new instance will be created. The difference is in the parameter for level number which is increased by one.

The startLevel function in Game:

We also liked to start the level right away, by putting some code in the constructor of Game. Let's do this now.


Step 6: Producing two Clean Backgrounds

Moving on to expanding the constructor of the Level class. A typical look of a difference game is the two-sided screen. In our case we have two clean identical backgrounds with differences laid over them. To produce the two identical clean backgrounds we are going to create one Bitmap instance called mainBitmap and copy the image data of the clean image (imageClean) to it twice, at two different positions.

The following pieces of code are added to the constructor of the Level class:

Let's break down what happens. In the first line we create a new Bitmap instance which will function as a container for the two clean images. A new BitmapData instance is made with the appropiate size, namely the size of the screen. We obtain the size of the screen through Main.STAGE.stageWidth and Main.STAGE.stageHeight which are static variables defined in Main, as discussed earlier.

Next up is the operation copyPixels. copyPixels is a function that belongs to the bitmapData class of Flash and can be used to copy bitmapdata from another instance to their own. In this case bitmapdata from imageClean (the source bitmapdata), supplied through the first parameter, is being copied to mainBitmapData (the target bitmapdata) The next parameter is a Rectangle object, which is used to determine exactly what part of the source bitmapdata will be copied. We would like to copy everything that is in imageClean, so the Rectangle is made to have the same dimensions as imageClean. The third parameter is a Point object which says where in the target bitmapdata the source bitmapdata will be copied to. This is the property that we would like to be different between the two copyPixel operations. We shift the x-location with BG_WIDTH+1 to the right. BG_WIDTH is the size of the clean image, and +1 just serves as a separator line.

Finally we add the bitmapData from mainBitmapData to mainBitmap and add the bitmap to the display list.

The current result thus far in an illustration:



Step 7: Using Markers for Dimensions and Placement

We are leaving the Level class for a second to talk about creating so called "difference markers". Each difference on the screen needs to have a certain position and a certain size, and we would like an efficient way to define these. One possible way of doing this is by manually looking up the x and y positions and the width and height of each difference and store them somewhere in an array. This can however get time-consuming and is kind of boring to do. A more elegant way is by placing markers over the difference image indicating where the differences will come. Those markers will be scanned through code and the position and dimensions will be extracted.

Let's set up the difference markers. We are creating two types, a circle and a square:


Export the two types of markers according to the image below. Why exporting as RoundDifference and SquareDifference is important in this case will be handled later.



Step 8: Placing the Difference Markers

We will need to create a container that will hold the difference markers. Because we need a guideline, the clean image will be included in the container. Drag the clean image from the CS3 library to the stage, right-mouse click on it, hit Convert to symbol and export it with name "differences level 1" and linkage class "differences_level1" and base class flash.display.Sprite. Inside the container, add a new layer that will holds the difference markers. Drag the round or square differences and position and scale them as you see fit.

The image below shows the result:



Step 9: Scanning the Difference Markers

Once again we return to the constructor of the Level class to add some more code to it. We would like to scan the container holding the difference markers for all difference marker objects and store those in an array called differenceMarkerList.

Add the following code to the constructor of Level:

Here, much like a few steps before, we obtain a Sprite object using getDefinitionByName. The object is then saved into variable differencesData. This is the whole container holding all the differences markers and a clear image.

Having obtained this data we can now search through it for objects that interest us. Also add the following code:

First we look how many children the container has in its display list and store this value in variable i. We then loop through all those children in search for a difference marker. The reason why we exported them earlier now becomes clear. By exporting a marker to let's say RoundDifference, it now belongs to the RoundDifference class. When you drag those markers to the container, all those objects are an instance of RoundDifference. Because of this, they also have the datatype RoundDifference, which we can use as an identifier of a certain type of object. N.B. it will not only have the datatype RoundDifference, but all the datatypes it inherits from MovieClip too.

Inside the while loop we first obtain the data of a child in differencesData. We do a datatype check to see if it either belongs to RoundDifference of SquareDifference. If yes, then add it to the array differenceMarkerList. Now we have got an array through which we can easily access the data of each difference and the clear image also put in the container is not included (because it's datatype did not belong to either RoundDifference or SquareDifference).


Step 10: Introduction to Difference Pieces

Because everything needs a name, we will call the differences visible on the screen "difference pieces". They are small objects that hold the graphics coming from the image with the differences, variable imageDifferences. Also they hold a hit field used for mouse interaction, the user must be able to click on them to activate a difference. These difference pieces must be added in pairs so they appear both on the left and right side of the screen. Each object must know who its linked partner is so they can communicate with each other. From these pairs only one of them must initially be visible. When clicking on either one of the pair, it will activate itself and also it's linked partner, to become visible.

The positioning of the difference pieces must happen according to the data set in the previously added difference markers. We will look what the position and dimensions of the difference marker is and using that information we extract a rectangular block of graphics from imageDifferences. Also the hit field placed inside a difference piece must match the form of the difference marker, so RoundDifference will generate a round hit field and SquareDifference a square hitfield.

With the introduction of the Piece class the following final class structure for this tutorial (which is very straightforward) is obtained. A Piece instance is located in
Level,
a Level instance in Game, and so forth.


The following illustration shows how the difference piece comes together:



Step 11: Creating the Piece Class

Every single difference piece will be created using the Piece class. In this class the graphics and the hit field reside. Input parameters for the Piece class are the difference marker object (Sprite), the image with differences i.e. imageDifferences (BitmapData), and whether or not the piece is triggered on creation (Boolean).

Piece Class: Adding the Class Skeleton

First we create the basic class form and save the third parameter.


Piece Class: Creating Hit Fields

We would like to create a hit field based on the form of the difference marker. So we've either got a square or a round and the dimensions are the same as the difference marker.

So first we create an empty Sprite that will hold the hit field:

Then a data type check is done to see if the difference marker supplied as a parameter is equal to RoundDifference. If yes, use the Flash graphics drawing function drawEllipse to draw a round shape. As you can see, the width and height of the difference marker as passed to it as well.

Same thing as the round hit field, but now for a square:

Finally we add the hit field to the display list, so it will become part of the clickable region. When we later put a MouseEvent listener onto a Piece object, this is the field that will respond to mouse clicks. We of course don't actually want to see the hit field, so the alpha is put as zero. You might think hitField.visible = false would work as well, but doing that will prevent hitField from becoming part of the clickable region.

Piece Class: Graphics

Each Piece object has a small rectangular bitmap containing some bitmapdata from imageDifferences. This is what we will be adding in this step.

Create a empty Bitmap that will hold the graphics:

Create a new BitmapData object with the same dimensions as the difference marker. We will be performing a copyPixels operation so we will need a Rectangle and a Point object as discussed before. It's position on the target bitmap is simply (0,0). The rectangle will need to be set so it covers a small rectangular area on imageDifferences. First set the top-left position with _dif.x and _dif.y then set the width and height of the piece of data you want.

Perform the copy pixels operation and set the bitmapData of difBitmap to difBitmapData.

Now that boolean parameter comes into action. If _bTriggered is indeed true, then immediately upon loading the screen the difference will be visible. Remember that one of the Piece objects in the pair needs to be shown already.


Step 12: Creating Piece Objects as Pairs

As said before we need to add those Piece objects as pairs to the screen. Let's make a function that does that. This function will need to be called each time a new pair is added to the screen. For example an image with 5 differences in it will need 5 pairs.

Create the function CreateDifferenceCouple inside the class Level. The parameter ob (int) is a number saying which difference marker must be used. In step 9 we scanned for difference markers and put those in array differenceMarkerList. We now retrieve the difference marker again using parameter ob as an index. The second parameter is side (String) and will be either value "left" or "right".

Next up we create two Piece objects. All of the following codes in this step must be added to the function we just created, CreateDifferenceCouple. Data is the difference marker we created in the code above, imageDifferences is the bitmapdata of the image with differences. Remember that the Piece class' third parameter is _bTriggered which is a Boolean value. If this boolean is true then the Piece object is shown directly upon creation. Using code side=="left" and side=="right" will generate boolean values. Only one of these can true at once, so it is a good way to tell the Piece class if it should be pre-shown or not.

Add MouseEvent listeners to both Piece objects. This will only respond to the hit field added inside each Piece object. The function Trigger it calls will be handled later. You might notice false, 0, true which if you look into the Flash docs means that weakReference is true. This is to assist garbage collection; I'm not going to go into detail about the reasons for this (see Daniel Sidhion's Quick Tip for a great introduction to garbage collection), but I put weakReference as true in a lot of cases to avoid memory leaks.

Add the two Piece objects to the display list of Level.

Position the two Piece objects. The x positioning works much the same way as in step 6 when we added clean backgrounds. The y position is the same on both sides of the screen.

Finally add the Piece objects to pieceArray so they can be accessed later.


Step 13: Linking the Piece Objects Together as a Pair

To link pieces together we need to store a reference of one another in each of the two Piece objects. Create the function SetPartner inside the Piece class with as parameter _partner (Piece). partner is then stored locally.

Next in the function CreateDifferenceCouple call the newly created functions in the Piece class and add each others references.

This illustration shows how the differences pieces are positioned and paired:



Step 14: Adding Piece Pairs in a Random Fashion

In this step we are going to add Piece pairs to the screen by calling the CreateDifferenceCouple function for each defined difference marker. We can put some randomization to the process by manipulating the side (String) parameter, which detemines which Piece will be pre-triggered. Either the left side or the right side is triggered. We will be using Math.Random() for it's random value, but have to be careful though: you don't want all differences pre-triggered on one side of the screen but instead evenly spread out. So we would need to perform an extra check to keep the balance.

We would like to add the placement of Piece pairs to happen right away when the level starts, so add the following code to the bottom of the constructor of Level:

Like in step 9 we loop through each difference marker. In this case we only need it's index value, though. Variables leftnum and rightnum track how many difference have been added to either screen and the variable distribution says how many differences would ideally be placed on the left screen. In the first if-statement we create a 50% chance that a difference is triggered on the left side given that the amount of differences on the left side does not exceed distribution. Then we check if the amount of differences on the right side doesn't exceed distribution, and else we add it to the left side.


Step 15: Trigger

Remember that we added a MouseEvent listeners to both of the Piece objects in a pair, that call Trigger when clicked. Add the following code to the Level class:

So what happens here, is we first get a reference to the Piece object that is just clicked. That is obtained through e.target.parent. The parent of hit field is the Piece object we want. Remove the event listener attached to it and call it's Activate function, which doesn't exist yet and we will create next step. The reference to the partner of the clicked Piece object is obtained through the function GetPartner() of piece. Also the partner has its event listener removed and is activated.


Step 16: Activating a Piece Object

When a Piece object is activated we would like it to fade in gently. Add the following code to the Piece class:

In case the Piece object is not just visible, add the difBitmap to the display list. We make the alpha 0 so that it can fade from alpha 0 to alpha 1. In this case we are using the Tweener library but any other tweening library for as3 could fit here.


Step 17: Making a Bridge Between the Level and the Game Class

Whenever the uses clicks on a difference piece, the pair is activated, and the amount of differences that still has to be found is decreased by one. Let's call the variable that holds this value amountOfDifferencesLeft. We will be creating a differences remaining counter in a later step that makes use of this variable to show the right number. The idea is that game statistics like the current level you are in and amountOfDifferencesLeft are placed inside the Game class. These should be seperated from the Level class, as the Level class will just provide graphics and user interaction.

So we need to make a "bridge" between Level and Game to let the system know the amount of differences has decreased by one. Add the following code to the Game class.

To let the Level class be able to call this function, we must pass the reference to this function as a parameter to the Level class upon instantiation. A reference to a function is simply it's name stored inside a variable: var someFunctionReference:Function = SubtractDifferencesLeft. Now the function can be activated by using someFunctionReference(parameters...).

The code inside the function StartLevel inside Game now changes by the addition to an extra parameter to Level:

And the new code inside Level to accomodate for the added parameter. We save the reference to the SubtractDifferencesLeft function for later use.

Now to make the actual call, we add the following code to the Trigger function inside the Level class.


Step 18: Checking if the Level is Completed

As you may have foreseen, when the amount of differences left is equal to zero, the level is complete. This check will have to be done inside the function we just created called SubtractDifferencesLeft.

The function SubtractDifferencesLeft with added code:


Step 18: Level Completion Graphics Notification

Very important is the verification to the player that the level is won through some graphics effect. In this tutorial is chosen to make the difference pieces blink when the level is won.

The following action is added to SubtractDifferencesLeft. We will be calling a new function inside the Level class called WinLevel.

This function WinLevel is a public function, which is required to be accessed from Game.

Here we see the code needed to blink all the differences pieces. We make use of a Timer with interval 750 ms that runs 4 times. It is important to let it run an even amount of times so it is visibile after the timer has stopped.

In the event listener applied to the timer we set an anonymous function that simply loop through all the pieces in pieceArray and sets it's visibility to the opposite of what it currently is. Finally we start the timer.


Step 19: Adding a Pause and Moving to the Next Level

Internally we must change the currentLevel variable and increase it with 1. There must be a pause between the transition so the level does not immediately switch after winning.

Add the highlighted code the function SubtractDifferencesLeft of the Game class.

As you can see we've added the if-statement to see if it doesn't increase the value NUMBER_OF_LEVELS. This is done for the purposes of the tutorial: there are only 2 levels. What can be added here for the full game is some function called WinGame after completing all the levels. The new NextLevel function that is inside the Game class looks like this:

So the first one is obvious, currentLevelNumber is increased by one. This value is always used as a parameter when creating a new Level instance. The second part is the delay. EasyTimer is a function supplied with the tutorial code package, inside the map utils, that has time in seconds as first parameter and a function reference as a second parameter. It is not important to know how this works internally. In this case it is a 5 second delay after which StartLevel is called.


Step 20: Smooth Transition Between Levels

We'd like to create a smooth transition between levels by fading out the current level into the new level. For this we will be using Tweener.

The StartLevel function of the Game class is expanded with the following code, added on top of the function:

Before a level is created, the variable currentLevel will produce null. If there is already a level and a new level is started through a call to StartLevel then the if-statement produces true. We create the variable oldLevel that will hold the reference temporarily. Then we add some Tweener code and let it fade out to alpha=0 in a timespan of 5 seconds. On complete function is called that removes the child from the display list. This is important, because although invisible it is still there and taking RAM. It's last reference was being held in the display list and by removing that reference through removeChild we make it eligible for garbage collection.


Step 21: Blend Mode

As the level fades we can see a problem: the difference pieces become visible as rectangles. The figure below demonstrates this problem.


What we need to do is apply BlendMode.LAYER to the level that is fading out. Add the following line of code (highlighted):


Step 22: Creating a Custom Mouse Cursor

Characteristic to a difference game is that instead of the normal mouse cursor, a double ring cursor is used. This allows the player to match up differences on both sides of the screen.

Custom Mouse Cursor: Creating the Graphics

Create a red ring and export it as a Graphic type. Then create a movieclip, name it "cursor" and export it as gfx_mouseCursor. Inside it paste two red rings. The middle of the movieclip must be between the two rings and is the position where the mouse is locked on to. The distance from the circles to the middle is equal to the the width of the background image (plus the one pixel that serves as divider).


Custom Mouse Cursor: The Code to Make it Work

In step 2 we had added code to show the mouse pointer. Let's bring that back up again.

When the Game class is loaded, it adds the two layers. To the top layer it adds the mouse cursor. The variable g_mouseCursor is created as follows:

So now the graphics are added and it still needs a way to move. It is time to create our gameloop. Inside the constructor of Game, add the following code:

Next up is the creation of a gameloop. A gameloop is a single loop in the game that runs all the time if the game is active and handles the changes of any components linked to it. Think about moving, creating or destroying entities. Anything that needs some update according to time or some event. The gameloop is present in the Game class and is called through an Event.ENTER_FRAME listener. Although the gameloop in a difference game doesn't play a particulary big role, you can imagine that in a game with a lot of moving enemies over the screen it would.

The Update function is called once a frame. For our game, Update is a very simple function:

So as you might guess, it just positions the cursor the same as the mouse position at each new frame.


Step 23: Creating the Difference Counter

One thing that is left to add in the game UI is the difference counter that shows how many differences are remaining.

Difference Counter: Graphics

Add a couple of keyframes and in those keyframes add numbers starting from 0. A layer of code is added with a simple stop() in it. This approach allows you to create any graphics you want for the numbers and doesn't limit you to using a textfield.


Difference Counter: Code

Just like the mouse cursor, we add the difference counter to InitGraphics:

And define g_differencesCounter as:

On loading the level the amount of differences must be counted as extracted from Level. Create a function in Level that returns the amount of differences. Then in startLevel set the variable currentDifferencesLeft to this number.

Whenever a difference is found the counter should update. SubtractDifferencesFound is the function that is called when the user finds a difference, so there it must be added.

We move the differences counter to the desired keyframe.


Intermezzo: Working Demo

So after a lot of coding, we are finally ready to see a working demo of the difference game. On each difference a hand cursor is added by the use of buttonMode = true to make it easier to spot the differences. Notice that when using tab you see yellow-tab boxes appear. This is caused by the buttonMode setting. Because buttonMode will be false anyway in the final version (because the hand cursor shouldn't be visible) this will not pose a problem.


Step 24: The Main Menu

The main menu in this tutorial will have an entrance page with background, title and buttons. Next to this are an instruction page and a credits page. Also for some eye-candy we've added alpha-smoothing between each page. Let's start by adding graphics.

Main Menu: Graphics

The chosen way to build up our main menu is this: we have an object called "main menu background" (exported as gfx_mainmenu_background) which holds just the background graphics. Then buttons and text are overlaid. Some pages contain the game title in it (credits) and some don't (instructions). All buttons are simply exported in Flash as buttons and given identifier names like butStart, butInstructions, butCredits. In the credits page and the instructions page is the same return button with identifier butReturn.

The following illustration demonstrates.


Main Menu: Initialization Code

We will be expanding Main.as to show the main menu instead of directly starting the game.

To get the code organized we the code up into two functions, InitGraphics and InitListeners. We create some instances of the screens shown above and also create g_menu which will serve as a container. In InitGraphics we add the graphics when starting up the game, so that starts with the main screen. We will always keep g_mainmenu_background visible and swap other graphics on top of it.

Main Menu: Toggle the Visiblilty of the Main Menu

Thanks to our container named g_menu we have a quick way to turn on or off everything that belongs to the menu. The if-statements check if the graphics are really there to eliminate any possible errors.

Main Menu: Adding Life to the Buttons

As you noticed we added listeners to all the buttons in InitListeners. Those linked to the function ButtonAction.

In ButtonAction we check for the instance name of the button that is clicked and do a specific command. I much prefer this method because it simplifies a lot of things. Like in this case not having to write a function for each button. So butStart will start the game through StartGame, a function we have yet to make. It also hides the main menu.

Main Menu: Switching Pages

The SwitchPage function will fade out the current page that is visibile and fade in the page that is given as a parameter.

The first section was added to remove errors that occurred when rapidly fading through pages. New references are set and the current page becomes the previous page and the page in the parameter the current page. Then we fade out the old page using Tweener and also block the mouse interaction, and when it's done we remove it from the display list. The new page is faded in from alpha 0. It is activated for mouse interaction just in case it was blocked before.

Main Menu: Starting the Game

Remember the code in Main.as we initially made to start the game right away? That is now wrapped in a function.


Step 24: A Game Ending

So what is a game without a proper ending? For this tutorial we add an animation after winning the second level letting the player know he/she has won and at the end the screen becomes clickable and can take you back to the main menu.

Game Ending: The Win Game Condition

Remember the function SubtractDifferencesLeft in Game.as? In here we check if the amount of differences left is zero, and if yes, win the game. Also we take it to the next level if the current level is lower than the amount of levels we've got (2). Now the else-statement is added that the user must get the win animation after beating all levels.

Game Ending: Animation

Here is a screenshot of the end-game animation.


At the last frame of the end game animation we've added code that dispatches an Event, telling the Game class that is it done animating and can activate the full-screen button.

Game Ending: Showing an Animation and Activating the Button

Add the following code to Game.as:

First we instantiate the end game animation and prevent it from running. The animation is added to the display list, and we use Tweener to fade it in. There is a delay set of 5 seconds so you can see the difference pieces of level 2 blink before moving on. On completion of the fade in we remove the current level from the display list and tell the animation to run.

Next we add a mouse listener and display it for mouse interaction. We check the animation for the event "DONE" (code in the last frame of the animation dispatches that event) and upon receiving we enable the mouse interaction of the animation.

Game Ending: Resetting the Game

The final step is to make the code that is called when the button on the end-game animation is clicked. This resides in the function ReturnToMenu of Game.as and links back to Main.as through an event dispatch. Let's look at ReturnToMenu.

This dispatches the custom event "GAME_OVER". To catch it, we must put an eventListener on the instance of the Game class. Let's add this listener to the StartGame function of Main.as.

When the event is caught, the function ResetGame is called, that removed the Game instance from the display list and also sets its value to null so it can be garbage collected. Also we remove its eventListener just in case. After all this we can show the main menu again.


Conclusion

So there we have it! I hope you have enjoyed this tutorial and were able to pick up some programming tricks to help you create your own solutions.

This game could still be expanded a lot. Think about hints, particle effects, points and penalties. Although the artwork is the main attraction of a difference game, some extra effects and options can make the game better, and having organized code helps you adding that without too much hassle. Development time can be cut down by choosing a proper way to create levels. Imagine that instead of the current solution, we chose to export each and every difference and turn in into a fading out animation. For 15 levels with 10 differences each that would have needed 150 manually created animations. Very time consuming!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.