Advertisement
  1. Game Development
  2. Game Design
Gamedevelopment

Obscuring and Revealing Scenes with AS3

Difficulty:IntermediateLength:LongLanguages:

One of the simplest game mechanics is to let the player find a hidden object. Games based on this take many forms: Where's Waldo, Peek-A-Boo, Spot the Difference, Hide and Seek, and of course Hidden Object. In this Premium tutorial, I'll show you two methods for obscuring a scene so that the player can uncover it later.


Final Result Preview

In the first SWF, click like mad to pop all the balloons. Okay, there's not a lot of challenge, but imagine doing it against the clock, or with more balloons appearing all the time.

In the second SWF, wipe away the dirt by swiping your mouse over the image. This mechanic was used in Window Washy, one of the first games for the PS2 EyeToy -- not to mention in countless scratchcards!


Section 1: Popping Balloons


Step 1: Draw a Balloon

We need to create the balloons before we can burst them. I'll use Flash Pro CS3 to do this; if you don't have Flash Pro, you can either draw your own using whatever method you normally use, or use the SWC from the download package and skim all of the steps in this tutorial explaining how to draw. I'll include instructions for users of other editors where relevant.

Open Flash Pro and create a new Flash File (ActionScript 3.0). I'm going to base the design of my balloons on this Illustrator tutorial from Vectortuts+ -- but using Flash's tools, obviously.

Select the Pencil tool and put it in Smooth mode, with a 1px black stroke. I've used the default Smoothing value of 50.


Now, draw a rough balloon shape. Don't worry about getting it perfect; we'll adjust it in a second. Here's mine:


Hmm. See those sharp corners? Smooth them out. Use the Selection tool to select that section of the line, then click the Smooth button a few times.


I'm sure there's a better way that the professionals use, but that usually does the trick for me. Tweak the balloon's shape however you like -- remember, you can click and drag any point on the line to stretch it out.

Here's what I've ended up with:


Now add the knot. As Jesse says in the aforementioned Vectortuts+ tutorial, "it's just a simple circle with a round cornered triangle-like shape below."


