We see lines used in a lot of scenarios; curves are also used but perhaps not as frequently – but that doesn’t undermine their importance! In this tutorial we shall take a closer look at...
Interested in game design? This weekend, we feature a set of four interactive lectures: games that are about game design, by Pixelate.
Play the Games
Bub and Bob, two little 8-bit guys, will talk...
Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Activetuts+. This tutorial was first published in February, 2010.
In this tutorial you’ll create a reusable Score class that counts up to the new total when points are added (instead of jumping up to the new score). We’ll cover graphics creation as well as code.
Final Result Preview
In some games when you gain points, you’ll see your score immediately jump to the new total. I think it’s much cooler if the score counts up one by one, so the player can “rack up points”. That’s what we’ll be making here.
Here’s an example of the score class in action:
The main idea behind this tutorial is to teach you how to program the “counting up” functionality, but I’ll also show you how to create the cool LED display seen in the preview. We’ll start by designing the numbers:
Step 1: Set up Your Flash File
Create a new Flash file (ActionScript 3.0). Your movie settings will vary depending on your game. For this demo I’m setting up my movie as 500×300, black background, and 30 fps.
Step 2: Create the Digit Symbol
Create a new Movie Clip symbol (Insert > New Symbol). Give this symbol the name “digit”.
Step 3: Create the Digit Text Field
Inside the digit movie clip use the Text tool to add a number 0 to the symbol. I’m using a font called Digital Readout, but any LED-style font should work.
Set the text size to 40 pt and make it a light amber/orange color (#F4C28B). Set the Paragraph Format to centered.
Step 4: Add Glows
Add two separate glow filters to your text field. Set the color to red (#FF0000) for both and set the Strength of both to 200%.
Check the Inner Glow checkbox for one and set the Blur to 2px. Leave the other at 5px Blur.
You can use a different color if you want (blue or green would both look cool). The trick in getting it to look realistic is to make the text color a little washed out and set the glows to a more saturated color. This makes it look like it’s emitting light.
Step 5: Add More Numbers
Create keyframes on frames 1-10 of the digit movie clip. An easy way to do this is to select frames 1-10 (click frame 1, then Shift-click frame 10) and press F6.
You should now have 10 frames, each with a keyframe with your glowing 0 text field. Go through each frame and change the numbers so you have the digits 0-9. Frame 1 will have “0″, frame 2 will have “1″, frame 3 will have “2″, etc.
Name this layer “numbers”.
Step 6: Add the LED Background
We’ll now add an “off” state for the LED numbers, so you’ll be able to see the unlit segments of the LED display.
Copy your 8 digit (in frame 9). Create a new layer named “background”. With the new layer selected use Paste in Place (Edit > Paste in Place) to paste the 8 digit in the exact position as the one we copied.
Remove the glows from the new 8 digit and change its color to dark grey (#333333). Add a blur filter with the Blur set to 3px. Move this layer underneath the “numbers” layer.
Now you can scrub through the frames and see how the unlit segments of the LED show behind each number.
Step 7: Add the Stop Action
Create another new layer named “actions”. Open the Actions Panel and add a stop() action on frame 1.
This will keep the display showing ’0′ until we tell it otherwise.
Step 8: Why Frames?
Why are we manually putting each digit on its own frame instead of using a dynamic text field? Good question.
The main reason is that doing so makes it more flexible for updating the graphics later. If you wanted to change the design and use bitmaps for the numbers, or have each digit displayed in a different font or color this makes it easy to do that.
Also, if designers and developers are working together on a project it’s best to create things in a way that gives designers easy access to as much of the graphics as possible.
I feel this setup does that more than using dynamic text.
Step 9: Create the Score Movie Clip
Create a new movie clip named “Score”. Check ‘Export for ActionScript’ and set the class name to “Score” also.
Drag the digit movie clip from the Library into the Score movie clip. Duplicate the digit clip (Edit > Duplicate) six times (so you have seven digits) and space them evenly.
Since we only have seven digits the maximum score we’ll be able to display is 9,999,999. If your game will need to accommodate higher scores add more digits accordingly.
Add a bit more space between every third digit to allow for comma separators.
Step 10: Name the Digit Clips
Select the leftmost digit movie clip and give it the instance name “digit1″. Name the next one to the right “digit2″, then “digit3″ and so on.
Step 11: Add Commas
Create a new layer called “commas”.
The easiest way to get the commas to look exactly like the numbers is to go into one of the digit clips and copy one of the number text fields.
Back inside the Score movie clip, paste the text field into the commas layer, and change the number to a comma. Duplicate it and move it as many times as you need.
Step 12: Add a Background
For the Score background we’ll just add a simple rounded rectangle.
Create a new layer called “background” and place it behind the numbers and commas layers. Select the Rectangle Tool and Option-click (Alt-click) the stage. Make a rectangle 200px x 40px with 3px corners (make yours longer if you have more digits). Make the fill black and the stroke 1px grey (#666666).
For some reason Flash always distorts strokes on rounded rectangles. To get around this, select the stroke and choose Modify > Shape > Convert Lines to Fills. This converts the stroke from a line to a filled shape and it will no longer distort.
If you think this is a total hack of a workaround for basic functionality that should have been fixed years ago, I urge you to contact Adobe and let them know.
Step 13: Add Shine
What graphic would be complete without some iPhone-esque shine?
Create a new layer above everything else called “shine”. Add a new rounded rectangle, slightly smaller than the background one. This time give it no stroke and fill it with a white gradient from 20% Alpha to 0% Alpha.
Step 14: Create the Score Class
Create a new Actionscript file named “Score.as”. Save it in the same directory as your main Flash file. Since the name of this class and the Export Class name of our Score movie clip are the same, Flash will automatically link them.
Add this code to the Score.as file:
package {
import flash.display.MovieClip;
import flash.events.Event;
public class Score extends MovieClip {
// CONSTRUCTOR
public function Score() {
}
}
}
This is just an empty shell of a class for now. We have to extend the MovieClip class since this class is linked to a movie clip in the library, so we also have to import the MovieClip class. We’ll be using the ENTER_FRAME event, so we import the Event class as well.
Step 15: Add Variables and Constants
Add these two lines to the Score class just above the constructor function.
private const SPEED:int = 1; // how fast to count
private const NUM_DIGITS:int = 7; // how many digits there are in the score
These are two constants – kind of like settings for the class.
The first, SPEED, controls how fast the score counts. I have it set to count one by one, but if your game uses higher scores this might be too slow. You can change this to 5 or 10 or 50 to count up by those increments.
The second constant, NUM_DIGITS, defines how many digits we have in our Score movie clip. If you added more (or less) than 7 digits you’ll need to change this.
Now let’s add a couple of variables. Put these just below the constants:
private var _totalScore:int = 0;
private var _displayScore:int= 0;
These variables will hold the two different versions of our score. “_totalScore” will be the actual score. “_displayScore” will be the number that is currently
being shown on the LED display. If I add 50 to the score, the _totalScore will immediately be 50, but the _displayScore will be 1, then 2, then 3, until it reaches 50.
If you ever need to know the actual score (like to send to your high score boards) you’ll use _totalScore since _displayScore might not be accurate.
I’m using underscores at the beginning of the variable names to denote that these are private variables.
Step 16: Add the totalScore Accessor Method
So if _totalScore is a private variable, how will we access from outside the Score class? We’ll use an “accessor” or “getter” method.
Add this method below the constructor function:
// public accessor for totalScore
public function get totalScore():int {
return _totalScore;
}
This method simply returns the value of the _totalScore variable. It gives us a way to access that value without having to expose it as a public variable.
Step 17: Add the add Method
We’ll need a way to add points to the score. Add this method:
// add an amount to the score
public function add(amount:int):void {
_totalScore += amount;
addEventListener(Event.ENTER_FRAME, updateScoreDisplay); // start the display counting up
}
This method accepts an integer “amount” which it adds to the _totalScore variable. The second line starts an ENTER_FRAME event that calls a method called updateScoreDisplay every frame. We’ll add that next.
Step 18: Add the updateScoreDisplay Method
Now add a the updateScoreDisplay method. This is where all of the cool counting-up functionality will happen. It needs to accept an Event since it’s getting called from an ENTER_FRAME event.
// this runs every frame to update the score
private function updateScoreDisplay(e:Event):void {
}
Now let’s add some functionality. The first thing this method will do is to increment the _displayScore variable by the amount we set in our SPEED constant:
// increment the display score by the speed amount
_displayScore += SPEED;
There’s a potential problem here though. What if our speed is set to 10 and we try to add 5 to the score? The displayScore will be higher than the totalScore. Let’s add a couple lines to fix that:
// make sure the display score is not higher than the actual score
if(_displayScore > _totalScore){
_displayScore = _totalScore;
}
That checks if the displayScore is higher than the totalScore and if so, sets the displayScore to be equal to the totalScore.
Next we need to add the leading zeros to the score. We’ll do this by converting the displayScore to a String and adding zeros until the length equals the number of digits defined by the NUM_DIGITS constant:
var scoreStr:String = String(_displayScore); // cast displayScore as a String
// add leading zeros
while(scoreStr.length < NUM_DIGITS){
scoreStr = "0" + scoreStr;
}
Now to actually display the score we’re going to loop through each of our digit clips (remember we named then “digit1″, “digit2″, etc.) and use the corresponding number from the score string to set the frame number of the clip:
// loop through and update each digit
for (var i:int = 0; i < NUM_DIGITS; i++) {
var num = int(scoreStr.charAt(i));
this["digit"+(i+1)].gotoAndStop(num+1);// set the digit mc to the right frame
}
The charAt method retrieves the character from a String at the specified position. This lets us go character by character through the score string.
The brackets in the next line allow us to dynamically create the clip name. The code, this["digit"+(i+1)] accesses the clip with the name “digit1″ or “digit2″, etc., depending on the value of i.
We’re using “num+1″ as the frame number because the frame numbers are offset by 1 from the digits they contain (frame 1 shows 0, frame 2 shows 1, etc.)
The last thing we need to do in this method is check to see if the displayScore and the totalScore are equal. If so, we can remove the listener and stop calling this method for now.
// if the display score is equal to the total score remove the enterframe event
if(_totalScore == _displayScore){
removeEventListener(Event.ENTER_FRAME, updateScoreDisplay);
}
If you got lost anywhere in that step you can check out the source files to see the completed class.
Step 19: The Score Class in Use
To use this class drag the Score movie clip from the Library onto the Stage and give it the instance name “myScore”. You can add points to your score by using this line in your Document Class:
myScore.add(50);
You can see an example of this in the source files. I’m adding to the score when the bumper buttons are clicked, but you’ll more likely be calling add() when events in your game occur.
If you need to know the player’s score you can get the totalScore by using:
myScore.totalScore
This will call the accessor method and return the value of _totalScore.
Conclusion
You now have a reusable counting Score class that you can use in any of your games.
I think the LED look is cool, but you should definitely alter the design to fit the look of your game. Here are a couple ideas for different designs to get you started:
Thanks for reading this tutorial. Let me know what you think!
Just because you missed that awesome presentation, there’s no need for you to miss out entirely! This weekend we feature a brand new plugin for the TweenMax and TweenLite libraries.
“ThrowProps” – tweens that flick, toss, and slide gracefully. Think, for example, of flicking a page on a touch-screen device..
ThrowPropsPlugin is a plugin for TweenLite and TweenMax that allows you to simply define an initial velocity for a property (or multiple properties) as well as optional maximum and/or minimum end values. It will [then] calculate the appropriate landing position and plot a smooth course based on the easing equation you define.
Note: the ThrowProps plugin is a membership benefit of Club GreenSock.
“Pinch, punch, first of the month”, “White Rabbits” – however you like to mark the dawn of a new month, we like to bring them in with freebies This month, we have a great little AS3 Image Revealer from Carlos Yanez.
Here is an example revealing a black and white version of an image:
This can be very useful in before and after comparisons:
Features
Using this base file you can:
Change the before and after (bottom-top) images
Use any Display Object for the effect
Modify the slider graphic
Usage
Open the ImageRevealer.fla and edit the MovieClip in the stage, use the Timeline to determine where to place every image and adjust the Mask size to fill the image.
Open the Main.as file and edit the highlighted lines:
package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
public final class Main extends Sprite
{
var frame:int = 11; //This is the middle frame
public final function Main():void
{
img.gotoAndStop(11); //Change the frame to show half top, half bottom
arrows.buttonMode = true;
addListeners();
}
private final function addListeners():void
{
arrows.addEventListener(MouseEvent.MOUSE_DOWN, initDrag);
arrows.addEventListener(MouseEvent.MOUSE_UP, termDrag);
img.addEventListener(MouseEvent.MOUSE_UP, termDrag);
}
private final function initDrag(e:MouseEvent):void
{
/* Change the y value (353) to the y of your "arrows" MC
Change the width value (300) to the width of your image drag area */
arrows.startDrag(true, new Rectangle(0, 353, 300));
stage.addEventListener(MouseEvent.MOUSE_MOVE, revealImage);
}
private final function termDrag(e:MouseEvent):void
{
arrows.stopDrag();
stage.removeEventListener(MouseEvent.MOUSE_MOVE, revealImage);
}
private final function revealImage(e:MouseEvent):void
{
/* This is a tricky part, the default frames in the MC are 20
you'll need to calculate the constant according to your frames
and image size to reveal the image correctly */
img.gotoAndStop(Math.floor(arrows.x * 0.07)); //0.07 is the constant here
}
}
}
This tutorial will show you a way to add homing missiles to the arsenal of your game.
Final Result Preview
Let’s take a look at the final result we will be working towards:
Step 1: Set up the FLA Document
Create a new Flash document set for ActionScript 3.0. I’ll be using the dimensions of 600×400, and a frame rate of 30 FPS. Save the file with a name of your choice.
Step 2: Create a Document Class
Besides the FLA, we also need to create a document class. Create a new Actionscript file, and add this code:
package
{
import flash.display.Sprite;
public class Main extends Sprite
{
public function Main()
{
}
}
}
Save this file in the same directory as our FLA. Name it Main.as.
Step 3: Link the Main Class with the FLA
In order to compile the code from the Main class, we need to link it with the FLA. On the Properties panel of the FLA, next to Class, enter the name of the document class, in this case, Main.
Then, save the changes on the FLA.
Step 4: Draw a Missile
We need a missile graphic to be displayed when shooting. You may import a bitmap or draw a shape right there on Flash. I’ll be using a tiny shape on this example.
What’s important here is that you have to make the missile point straight to the right, since that’s the origin point for the rotation. So 0° means pointing straight to the right, -90° means upwards, 90° means downwards, and 180° points to the left. Later on we’ll need to rotate the missile according to its direction.
Step 5: Create a MovieClip for the Missile
Once you have the missile graphic, select it and press F8 to create a Movie Clip. Name it "Missile", make sure the the Registration Point is at the center, and tick the "Export for ActionScript" checkbox.
You’ll end up with a Missile MovieClip in the Library.
If you have a Missile instance on the Stage, delete it. We’ll be adding the Missile MovieClip by code.
Step 6: Aim
The first thing a homing missile needs to know is where the target is located. We’re going to set the rotation of the missile according to the position of the mouse cursor first. Let’s work with the enterFrame Event for a constant rotation update.
Add a Missile instance to the stage, I’m placing it at the center (300, 200). Then calculate the distance from the missile to the mouse cursor (I’m storing it in variables targetX and targetY). Finally, the missile’s angle will be the arc tangent of both points (targetX, targetY). The result you’ll get will be in radians, but the rotation works in degrees, so you’ll need to do the conversion by multiplying by 180/Pi. (To see why, check this article.)
import flash.events.Event;
public class Main extends Sprite
{
private var missile:Missile = new Missile();
public function Main()
{
addChild(missile);
missile.x = 300;
missile.y = 200;
addEventListener(Event.ENTER_FRAME, playGame);
}
private function playGame(event:Event):void
{
var targetX:int = mouseX - missile.x;
var targetY:int = mouseY - missile.y;
missile.rotation = Math.atan2(targetY, targetX) * 180 / Math.PI;
}
}
If you Publish (Ctrl + Enter) the document at this point, you should be getting something like this:
Move your mouse near the missile to see it rotate.
Step 7: Seek
We got the rotation, now we need the movement. The missile has to seek the target, no matter whether it’s a steady or a moving target. What we’ll do is calculate the movement according to the current rotation of the missile. Let’s set a value for the speed, and make the missile chase after the mouse cursor.
We’ll include a couple of new variables to calculate the velocity (vx, vy). When the missile is pointing to the right, its angle is lower than 90° and higher than -90°, so it’s always lower than the absolute value of 90°. When it’s pointing to the left, its angle has an absolute value higher than 90°. This will determine vx in accordance to speed, then vy will be the difference of speed and vx.
private var speed:int = 10;
public function Main()
{
addChild(missile);
missile.x = 300;
missile.y = 200;
addEventListener(Event.ENTER_FRAME, playGame);
}
private function playGame(event:Event):void
{
var targetX:int = mouseX - missile.x;
var targetY:int = mouseY - missile.y;
missile.rotation = Math.atan2(targetY, targetX) * 180 / Math.PI;
//Velocity in x is relative to the angle, when it's 90° or -90°, vx should be 0.
var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90;
var vy:Number;//Velocity in y is the difference of speed and vx.
if (missile.rotation < 0)
vy = -speed + Math.abs(vx);//Going upwards.
else
vy = speed - Math.abs(vx);//Going downwards.
missile.x += vx;
missile.y += vy;
}
You’ll get a missile chasing your cursor.
You can use a different speed if you want.
Step 8: Create a Missile Launcher
Missiles don’t come out of thin air, they are shot out of missile launchers. Let’s make a MovieClip representing a cannon (I’ll use a simple rectangle), and name it Cannon. I’m going to add a Cannon instance by code, so I’m going to keep the stage empty.
Step 9: Shoot
Now, instead of adding a missile, I’m just going to add a cannon, and a missile will be added at the cannon’s position when I click on the stage. We’ll add a Boolean to check if the missile has been shot, and also a new function for shooting after the click.
import flash.events.MouseEvent;
public class Main extends Sprite
{
private var missile:Missile = new Missile();
private var speed:int = 10;
private var cannon:Cannon = new Cannon();
private var missileOut:Boolean = false;//Has the missile been shot?
public function Main()
{
addChild(cannon);
cannon.x = 50;
cannon.y = 380;
addEventListener(Event.ENTER_FRAME, playGame);
stage.addEventListener(MouseEvent.CLICK, shoot);
}
private function playGame(event:Event):void
{
if (missileOut)
{
var targetX:int = mouseX - missile.x;
var targetY:int = mouseY - missile.y;
missile.rotation = Math.atan2(targetY, targetX) * 180 / Math.PI;
var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90;
var vy:Number;
if (missile.rotation < 0)
vy = -speed + Math.abs(vx);
else
vy = speed - Math.abs(vx);
missile.x += vx;
missile.y += vy;
}
}
private function shoot(event:MouseEvent):void
{
if (!missileOut)
{
addChild(missile);
swapChildren(missile, cannon);//missile will come out from behind cannon
missileOut = true;
missile.x = cannon.x;
missile.y = cannon.y;
}
}
This is what you’ll get:
This doesn’t look nice. We have to either make the cannon rotate as well, or force the missile to go upwards right after being shot. Since option #1 is the easiest approach, we’ll take option #2.
Step 10: Less Precision for Better Looks
If the cannon is vertical, we would expect the missile to launch upwards and then get on track towards its target. The approach I’ll use to achieve this is to give the missile a starting angle of -90° (pointing upwards), and smoothly rotate to get on track to the mouse cursor. We’ll add an ease variable to determine the smoothness or sharpness of the rotation. Then we’ll create another variable to keep track of the actual rotation that points straight to the target, while the missile’s rotation will change according to the ease we set (ease = 1 will behave just like before, anything higher will make a smoother turn).
Since half of the rotation values are negative, in some cases we’ll need to calculate them against 360 to get the actual difference between the target angle and the missile’s rotation.
private var ease:int = 10;
public function Main()
{
addChild(cannon);
cannon.x = 50;
cannon.y = 380;
addEventListener(Event.ENTER_FRAME, playGame);
stage.addEventListener(MouseEvent.CLICK, shoot);
}
private function playGame(event:Event):void
{
if (missileOut)
{
var targetX:int = mouseX - missile.x;
var targetY:int = mouseY - missile.y;
var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI;
if (Math.abs(rotation - missile.rotation) > 180)
{
if (rotation > 0 && missile.rotation < 0)
missile.rotation -= (360 - rotation + missile.rotation) / ease;
else if (missile.rotation > 0 && rotation < 0)
missile.rotation += (360 - rotation + missile.rotation) / ease;
}
else if (rotation < missile.rotation)
missile.rotation -= Math.abs(missile.rotation - rotation) / ease;
else
missile.rotation += Math.abs(rotation - missile.rotation) / ease;
var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90;
var vy:Number;
if (missile.rotation < 0)
vy = -speed + Math.abs(vx);
else
vy = speed - Math.abs(vx);
missile.x += vx;
missile.y += vy;
}
}
private function shoot(event:MouseEvent):void
{
if (!missileOut)
{
addChild(missile);
swapChildren(missile, cannon);//missile will come out from behind cannon
missileOut = true;
missile.x = cannon.x;
missile.y = cannon.y;
missile.rotation = -90;//missile will start pointing upwards
}
}
Check it out:
Notice what happens when you move your mouse out of the SWF, and how this is different from the previous example.
Step 11: Missile Hits, Missile Explodes
Besides the Missile Movie Clip, we need an explosion animation. In my case, I’ll make a separate MovieClip with a simple tween of a circle that expands. I’m exporting it as Explosion. Press O to select the Oval Tool, and hold Shift while drawing the oval to get a circle.
For a nicer visual effect, I’ll put the circle inside another Movie Clip of its own, and give it a Bevel filter to get a darker color at the bottom and a lighter color at the top. Next, I’ll go to frame 10 and press F6 to create a Keyframe, then right-click between frame 1 and 10 and create a Classic Tween. Back on frame 10, press Q to select the Free Transform Tool and enlarge the circle.
Then, create another Classic Tween to frame 20, I’ll add a Blur filter effect.
Finally, make it disappear in a last Classic Tween to frame 30 with an Alpha color effect going to 0.
Step 12: Clean Up the Stage
The explosion animation has to be removed after it finishes, or it will loop indefinitely. Add a new layer and press F6 on the last frame, then press F9 to open the Actions panel, and add this code:
stop();<br />parent.removeChild(this);
This will make the Explosion instance remove itself after the animation is done.
Step 13: Explode
Now when the missile meets the cursor, we’ll replace it with an Explosion instance. We just need to add a new conditional in the playGame() function.
private function playGame(event:Event):void
{
if (missileOut)
{
if (missile.hitTestPoint(mouseX, mouseY))
{
var explosion:Explosion = new Explosion();
addChild(explosion);
explosion.x = missile.x;
explosion.y = missile.y;
removeChild(missile);
missileOut = false;
}
else
{
var targetX:int = mouseX - missile.x;
var targetY:int = mouseY - missile.y;
var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI;
if (Math.abs(rotation - missile.rotation) > 180)
{
if (rotation > 0 && missile.rotation < 0)
missile.rotation -= (360 - rotation + missile.rotation) / ease;
else if (missile.rotation > 0 && rotation < 0)
missile.rotation += (360 - rotation + missile.rotation) / ease;
}
else if (rotation < missile.rotation)
missile.rotation -= Math.abs(missile.rotation - rotation) / ease;
else
missile.rotation += Math.abs(rotation - missile.rotation) / ease;
var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90;
var vy:Number;
if (missile.rotation < 0)
vy = -speed + Math.abs(vx);
else
vy = speed - Math.abs(vx);
missile.x += vx;
missile.y += vy;
}
}
}
Take a look:
Step 14: Something Else to Blow Up
Chasing after the mouse cursor was entertaining, but it’s pointless in a game; we need to make a target. I’m going to draw a bunch of circles to form a Target Movie Clip.
Step 15: Shoot the Target
Now we’ll add a Target instance for the missile to have a more tangible objective. So we’ll replace any reference of the mouse cursor for the target’s position. Also, we won’t be testing for a hit point, but an object.
private var target:Target = new Target();
public function Main()
{
addChild(cannon);
cannon.x = 50;
cannon.y = 380;
addEventListener(Event.ENTER_FRAME, playGame);
stage.addEventListener(MouseEvent.CLICK, shoot);addChild(target);
target.x = 550;
target.y = 50;
}
private function playGame(event:Event):void
{
if (missileOut)
{
if (missile.hitTestObject(target))
{
var explosion:Explosion = new Explosion();
addChild(explosion);
explosion.x = missile.x;
explosion.y = missile.y;
removeChild(missile);
missileOut = false;
}
else
{
var targetX:int = target.x - missile.x;
var targetY:int = target.y - missile.y;
var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI;
if (Math.abs(rotation - missile.rotation) > 180)
{
if (rotation > 0 && missile.rotation < 0)
missile.rotation -= (360 - rotation + missile.rotation) / ease;
else if (missile.rotation > 0 && rotation < 0)
missile.rotation += (360 - rotation + missile.rotation) / ease;
}
else if (rotation < missile.rotation)
missile.rotation -= Math.abs(missile.rotation - rotation) / ease;
else
missile.rotation += Math.abs(rotation - missile.rotation) / ease;
var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90;
var vy:Number;
if (missile.rotation < 0)
vy = -speed + Math.abs(vx);
else
vy = speed - Math.abs(vx);
missile.x += vx;
missile.y += vy;
}
}
}
private function shoot(event:MouseEvent):void
{
if (!missileOut)
{
addChild(missile);
swapChildren(missile, cannon); //missile will come out from behind cannon
missileOut = true;
missile.x = cannon.x;
missile.y = cannon.y;
missile.rotation = -90;//missile will start pointing upwards
}
}
The hitTestObject() method actually only checks for an overlap between the bounding boxes of the two objects (i.e., the blue boxes that appear when you click an instance of the object in the stage), so watch out for that; it’s not pixel-perfect collision detection. However, it does the job just fine here.
You may try placing the target at different locations, as well as the cannon.
Step 16: Moving Target
We already saw that the missile will chase a moving target, such as the mouse cursor, so now let’s make the Target instance move a little.
This isn’t realistic physics, I’m just going to make the target bounce vertically. I’ll pick a reference point as the ground level, and add a gravity value to affect the target. And to make it more dynamic, I’ll increase the missile speed to 15.
private var floor:int = 385;
private var gravity:Number = 0.5;
private var targetVY:Number = 0;//Current vertical velocity of the target
public function Main()
{
addChild(cannon);
cannon.x = 50;
cannon.y = 380;
addEventListener(Event.ENTER_FRAME, playGame);
stage.addEventListener(MouseEvent.CLICK, shoot);addChild(target);
target.x = 550;
target.y = 50;
}
private function playGame(event:Event):void
{
if (missileOut)
{
if (missile.hitTestObject(target))
{
var explosion:Explosion = new Explosion();
addChild(explosion);
explosion.x = missile.x;
explosion.y = missile.y;
removeChild(missile);
missileOut = false;
}
else
{
var targetX:int = target.x - missile.x;
var targetY:int = target.y - missile.y;
var rotation:int = Math.atan2(targetY, targetX) * 180 / Math.PI;
if (Math.abs(rotation - missile.rotation) > 180)
{
if (rotation > 0 && missile.rotation < 0)
missile.rotation -= (360 - rotation + missile.rotation) / ease;
else if (missile.rotation > 0 && rotation < 0)
missile.rotation += (360 - rotation + missile.rotation) / ease;
}
else if (rotation < missile.rotation)
missile.rotation -= Math.abs(missile.rotation - rotation) / ease;
else
missile.rotation += Math.abs(rotation - missile.rotation) / ease;
var vx:Number = speed * (90 - Math.abs(missile.rotation)) / 90;
var vy:Number;
if (missile.rotation < 0)
vy = -speed + Math.abs(vx);
else
vy = speed - Math.abs(vx);
missile.x += vx;
missile.y += vy;
}
}
targetVY += gravity;
target.y += targetVY;
if (target.y > floor)
{
target.y = floor;
targetVY = -18;
}
}
If you Publish this now, you should be getting a moving target.
Conclusion
Whether you want an accurate homing missile, or you’d prefer a smooth animation, you can get both results based on this example. Now you’ve got a new weapon to add in your arsenal, maybe you could try making a Worms-like game, or even use the algorithm on something other than a missile, like some weird mosquito that follows your character.
I hope you’ve found this tutorial useful. Thanks for reading!
ByteArray is an extremely powerful Class that can be used for many things related to data manipulation, including (but not limited to) saving game data online, encrypting data, compressing data, and converting a BitmapData object to a PNG or JPG file. In this introduction, we’ll use the ByteArray class to take a native AS3 object and encode it to a string that could be saved to a server for later recovery, then decode it later.
In previous tutorials we’ve seen how to use XML and JSON to encode data in a textual (String) format. However, both XML and JSON are designed to be human-readable, and as a result they’re much longer than they need to be. It can also be tricky to convert certain types of AS3 object to either format. ByteArray has some truly advanced features, but to start with, we’ll just look at one simple one: it makes it very easy to turn an AS3 object into a String.
Final Result Preview
Let’s take a look at the final result we will be working towards:
When you paste an encoded ByteArray string into the TextField and click the Load button, it will decrypt it, and show the object properties saved in it. You can try the following encoded ByteArrays; copy-paste them into the TextField and click the Load button to see what I am talking about:
//This ByteArray will show my data (This is the default ByteArray loaded)
CgsBFW9jY3VwYXRpb24GB0NUTw93ZWJzaXRlBiFodHRwOi8vaWt0LmNvLmlkCW5hbWUGDVRhdWZpawE=
//This ByteArray will show my current thought
CgsBIWZvb2RfZm9yX3Rob3VnaHQGgnVJIGFtIHRoaW5raW5nIG9uIHNoYXJpbmcgdGhlIHRlY2huaXF1ZSBpIHVzZWQgdG8gbWFrZSBhIEZ1bGwgRmxhc2ggRHluYW1pYyBXZWJzaXRlIFNFTyBGcmllbmRseSBmb3IgbXkgbmV4dCBUdXRvcmlhbCBpbiBBY3RpdmVUdXRzKy4uLiA8dT5XaGF0IGRvIHlvdSB0aGluaz88L3U+IDxiPmlzIGl0IGEgZ29vZCBpZGVhPC9iPj8B
//This ByteArray will talk about Flash and SEO and my experience with them
CgsBEXF1ZXN0aW9uBoEDPGI+PHU+Q2FuIGEgZnVsbHkgZHluYW1pYyBGbGFzaCBXZWJzaXRlIGJlIFNFTyBmcmllbmRseTwvdT48L2I+Pz8NYW5zd2VyBoM/SXQgY2FuLCBoZXJlIGlzIHRoZSBwcm9vZiwgPGEgaHJlZj0naHR0cDovL3d3dy5nb29nbGUuY28uaWQvc2VhcmNoP3E9Zmxhc2grc2VvJmllPXV0Zi04Jm9lPXV0Zi04JmFxPXQnIHRhcmdldD0nX2JsYW5rJz5odHRwOi8vd3d3Lmdvb2dsZS5jby5pZC9zZWFyY2g/cT1mbGFzaCtzZW8maWU9dXRmLTgmb2U9dXRmLTgmYXE9dDwvYT4sIGlrdC5jby5pZCBpcyByYW5rZWQgIzYgb3ZlciB0aGVyZQE=
Step 1: Create New ActionScript Project
Within the ‘Flash Builder’ window :
Open Flash Builder 4
Click the File Menu
Hover to New
Click ActionScript Project
Step 2: New ActonScript Project Setup
Within the ‘New ActionScript Project’ window :
Type ‘TUTORIAL_ByteArray’ into Project name field
Please remember where you save your project
Click ‘Finish’ button
Step 3: Base64.as
Copy Base64.as into your project ‘com’ directory.
Create a new ‘com’ directory inside your source directory.
Put the file into the newly created ‘com’ directory.
Base64.as will come in useful later. It’s by Steve Webster, who used to reside at dynamicflash.com (he left the Flash community a couple of years ago).
Step 4: Necessary Classes
In TUTORIAL_ByteArray class (which is the main class), please import the following Classes for this tutorial:
package
{
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.events.MouseEvent;
import flash.utils.ByteArray;
import com.Base64;
public class TUTORIAL_ByteArray extends Sprite
{
public function TUTORIAL_ByteArray()
{
}
}
}
Step 5: Getting used to Flash Builder I
Add the following code inside TUTORIAL_ByteArray Constructor for a very simple test.
public function TUTORIAL_ByteArray()
{
var _test:String = "Hello world!";
trace(_test);
}
Press F11 key to run this project, you should get the message inside the Console Window.
Step 6: Getting used to Flash Builder II
Now let’s try to trace the message inside _test variable, but this time we will do it from another function:
public function TUTORIAL_ByteArray()
{
var _test:String = "Hello world!";
TestFunction();
}
private function TestFunction():void{
trace(_test);
}
Press CTRL+S to save your project. An error detected after you saved your project; this is because a variable which has been declared inside a function will not be available for any other function. So for this case, we need to declare the _test variable outside:
public function TUTORIAL_ByteArray()
{
TestFunction();
}
private function TestFunction():void{
trace(_test);
}
private var _test:String = "Hello world!";
Step 7: Necessary Private Variables
Please add the following private variables for this project:
public function TUTORIAL_ByteArray()
{
TestFunction();
}
private function TestFunction():void{
trace(_test);
}
private var _test:String = "Hello World!";
private var _loadButton:TextField;
private var _inputField:TextField;
private var _testObject:Object;
private var _testByteArray:ByteArray;
Step 8: UI
Let’s create a simple user interface for this project.
Now that we need to display something into our project, we need to declare our stage sizes (Check Line 13).
Rename our TestFunction into InitUI function, and put the following line of codes inside. Please read the explanation commented inside the code.
[SWF(width="550", height="400", frameRate="60", pageTitle="Tutorial ByteArray")]
public class TUTORIAL_ByteArray extends Sprite
{
public function TUTORIAL_ByteArray()
{
InitUI();
}
private function InitUI():void{
//Initialize our TextFields so that we can use them
_loadButton = new TextField();
_inputField = new TextField();
//Give a defaultTextFormat for both of them (Tahoma at 11pt, colored 0x777777)
_loadButton.defaultTextFormat = _inputField.defaultTextFormat = new TextFormat("Tahoma", 11, 0x777777);
//Give both of them a border
_loadButton.border = _inputField.border = true;
//Set the autosize for our Load Button , so that it will automatically shrink / grow to fit the text inside
_loadButton.autoSize = TextFieldAutoSize.LEFT;
//Set the selectable of our Load Button to false, so that user cannot select the text in it
_loadButton.selectable = false;
//Set the multiline and wordWrap of our Input Field to true, so that a long text will automatically wrapped to the next line
_inputField.multiline = _inputField.wordWrap = true;
//Enable user to type something into our Input Field, by setting this type property
_inputField.type = TextFieldType.INPUT;
//Put some text into Both of them
_loadButton.text = "Load";
_inputField.text = "";
//Add both of them into stage, so that they are visible to our visitors
addChild(_inputField);
addChild(_loadButton);
//Position our Input Field and make it bigger
_inputField.x = 25;
_inputField.y = 25;
_inputField.width = 200;
_inputField.height = 150;
//There is a reason why i did this, so that the Load Button is located directly below our Input Field
//So you can position the Input Field anywhere you like, as long as there is this code, the Load Button will stick below the Input Field
_loadButton.y = _inputField.y + _inputField.height;
_loadButton.x = _inputField.x;
}
Press F11 to run this project and see the simple user interface we have created.
Step 9: Enable Interactivity
Please read the explanation commented inside the code
_loadButton.y = _inputField.y + _inputField.height;
_loadButton.x = _inputField.x;
//Add an Event Listener for our _loadButton, so whenever the user clicks this button,
//Flash will call _loadButton_CLICK() Method
_loadButton.addEventListener(MouseEvent.CLICK, _loadButton_CLICK, false, 0, true);
}
//This method will be called whenever user click the _loadButton
private function _loadButton_CLICK(Events:MouseEvent = null):void{
//Get anything that the user input and save them into our _test variable
_test = _inputField.text;
//Trace the _test variable
trace("User input the following message : " + _test);
}
Press F11 to run this project; try typing something into the _inputField and then click the _loadButton. This is the most basic technique of getting a variable from our user and storing it into our private variable.
Food for Thought
We have finally reach our most important steps in this project, but before we continue let me provides a mental stimulus for thinking. Currently in our project, we are capable of getting a String and storing it in our private variable. But it is only a string; how about if I want a user to type in something inside _inputField so that I can get an Object from it? What should the user type? The answer is an ‘Encoded Base64 ByteArray’
Step 10: Introduction to ByteArray
We will proceed slowly this time, so that you will understand the ByteArray class and be able to create your own data manipulation and apply it to your own projects. Please read the explanation commented inside the code:
public function TUTORIAL_ByteArray()
{
InitUI();
CreateByteArray();
}
private function CreateByteArray():void{
//Initialize our _testObject variable, so that we can populate many dynamic properties and store String data in it (we will load them later whenever user clicked the _loadButton)
_testObject = new Object();
_testObject.name = "Taufik";
_testObject.website = "<a href='http://ikt.co.id'>http://ikt.co.id</a>";
_testObject.occupation = "CTO";
//Initialize our _byteArray variable, so that we can start converting object into a ByteArray
_testByteArray = new ByteArray();
//Convert the Object into Byte Array, This is how you do it, to convert an Object into a ByteArray, IT IS SIMPLE isnt it? )
_testByteArray.writeObject(_testObject);
//Lets see if everything works properly
trace("Our first ByteArray created :: " + _testByteArray.toString());
}
Press F11 to run this project. See how simple it is, this ByteArray is an extremely powerful class and yet it is not hard at all. We’ve taken a native AS3 Object and converted it to Action Message Format.
Before sending the data to our PHP Script using the GET method, we should convert it into a Base64 String. This is because Base64 can be carried by XML (and by HTML).
Step 11: Encoding ByteArray into Base64 String
Please read the explanation commented within the code.
private function CreateByteArray():void{
//Initialize our _testObject variable, so that we can populate many dynamic properties and store String data in it
//(we will load them later whenever user clicks the _loadButton)
_testObject = new Object();
_testObject.name = "Taufik";
_testObject.website = "<a href='http://ikt.co.id'>http://ikt.co.id</a>";
_testObject.occupation = "CTO";
//Initialize our _byteArray variable, so that we can start converting object into a ByteArray
_testByteArray = new ByteArray();
//Convert the Object into Byte Array, This is how you do it, to convert an Object into a ByteArray, IT IS SIMPLE isnt it? )
_testByteArray.writeObject(_testObject);
//Encode the ByteArray into Base64 String (so that we can send them via PHP or copy the text to notepad), again IT IS VERY SIMPLE!
var encoded:String = Base64.encodeByteArray(_testByteArray);
//Put the encoded Base64 String into our _inputField (so that we can copy them into notepad)
_inputField.text = encoded;
}
Press F11 to run this project. If converting an Object into a ByteArray is simple, converting the Byte value of our data into Base64 String is as simple, thanks to Base64.as.
Step 12: Converting Encoded Base64 String into Object
We will try to decode the entered Base64 String into an Object whenever the user clicks the _loadButton, change our _loadButton_CLICK function. Please read the explanation commented inside the code:
private function _loadButton_CLICK(Events:MouseEvent = null):void{
//We have to catch any Errors
try{
//We decode our encoded Base64 String into a ByteArray, so that we can retrieve our Object back
var DecodedByteArray:ByteArray = Base64.decodeToByteArray(_inputField.text);
//If converting an Object into ByteArray is simple, retrieving an Object from ByteArray is as simple as this
var LoadedObject:Object = DecodedByteArray.readObject();
//Prepare to output all properties and their values inside the LoadedObject
var Output:String = "";
for (var VarName:String in LoadedObject){
Output += VarName + " : " + LoadedObject[VarName] + "<br>";
}
//Output them into our _inputField
_inputField.htmlText = Output;
}catch(err:Error){
_inputField.text = "Please input an Encoded ByteArray into this TextField before clicking the 'Load' Button. Error message :: " + err.message;
}
}
Press F11 to run this project. We get our encoded Base64 String of our _testObject inside our _inputField; click the _loadButton to see our project convert this Base64 String back and display all of its properties and values. You can try to copy and paste the Base64 Strings at the beginning of this tutorial and read all of my messages.
Conclusion
The ByteArray Class is an extremely powerful Class, and yet it is very simple to use. I have seen many great Flash apps out there utilizing this ByteArray to perform so many mind blowing data manipulation, such as those kinds I mentioned at the beginning of this tutorial. I have heard many Flash game programmers utilize XML to save their visitors’ ‘Save Game Data’, but as we all already know, XML is one hell of a very complicated class; with ByteArray I can save something like this EASILY.
private function CreateByteArray():void{
_testObject = new Object();
_testObject.name = "Taufik";
_testObject.website = "<a href='http://ikt.co.id'>http://ikt.co.id</a>";
_testObject.occupation = "CTO";
_testObject.level = 99;
//Get the state of this Game Character Inventory
var _inventory:Array = new Array({item_id:5, amount:1}, {item_id:85, amount:1}, {item_id:42, amount:5});
_testObject.inventory = _inventory;
//Get what is the skill they already level up
var _skill:Array = new Array({skill_id:1, level:0}, {skill_id:2, level:1});
_testObject.skill = _skill;
//Initialize our _byteArray variable, so that we can start converting object into a ByteArray
_testByteArray = new ByteArray();
//Convert the Object into Byte Array, This is how you do it, to convert an Object into a ByteArray, IT IS SIMPLE isnt it? )
_testByteArray.writeObject(_testObject);
//Encode the ByteArray into Base64 String (so that we can send them via PHP or copy the text to notepad), again IT IS VERY SIMPLE!
var encoded:String = Base64.encodeByteArray(_testByteArray);
//Put the encoded Base64 String into our _inputField (so that we can copy them into notepad)
_inputField.text = encoded;
}
Yeah, something this complicated only takes a couple line of codes, imagine the horror of saving this data using XML and retrieving them back for further use. All in all I have to say that with Byte data manipulation you can achieve a lot of things, and some might be the solution you have been looking for all this time.
I hope you have found this tutorial useful. Thanks for reading!
Hey there and welcome to "Flash Video Training Source", a resource for anybody interested in learning more about Adobe's great tool. We feature educational videos, which will help you master Adobe Flash and help you get to know all of its features. We at "Flash Video Training Source" believe that video training and video... more
Why don't you follow us on Twitter and get the latest video tutorials twitted to your account. Just click on the floating twitter bar to your right!