Okay, now fill the balloon with a pleasant pastel colour (I've picked #dae8b3, which is again from the Vectortuts+ tutorial) and delete all of the lines.


Not bad! If you want to add a shine, use the line tool, with a thicker stroke width (I've used 3px) and a white colour, to draw a straight line across a "corner", then use the Selection tool to curve it.


Select this shine line, then click Modify | Shape | Convert Lines to Fills -- this way, if you resize the balloon, the shine will stay the same size proportional to the rest of the balloon.


Step 2: Convert the Balloon to a Symbol

In order to interact with a balloon using ActionScript, we need to convert it to a symbol. Select your art, then click Modify | Convert to Symbol. Make it a movie clip symbol called Balloon, and export it for ActionScript using the same class name.


Ignore the warning about there not being a class with the same name, if it comes up after you click OK.

You can find a FLA and SWC of the assets used so far in the BalloonsStep2 folder of the source download.


Step 3: Add a Background

Pick a backdrop for your to float in front of. I've picked this wallpaper (credit LGLab and envato) and cropped it slightly:


If you're using Flash Professional, add a new layer to the stage and import your image. Otherwise, embed the graphic and add it to the bottom of the display list using whatever method you prefer. You may wish to resize your stage in order to fit the image, as I've done.


Next we're going to make this lone balloon disappear when it's clicked.


Step 4: Create a Blank Document Class

Time for some code!

Create a class, called Main.as, in the same directory as your FLA, and link it to the FLA as the document class -- see here for details. (If you're not using Flash Pro, then I'll assume you know how to do the equivalent in your editor; you must have already created a main class in order to get the background on stage.)


Step 5: Hook the Balloon Instance Up

We need to access the balloon from the document class, and so must give it a class name.

If you're using Flash Professional, select the balloon on the stage, and type theBalloon into the box in the Properties panel. Then, click File | Publish Settings, open the Flash tab, click Settings... next to the ActionScript version drop-down box, and uncheck the "Automatically declare stage instances" box. (This isn't strictly necessary, but allows the code to be the same regardless of whether you're using Flash Pro or some other editor.)

Then, modify your document class like so:

If you're using another editor, add an instance of the Balloon class to the display list at any coordinates you like (as long as it's in front of the background), giving it an instance name of theBalloon.


Step 6: Make the Balloon Disappear When Clicked

We'll use a MouseEvent listener to detect when the balloon is clicked, and a handler function to remove it:

Simple stuff. Test it out:

Nothing mind-blowing, but at least it works.


Step 7: Using Multiple Balloons

Not much challenge in this, is there? Drag a few more balloons to the stage, on the same layer as the original:


How are we going to access these in code? I guess we could give them all instance names like greenBalloon1, greenBalloon2, and so on, and add a MouseEvent listener to each... ugh. We're coding, we can automate this.

The document class is a MovieClip, which means it's a DisplayObjectContainer (hooray for inheritance), which means it has a getChildAt() function and a numChildren property, which means we can use a for loop to iterate through all the objects on stage. I'll prove it. Modify your Main() contsructor function like so:

(You can leave the code for removing the original balloon in.) Run the SWF and check your Output panel:

The code is returning the type of each child of Main -- that is, each object in the display list, from bottom (getChildAt(0)) to top (getChildAt(10)). Because I didn't export the background image for ActionScript, all Flash knows is that it's some sort of Shape.

We need to add the onClickBalloon() listener to each one of the balloons, but not to the background. Fortunately there's a keyword that lets us check the class of an object: is. We can use it like so:

(Note that I've removed the line that specifically adds the event listener to the theBalloon instance.)

Test the SWF:

Hmm. Not quite right, is it?


Step 8: Targeting the Right Balloon

No matter which balloon you click, the original balloon is removed. The cause of this is easy to spot:

In line 16, we're adding the event listener to each balloon; however, in lines 23 and 24, we're specifically removing the theBalloon instance. In the event handler function, we need to remove whichever balloon was clicked on, instead. This is called the event target, and can be accessed via the a_event.target property. So, you'd expect this to work:

...but it doesn't; we get an error:

See, Flash doesn't know what class of object the event target is, so it doesn't know for sure that it can be removeChild()-ed or that it can have any event listeners attached. We need to tell Flash to treat the event target as an instance of the Balloon class, like so:

Try it out now:

Great! That's a decent milestone; you can find all the files created so far in the BalloonsStep8 folder in the source download.

Challenge: Try counting how many balloons there when the SWF first loads, counting how many are removed as they are clicked, and displaying some congratulatory text or playing a victory sound when all the balloons are gone.


Step 9: Make the Balloons Burst

Next, let's make the balloons pop with a little animation when they're clicked.

I wasn't sure how to animate this, so I looked at a slow-mo video of a real balloon being burst:

Unfortunately, this just looks fake to me (I know), so I tried something else.

Edit your balloon, and add a new frame to the timeline. In this frame, draw a big spiky mess with the pencil tool:


Delete the shine line (fill it with the balloon colour), and draw a few lines from the spiky mess out to the edge of the balloon:


Click each section, turn it into a Group (CTRL-G), separate it from the others slightly, and delete the lines:


Create a new keyframe, and tweak the separate bits by using the Free Transform Tool and by stretching some of the edges of the fills. I've turned on Onion Skinning here so that you can see how my sections compare to their positions in the frame before:


I've found it helps to keep the balloon's pieces within within the same area the balloon occupied before, but you can experiment with this. Next, create another keyframe and make all the segments even smaller:


I've made the segments drop a bit here, as if due to gravity. Now add a new keyframe, totally empty. Test out your animation (you may wish to adjust the frame rate of your movie; I went for 24fps).

Awesome. Of course, if you run your SWF now, all the balloons will keep popping over and over again:

...so open the Actions panel in the first frame of the Balloon's timeline and add this code:

The balloon's animation is included in the SWC and FLA inside the BalloonsStep9 folder of the source download.


Step 10: Making the Balloons Burst when Clicked

To make a balloon pop only when it's clicked, we just have to make the animation play():

...er, except that won't work, because the balloon will instantly be removed from the display list, won't it? Just comment out the removeChild() line for now and make sure the SWF works:

Oh, right, we need to stop() the animation once it's done. Open the blank keyframe in the balloon's timeline and add this:

Actually, while we're here, we could solve our removeChild() problem. If we make the balloon dispatch a COMPLETE event when its bursting animation has finished, we could listen for this event in Main.as, and remove the balloon from the display list once we hear it. Add this line to the blank keyframe's actions:

(This is all in the BalloonsStep10 SWC and FLA, don't worry.) Now, in Main.as, modify your onClickBalloon() handler function:

...create an onBalloonBurst() handler function, which will be run once the animation has finished:

...and import the Event class:

Test it out:

Looking good so far.

Challenge: How about animating the balloons so that they bob about a bit before you click them?


Step 11: Add a "Pop" Sound Effect

I found a perfect sound effect for this on AudioJungle: Balloon Pop. I can't include it in the source download, but you can buy it for just a dollar.

If you want, buy this effect, or find another online, and make it play when a balloon is popped. To do this, first add it to your Library and export it for ActionScript (or embed it in your project, for non Flash Pro users), with a class name of PopSWF.

Then, in Main.as, create a private instance of the sound:

...and play it when needed:

Try it out:


Step 12: Add Another Color of Balloon

Let's fill up the screen with multiple colors of balloons. Duplicate the Balloon symbol in the Library, and call it BlueBalloon, with a Class of BlueBalloon. Keep it identical to the original balloon, but with a blue fill (I've used #c1e6ee, again from that Vectortuts+ tutorial).

Drag a few instances onto the stage. Remember you can remove some of the green balloons, and you can resize any of the balloons if you like:


If you test the SWF, the blue balloons don't do anything yet:


Step 13: Make the Blue Balloons Do Something

The blue balloons aren't doing anything because all our code is written to deal with the Balloon class, and not the BlueBalloon class. We could duplicate all our code to deal with different colors of balloon, but that's messy, and would be a pain to change later on if we wanted to.

Instead, let's make the blue balloon and the green balloon use the same class, using the power of inheritance. Select your original Balloon symbol in the Library and rename it to GreenBalloon; change the Class to GreenBalloon as well.

Our aim is to give both balloons a Base Class of Balloon; this will mean that each green balloon is seen as an instance of Balloon as well as of GreenBalloon, and each blue balloon is seen as an instance of Balloon as well as BlueBalloon -- our code, which is written with the Balloon class in mind, will all work fine.

Unfortunately, although we can set the Class of a symbol to the name of a class that does not exist, we cannot do the same with the Base Class. We must create a class file that the two balloons can inherit.

Create a new class file, Balloon.as, in the same directory as your FLA, and enter this code:

That's all you need. It must extend MovieClip because both of the balloons use animations; if we extended, say, Sprite instead, then the two balloon symbols could not use a timeline, and would be static images.

Set the Base Class of each of the balloon symbols in the Library to Balloon, and run the SWF:

Great! It'll now be easy to add any other color of balloon. Just to prove it, let's add red and yellow ones.


Step 14: Even More Balloons

This is an easy step. Duplicate the green balloon symbol twice more, and recolor one pastel red (#f2daea), with a Name and Class of RedBalloon, and the other pastel yellow (#f6f5b4), with a Name and Class of YellowBalloon. In each case, set the Base Class to Balloon. Add lots of each to the stage.


Run the SWF; the new balloons should work without any problems.

If any color refuses to pop, make sure the symbol's Base Class is set to Balloon.


Step 15: Set the Hand Cursor

We're conditioned to think that Flash objects are only clickable if the mouse cursor turns into a hand when we hover over them. To make this hand appear, we just have to set the balloon's buttonMode property to true.

The easiest place to do this is in the for loop where we add the CLICK event listener to each balloon. However, all Flash knows about the balloons at this stage is that they are instances of DisplayObject, since that's what getChildAt() returns -- but buttonMode is a property of the Sprite class. This means we need to use the as keyword again. We could write:

...and then import the flash.display.Sprite class, but for the sake of simplicity I'm going to use the Balloon class instead:

Run the SWF:

Challenge: To keep with the theme of popping balloons, you could change the mouse cursor to a needle or a pin. For help, take a look at this Quick Tip on doing so by making a movie clip follow the mouse, or this one on changing the operating system's native cursor.

Congratulations, you've finished this section of the tutorial! If you've followed all the challenges so far, you should be well on your way to a neat little minigame.


Section 2: Cleaning Windows


Step 1: Set Up a New AS3 Document

Let's rush through this. If you're using Flash Pro:

  1. Create a new FLA (ActionScript 3)
  2. Save it as WindowCleaning.fla, in a different directory to Balloons.fla
  3. Create a new AS file
  4. Save it as Main.as, in the same directory as WindowCleaning.fla
  5. Set Main.as as the document class of WindowCleaning.fla

If you're using a different editor, just create a new AS3 project using whatever method you normally would. Call the project WindowCleaning and the main class Main.as, to make this tutorial easier to follow.

In either case, your Main class should look something like this:

Some versions of Flash and some editors may generate some slightly different code for this class; that's fine, just go with its defaults. If your editor doesn't auto-generate any code, copy mine from above.


Step 2: Create a "Dirt" Sprite

To start with, we're going to create a solid rectangle of color and clean that up; we'll move on to more complicated images later.

In your Main class, create a new Sprite to contain this "dirty" rectangle:

Next, use the Sprite's graphic property to create a rectangle of color the size of the stage. You could hard-code the values in, if you like (my FLA is 500x400px), or set the values dynamically as I've done here:

This won't be visible unless we pick a fill color, though. I've chosen #440000, a deep red.

Oh, we need to add the dirt Sprite to the display list:

Run your SWF. If you don't see a solid color, then perhaps your FLA is not hooked up to your document class correctly.


Step 3: White-Out Some Dirt with the Mouse

In Carlos Yanez's tutorial, Create a Basic Drawing Application with Flash, he showed us how to create the appearance that colors on a canvas had been erased by the mouse cursor, simply by drawing a thick white line that follows the mouse. We'll use the same trick here.

First, we must create a MouseEvent listener to track the mouse as it moves, and a handler function for when it does:

Next, we need to draw a line from the mouse's previous position to its current position:

Don't forget the lineStyle() call; the first line is the thickness of the line (in pixels); the second defines its color (#ffffff is white).

Try it out:

Wow, that's... an interesting effect, but not what we were going for! The problem here is that lineTo() draws a line from the dirt graphic object's current drawing position to whichever point you specify (the mouse's coordinates, in this case). However, we're not moving the current drawing position, so it's staying at (0, 0), the top-left corner of the stage. We need the drawing position to follow the mouse around, too; we can do this with the moveTo() method:

Try the SWF now:

Pretty good, except that the initial point is set to (0, 0), meaning that the first line drawn will always jump from the top left corner. Additionally, if you move your mouse out of the SWF at one spot and into the SWF at another, the line jumps again.

To solve both problems, we should:

  • Set the initial drawing position to the mouse's location when the SWF first loads,
  • Reset the current drawing position to the mouse's location whenever the mouse leaves and then re-enters the SWF, and
  • Only draw a line following the mouse's movements if it's inside the SWF.

Here's the code for that. If you don't entirely follow the logic, then try commenting out certain lines or adding your own in to see how it changes the final effect.

Run your SWF:

Pretty good! It's not perfect, but it demonstrates what we want to do well enough.


Step 4: Add a Background

Our eventual aim is to erase a foreground to reveal a background. At the minute, we appear to be erasing a red foreground to reveal a white background; now let's add a more interesting backgound.

I've chosen this image of the Envato office's front door from Flickr (credit to envato), trimmed to fit my FLA:


If you're using Flash Pro, create a new movie clip symbol, drag your chosen image into it (or create your own using the drawing tools), and export the symbol for ActionScript with a Class name of Background. If you're using another editor, embed it into your project (also with the name Background) using your usual method. I've included this image in WindowWashing.swc inside the source download.

Instead of dragging it onto the stage, use code to add it to the display list below the dirt:

So now the background is below the dirt, but can we see it?


Er, no.


Step 5: Check the Background is There

The easiest way to check that the background is actually there is to reduce the alpha of the foreground so that it is semi-transparent:

As you can see from the SWF below, the background's there:

This SWF also makes it obvious why we're not seeing the background shine through (in case you hadn't worked it out already): we're drawing white lines on top of the red, not removing the red lines altogether. Ideally, we'd make the darker areas of the dirt opaque, while the white areas were transparent. This is possible, using blend modes.


Step 6: Apply a Blend Mode

If you haven't used blend modes before, check out this introduction by Trent Sterling. Briefly, a blend mode defines how two images blend together when one is laid on top of the other.

the blend mode we'll apply is called DARKEN. Think of it this way: for each pixel, Flash compares the color of that pixel from the two images, and displays whichever is the darkest (i.e., whichever is furthest away from pure white). Here's what it looks like if we lay the red dirt on top of the Envato sign and apply the blend mode:


Compare it with the original sign image:


The dark blues and greens in the sign are counted as being darker than the deep red of the dirt, and so show through. The graininess of the image leads to the interesting speckled effect on the blended image.

How do we write the code for this? It's simple, actually:

Two new lines, that's all. Try it out -- run the mouse over the SWF below:

Great! If you don't want the background to show through at all, then you just have to make sure that the foreground is darker -- so either pick a background with lighter colors, or use a darker color for the dirt.


Step 7: Blend Modes Aren't Perfect

There are two main restrictions with this blend mode solution:

  • First, we have to be careful with what colors and images we pick, as explained in the previous step
  • Second, it's quite processor-intensive for Flash to figure out how the images should blend.

Take a look at your SWF again; unless your computer is a lot better than mine, it'll run a lot slower than the SWF where we were just drawing white lines.

An even better solution than blending the two images together would be to make the undesired pixels from the foreground image transparent (or even remove them from the foreground image altogether). And whenever you need to manipulate individual pixels, that means it's time to use a Bitmap.


Step 8: Create a Bitmap Foreground

Instead of using a Sprite for our foreground, we can use a Bitmap; the difference is, a Bitmap stores its image as a grid of pixels, rather than as a collection of lines and fills.

These pixels are stored in an instance of another class of object: BitmapData. We create a BitmapData that contains the image we want to use, and then hook it up to a Bitmap which displays it.

So, first we need to create a BitmapData object containing the pixels of our desired foreground. Here's the code for that:

(I'm referring to this as "grime" to keep it separate in my mind from the "dirt" we made earlier.)

In line 19, we create a new BitmapData containing a solid rectangle of color; the first argument is the width of the rectangle, the second is the height, the third is whether we should be able to change the transparency of the individual pixels, and the fourth is the color to use (I've picked a dark brown).

Now we must hook this up to a Bitmap:

Nothing complicated there; just note that in line 22 we pass the BitmapData object to the Bitmap, in order to connect the two.

Bitmap extends DisplayObject, and so can be added to the display list -- we'll have to do this if we want to see it:

(I've commented out the line adding the dirt Sprite to the display list, to keep things simple.)

Try it out:


Oh. What?


Step 9: Transparency Trickery

The issue is with the color that we set the foreground image to be. Up till now, it's been fine to specify a color in 0xRRGGBB format, with RR representing how much red is in the color, and GG and BB representing green and blue respectively. However, when creating the BitmapData, we said that we should be allowed to modify the transparency of individual pixels. This means that we need to specify colors in 0xAARRGGBB format, where AA represents how opaque the color is.

The highest value we can set for this is ff, so modify the line where we create the BitmapData like so:

Try the SWF again:


That's more like it.


Step 10: Manipulating a Specific Pixel

Now we can see the Bitmap, it's time to go about hiding it again, pixel by pixel.

We can modify the color and transparency of a single pixel inside a BitmapData by using the setPixel32() method. (There's also a setPixel() method that allows us to modify color but not transparency.) It works like so:

In line 24 we're setting the pixel at (100, 100) to be completely transparent (and, technically, black -- but you can't see that, because it's transparent). Notes that we're actually changing the pixel itself, rather than drawing a new pixel on top of the old one. Run the SWF now, and see if you can notice the difference:


You can just about see that the underlying image is peeking through! But we're gonna need a bigger brush...


Step 11: Manipulating a Clump of Pixels

There is a setPixels() method that you may assume would do what we're looking for, but it's not actually suitable for our goals. The simplest way to manipulate a range of pixels at once is just to use a loop:

We're just looping through all the pixels in a rectangle from (95, 95) to (104, 104) and making them all transparent. Here's the result:


Challenge: Try erasing a different shape or size of "clump", while still changing the pixels one-by-one. Can you make a circle of pixels disappear?


Step 12: Following the Mouse

To make clumps invisible based on the mouse's position, we can write code that's much simpler than the mouse code we wrote earlier, as we're only removing clumps from specific points, rather than drawing lines from point to point. This means we don't have to worry about the mouse leaving the SWF, so we should be able to reduce our entire class to this:

However, if you test the SWF, it won't work. This is because even though Bitmap extends DisplayObject, it does not extend InteractiveObject, which is the class containing the code needed to monitor mouse movements.

All is not lost, though; we can simply put the Bitmap inside a Sprite -- which does extend InteractiveObject -- and add the MouseEvent listeners to that Sprite!

The code to do so looks like this -- pay careful attention to the addChild() and addEventListener() calls:

Take a look at the resulting SWF:

It's not quite as smooth as the line-drawing version, because your mouse moves faster than Flash can detect, leaving gaps in between the clumps. This effect can be reduced with bigger clumps, however.

Challenge: Try storing the current position of the cursor at the end of the onMouseMoveOverGrime() function, and at the start of that function, turn all the pixels transparent that lie in the line between the mouse's current position and the last position stored.


Step 13: Create a Different Foreground Image

We're not restricted to a solid color foreground. Since every image on a computer screen is made up of pixels, every image can be drawn into a BitmapData and displayed as a Bitmap.

Create a new image to use as the foreground. If you're using Flash Pro, you could use the drawing tools to make one, or import an image into your library and drag it into an empty movie clip. If you're using another editor, use whatever method you usually use. Either way, just make sure you have an object that's exported for ActionScript with a class name of Foreground.

This is mine; it's an image I made by fiddling about with the Difference Clouds filter in Photoshop:


(It's in WindowCleaning.swc, yes.)


Step 14: Use the Foreground Image

To draw this foreground image into grimeBitmapData, we just pass an instance of it to the BitmapData's draw() method:

The draw() method takes a snapshot of the object passed to it, breaks it down into pixels, and draws those pixels on top of whatever is currently in the BitmapData. This means that if your image is smaller than the stage you'll see some brown round the edges (since the BitmapData was filled with brown when created). I drew mine to fit exactly, though, and here's the result:


Step 15: Actually Remove Some Pixels

At the moment, when the mouse passes over the Bitmap, all we're doing is turning the nearby pixels transparent. We can, instead, remove the pixels from the BitmapData altogether; it's not strictly necessary, but it's neater.

We can do this by using the draw() method -- but we specify that instead of just drawing new pixels on top of old ones, we want to use a blend mode called ERASE.

Remember how the DARKEN blend mode compared all of the pixels of two images, and displayed the darker one each time? Well, ERASE compares the pixels of two images, and erases each pixel of one image wherever the corresponding pixel of the other image is not transparent. ("The other image" being whichever image has the blend mode applied to it.)

Let's test this out. Create yet another image, this time with a class name of Brush. You'll want this to be smaller than the main image -- maybe 20x20px. Don't bother with coloring it in, as it's only going to be used as a cookie cutter to remove shapes from the foreground image. Make sure the registration point is at the top-left corner. Here's mine:


The image on the left is zoomed in; the right is at actual size. The eyes and mouth are not white; they're cut out of the circle.

To erase the brush image from the foreground, we must create an instance of it, and then draw it into the foreground's BitmapData using the DARKEN blend mode, like so:

(The fourth argument of draw() specifies the blend mode. Don't worry about the second and third arguments for now; their default values are null, so I've left them at that.)

Take a look at the result:


Since the background image is almost a uniform color in the top-left corner, it looks as though we've just drawn a solid-colored smiley face on top of the foreground. You'll have to trust me that this isn't the case ;) The pixels have actually been removed from the foreground's bitmap.


Step 16: Move That Brush

Hold on, though -- the draw() method doesn't have any parameters to specify x- and y-coordinates! How are we going to make the brush follow the mouse?

Actually, the second parameter of the draw() method can be used to alter coordinates. It takes a Matrix, which can hold data about the scale, rotation, skew, and location of an object.

This means we can use a Matrix to package up a bunch of information about how we'd like the brush to be drawn, and pass it to the draw() function. Here's how we do that:

(You'll need to import flash.geom.Matrix, as well.)

This creates what's called an identity matrix -- a Matrix that doesn't specify any changes to be made -- and passes it to the draw() function. Since the identity matrix doesn't specify any changes, the result you'll get upon running this SWF will be exactly the same as you got before.

We want the Matrix to tell the draw() command to move the brush to a different location. In mathematics, a movement like this is called a translation; the method of the Matrix we need to use takes this name:

We've told it to translate -- that is, move -- the brush image 100 pixels to the right and 100 pixels down. Check it out:


Great! We're ready to make this move.

Challenge: Read up on the Matrix class and experiment with the other types of modifications you can make, like changing the size of the brush on the fly.


Step 17: Make the Brush Follow the Mouse

We can pretty much move the code we just wrote from the Main() function to the onMouseMoveOverGrime() handler function, and have it work. We need to make the new coordinates match the mouse, of course, and remove the old code for making pixels transparent. Have a go yourself; it should end up looking like this:

Try it out:

Wonderful. Just a little cleaning up to do now.


Step 18: Clean It Up

Three things bug me about this:

  1. The brush has "holes" in it -- good for demonstrating how draw() works, but silly now.
  2. We create a new instance of Brush and Matrix every time the mouse moves.
  3. The brush isn't centered on the mouse cursor.

Each is easy to fix.

For the brush, just edit your image and fill in the holes. (I'm going to double the size of mine, while I'm there.)

To correct the wasteful creation of new instances, just create the objects as properties of the Main class:

However, there's a problem with this: translate()tells the Matrix to move the drawing position relative to its current location. We need to give it absolute values. This can be done by setting the tx and ty properties:

Finally: to center the brush on the cursor, just translate it a few pixels to the left of the cursor (by half the brush's width), and a few pixels above it, too:

The end result:

Fantastic!

Challenge: Just as with the balloons, try changing the mouse cursor to something more fitting. You could use a soapy rag, if you want to stick with the window cleaning theme, or perhaps a coin, if you wanted to create a scratchcard effect.


Summary

Now you've learned two methods for letting the player reveal a hidden scene. Your real challenge now is to build on these basic mechanics, and turn these simple toys into fun games!

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.