logo
468x60-2-495


  • Home
  • Privacy Policy
  • About
search
Feb 24, 2012 Posted on Feb 24, 2012 in Hints and Tips | 10 comments

Make a Tower Defense Game in AS3: Enemies and Basic AI

Hey Flash Developers, welcome to the second part of my Tower Defense Game tutorial. In the first part, we developed the basic mechanism of creating turrets and making them shoot towards the point of mouse click. But that’s not what turrets are for! In this part we’ll extend the game to include enemies, basic artificial intelligence (AI) in turrets, and some more game elements. Are you ready?


Final Result Preview

This is the game we are going to create in this tutorial:

Click the orange circles to place turrets. The red circles are enemies, and the number on each represents its hit points.


Step 1: Recap

In the previous tutorial we developed a game which had placeholders for the turrets. We could deploy turrets by clicking those placeholders, and the turrets aimed at the mouse pointer and shot bullets towards the point where the user clicked.

We finished with a Main class which had the game loop and game logic. Apart from that we had the Turret class which had nothing much except the update function that made the turret rotate.


Step 2: A Separate Bullet Class

We previously created the bullets in Main class and attached an ENTER_FRAME listener to move it. The bullet did not have enough properties earlier to consider it a making a separate class. But in such a game bullets can have many varieties like speed, damage, and so on, so it is a good idea to pull out the bullet code and encapsulate it in a separate Bullet class. Let’s do it.

Create a new class called Bullet, extending the Sprite class. The basic code for this class should be:

 package
 {
	import flash.display.Sprite;

	public class Bullet extends Sprite
	{

		public function Bullet() {
		}
	}
}

Next we put the code to draw the bullet graphic, taken from Main, in Bullet. As we did with the Turret class, we create a function called draw in the Bullet class:

private function draw():void {
	var g:Graphics = this.graphics;
	g.beginFill(0xEEEEEE);
	g.drawCircle(0, 0, 5);
	g.endFill();
}

And we call this function from the Bullet constructor:

public function Bullet() {
	draw();
}

Now we add some properties to the bullet. Add four variables: speed, speed_x, speed_y and damage, before the Bullet constructor:

private var speed:Number;
private var speed_x: Number;
private var speed_y:Number;
public var damage:int;

What are these variables for?

  • speed: This variable stores the speed of the bullet.
  • speed_x and speed_y: These store the x and y components of the speed, respectively, so that the calculation of breaking the speed into its components does not have to be done again and again.
  • damage: This is the amount of damage the bullet can do to an enemy. We keep this variable public as we will require this in our game loop in the Main class.

We initialize these variables in the constructor. Update your Bullet constructor:

public function Bullet(angle:Number) {
	speed = 5;
	damage = 1;
	speed_x = Math.cos(angle * Math.PI / 180) * speed;
	speed_y = Math.sin(angle * Math.PI / 180) * speed;
	draw();
}

Notice the angle variable we receive in the constructor. This is the direction (in degrees) in which the bullet will move. We just break the speed into its x and y components and cache them for future use.

The last thing that remains in the Bullet class is to have an update function that will be called from the game loop to update (move) the bullet. Add the following function at the end of the Bullet class:

public function update():void {
	x += speed_x;
	y += speed_y;
}

Bingo! We are done with our Bullet class.


Step 3: Updating the Main Class

We moved a lot of bullet code from Main class to its own Bullet class, so a lot of code remains unused in Main and much needs to be updated.

First, delete the createBullet() and moveBullet() functions. Also remove the bullet_speed variable.

Next, go to the shoot function and update it with the following code:

private function shoot(e:MouseEvent):void {
	for each(var turret:Turret in turrets) {
		var new_bullet:Bullet = new Bullet(turret.rotation);
		new_bullet.x = turret.x + Math.cos(turret.rotation * Math.PI / 180) * 25;
		new_bullet.y = turret.y + Math.sin(turret.rotation * Math.PI / 180) * 25;
		addChild(new_bullet);
	}
}

We no longer use the createBullet function to create bullet rather use the Bullet constructor and pass the turret’s rotation to it which is the direction of the bullet’s movement and so we don’t need to store it in the bullet’s rotation property as we did earlier. Also we don’t attach any listener to the bullet as the bullet will be updated from within the game loop next.


Step 4: Saving the Bullet References

Now that we need to update the bullets from the game loop, we need a reference of them to be stored somewhere. The solution is the same as for the turrets: create a new Array named bullets and push the bullets onto it as they are created.

First declare an array just below the turrets array declaration:

private var ghost_turret:Turret;
private var turrets:Array = [];
private var bullets:Array = [];

Now to populate this array. We do so whenever we create a new bullet – so, in the shoot function. Add the following just before adding the bullet to the stage:

var new_bullet:Bullet = new Bullet(turret.rotation);
new_bullet.x = turret.x + Math.cos(turret.rotation * Math.PI / 180) * 25;
new_bullet.y = turret.y + Math.sin(turret.rotation * Math.PI / 180) * 25;
bullets.push(new_bullet);
addChild(new_bullet);

Step 5: Update the Bullets

Just like how we update the turrets the game loop, we will update the bullets, too. But this time, instead of using a for...each loop, we’ll use a basic for loop. Before this, we must add two variables to the top of the game loop, so that we know which variables are used within the game loop and can set them free for garbage collection.

var turret:Turret;
var bullet:Bullet;

Go ahead and add the following code at the end of game loop:

for (var i:int = bullets.length - 1; i >= 0; i--) {
	bullet = bullets[i];
	if (!bullet) continue;
	bullet.update();
}

Here we traverse over all the bullets on the stage every frame and call their update function which makes them move. Note here that we iterate the bullets array in reverse. Why? We’ll see this ahead.

Now that we have a turret variable declared outside already, we don’t need to declare it again inside the for...each loop of turrets. Modify it to:

for each(turret in turrets) {
	turret.update();
}

Finally we add the boundary check condition; this was previously in the bullet’s ENTER_FRAME but now we check it in the game loop:

if (bullet.x < 0 || bullet.x > stage.stageWidth || bullet.y < 0 || bullet.y > stage.stageHeight) {
	bullets.splice(i, 1);
	bullet.parent.removeChild(bullet);
	continue;
}

We check whether the bullet is out of the stage’s boundary, and if so we first remove its reference from the bullets array using the splice function, and then remove the bullet from the stage and continue with the next iteration. This is how your game loop should look:

private function gameLoop(e:Event):void {
	var turret:Turret;
	var bullet:Bullet;

	for each(turret in turrets) {
		turret.update();
	}

	for (var i:int = bullets.length - 1; i >= 0; i--) {
		bullet = bullets[i];
		if (!bullet) continue;
		bullet.update();
	}
}

If you now run the game, you should have the same functionality as in Part 1, with code that is much more clean and organized.


Step 6: Presenting the Enemy

Now we add one of the most important elements of the game: the Enemy. First thing is to create a new class named Enemy extending the Sprite class:

package
{
	import flash.display.Sprite;

	public class Enemy extends Sprite
	{
		public function Enemy() {
		}
	}
}

Now we add some properties to the class. Add them before your Enemy constructor:

private var speed_x:Number;
private var speed_y:Number;

We initialize these variables in the Enemy constructor:

public function Enemy()
{
	speed_x = -1.5;
	speed_y = 0;
}

Next we create the draw and update functions for the Enemy class. These are very similar to the ones from Bullet. Add the following code:

private function draw():void {
	var g:Graphics = this.graphics;
	g.beginFill(0xff3333);
	g.drawCircle(0, 0, 15);
	g.endFill();
}

public function update():void {
	x += speed_x;
	y += speed_y;
}

Step 7: Timing the Game Events

In our game we need to have many events that take place at certain times or repeatedly at certain intervals. Such timing can be achieved using a time counter. The counter is just a variable that gets incremented as the time passes in the game. The important thing here is when and by how much amount to increment the counter. There are two ways in which timing is generally done in games: Time based and Frame based.

The difference is that the unit of step in time based game is based on real time (i.e. number of milliseconds passed), but in a frame based game, the unit of step is based on frame units (i.e. the number of frames passed).

For our game we are going to use a frame based counter. We’ll have a counter which we’ll increment by one in the game loop, which runs each frame, and so will basically give us the number of frames which have passed since the game started. Go ahead and declare a variable after the other variable declarations in the Main class:

private var ghost_turret:Turret;
private var turrets:Array = [];
private var bullets:Array = [];
private var global_time:Number = 0;

We increment this variable in the game loop at the top:

global_time++;

Now based on this counter we can do stuff like creating enemies, which we’ll do next.


Step 8: Let’s Create Some Enemies

What we want to do now is create enemies on the field after every two seconds. But we are dealing with frames here, remember? So after how many frames should we create enemies? Well, our game is running at 30 FPS, thus incrementing the global_time counter 30 times each second. A simple calculation tells us that 3 seconds = 90 frames.

At the end of the game loop add the following if block:

if (global_time % 90 == 0) {
}

What is that condition about? We use the modulo (%) operator, which gives the remainder of a division – so global_time % 90 gives us the remainder when global_time is divided by 90. We check whether the remainder is 0, as this will only be the case when global_time is a multiple of 90 – that is, the condition returns true when global_time equals 0, 90, 180 and so on… This way, we achieve a trigger at every 90 frames or 3 seconds.

Before we create the enemy, declare another array called enemies just below the turrets and bullets array. This will be used to store references to enemies on the stage.

private var ghost_turret:Turret;
private var turrets:Array = [];
private var bullets:Array = [];
private var enemies:Array = [];
private var global_time:Number = 0;

Also declare an enemy variable at the top of the game loop:

global_time++;
var turret:Turret;
var bullet:Bullet;
var enemy:Enemy;

Finally add the following code inside the if block we created earlier:

enemy = new Enemy();
enemy.x = 410;
enemy.y = 30 + Math.random() * 370;
enemies.push(enemy);
addChild(enemy);

Here we create a new enemy, position it randomly at the right of the stage, push it in the enemies array and add it to the stage.


Step 9: Updating the Enemies

Just like we update the bullets in the game loop, we update the enemies. Put the following code below the turret for...each loop:

for (var j:int = enemies.length - 1; j >= 0; j--) {
	enemy = enemies[j];
	enemy.update();
	if (enemy.x < 0) {
		enemies.splice(j, 1);
		enemy.parent.removeChild(enemy);
		continue;
	}
}

Just like we did a boundary check for bullets, we check for enemies too. But for enemies we just check whether they went out of the left side of the stage, as they only move right-to-left. You should see enemies coming from the right if you run the game now.


Step 10: Give the Enemies Some Health

Every enemy has some life/health and so will ours. We will also show the remaining health on the enemies. Lets declare some variables in the Enemy class for the health stuff:

private var health_txt:TextField;
private var health:int;
private var speed_x:Number;
private var speed_y:Number;

We initialise the health variable in the constructor next. Add the following to the Enemy constructor:

health = 2;

Now we initialize the health text variable to show on the center of enemy. We do so in the draw function:

health_txt = new TextField();
health_txt.height = 20; health_txt.width = 15;
health_txt.textColor = 0xffffff;
health_txt.x = -5;
health_txt.y = -8;
health_txt.text = health + "";
addChild(health_txt);

All we do is create a new TextField, set its color, position it and set its text to the current value of health Finally we add a function to update the enemy’s health:

public function updateHealth(amount:int):int {
	health += amount;
	health_txt.text = health + "";
	return health;
}

The function accepts an integer to add to the health, updates the health text, and returns the final health. We’ll call this function from our game loop to update each enemy’s health and detect whether it’s still alive.


Step 11: Shooting the Enemies.

First lets modify our shoot function a bit. Replace the existing shoot function with the folowing:

private function shoot(turret:Turret, enemy:Enemy):void {
	var angle:Number = Math.atan2(enemy.y - turret.y, enemy.x - turret.x) / Math.PI * 180;
	turret.rotation = angle;
	var new_bullet:Bullet = new Bullet(angle);
	new_bullet.x = turret.x + Math.cos(turret.rotation * Math.PI / 180) * 25;
	new_bullet.y = turret.y + Math.sin(turret.rotation * Math.PI / 180) * 25;
	bullets.push(new_bullet);
	addChild(new_bullet);
}

The shoot function now accept two parameters. The first is a reference to a turret which will do the shooting; the second is a reference to a enemy towards which it will shoot.

The new code here is similar to the one present in the Turret class’s update function, but instead of the mouse’s position we now use the enemy’s cordinates. So now you can remove all the code from the update function of the Turret class.

Now how to make the turrets shoot at enemies? Well the logic is simple for our game. We make all the turrets shoot the first enemy in the enemies array. What? Lets put some code and then try to understand. Add up following lines in the end of the for...each loop used to update the turrets:

for each(turret in turrets) {
	turret.update();
	for each(enemy in enemies) {
		shoot(turret, enemy);
		break;
	}
}

For every turret we now update it, then iterate the enemies array, shoot the first enemy in the array and break from the loop. So essentially each turret shoots at the earliest created enemy as it is always at the beginning of the array. Try running the game and you should see turrets shooting the enemies.

But wait, what’s that bullet stream flowing? Looks like they are shooting too fast. Lets see why.


Step 12: Turrets Are Shooting Too Fast

As we know, the game loop runs every frame i.e. 30 times a second in our case, so the shooting statement we added in the previous step gets called at the speed of our game loop and hence we see a stream of bullets flowing. Looks like we need a timing mechanism inside the turrets too. Switch over to the Turret class and add the following code:

private var local_time:Number = 0;
private var reload_time:int;
  1. local_time: Our counter is called local_time in contrast to the global_time in the Main class. This is for two reasons: first, because this variable is local to the Turret class; second, because it doesn’t always go forward like our global_time variable – it will reset many times during the course of the game.
  2. reload_time: This is the time required by the turret to reload after shooting a bullets. Basically its the time difference between two bullet shoots by a turret. Remember all time units in our game are in terms of frames.

Increment the local_time variable in the update function and initialize the reload_time in the constructor:

public function update():void {
	local_time++;
}
public function Turret() {
	reload_time = 30;
	draw();
}

Next add the following two functions at the end of the Turret class:

public function isReady():Boolean {
	return local_time > reload_time;
}

public function reset():void {
	local_time = 0;
}

isReady returns true only when the current local_time is greater than the reload_time, i.e. when the turret has reloaded. And the reset function simply resets the local_time variable, to start it reloading again.

Now back in the Main class, modify the shoot code in the game loop we added in the previous step to the following:

for each(turret in turrets) {
	turret.update();
	if (!turret.isReady()) continue;
	for each(enemy in enemies) {
		shoot(turret, enemy);
		turret.reset();
		break;
	}
}

So if now the turret isn’t ready (isReady() returns false), we continue with the next iteration of the turret loop. You will see that the turrets fire at an interval of 30 frames or 1 second now. Cool!


Step 13: Limit the Turret Range

Still something not right. The turrets shoot at enemies irrespective of the distance between them. What’s missing here is the range of a turret. Each turret should have its own range inside which its can shoot an enemy. Add another variable to the Turret class called range and set it to 120 inside the constructor:

private var reload_time:int;
private var local_time:Number = 0;
private var range:int;
public function Turret() {
	reload_time = 30;
	range = 120;
	draw();
}

Also add a function called canShoot at the end of the class:

public function canShoot(enemy:Enemy):Boolean {
	var dx:Number = enemy.x - x;
	var dy:Number = enemy.y - y;
	if (Math.sqrt(dx * dx + dy * dy) <= range) return true;
	else return false;
}

Every turret can shoot an enemy only when it meets certain criteria – for example, you could let the turret shoot only red enemies with less than half their life and not more than 30px away. All such logic to determine whether the turret is able to shoot an enemy or not will go in the canShoot function, which returns true or false according to the logic.

Our logic is simple. If the enemy is within the range return true; otherwise return false. So when the distance between the turret and enemy (Math.sqrt(dx * dx + dy * dy)) is less than or equal to range, it returns true. A little more modification in the shoot section of the game loop:

for each(turret in turrets) {
	turret.update();
	if (!turret.isReady()) continue;
	for each(enemy in enemies) {
		if (turret.canShoot(enemy)) {
			shoot(turret, enemy);
			turret.reset();
			break;
		}
	}
}

Now only if the enemy is within the range of the turret, will the turret shoot.


Step 14: Collision Detection

A very important part of every game is the collision detection. In our game collision check is done between bullets and enemies. We will be adding the collision detection code inside the for...each loop which updates the bullets in the game loop.

The logic is simple. For every bullet we traverse the enemies array and check if there’s a collision between them. If so, we remove the bullet, update the enemy health and break out of the loop to check other enemies. Let’s add some code:

for (i = bullets.length - 1; i >= 0; i--) {
	bullet = bullets[i];
	// if the bullet isn't defined, continue with the next iteration
	if (!bullet) continue;
	bullet.update();
	if (bullet.x < 0 || bullet.x > stage.stageWidth || bullet.y < 0 || bullet.y > stage.stageHeight) {
		bullets.splice(i, 1);
		bullet.parent.removeChild(bullet);
		continue;
	}

	for (var k:int = enemies.length - 1; k >= 0; k--) {
		enemy = enemies[k];
		if (bullet.hitTestObject(enemy)) {
			bullets.splice(i, 1);
			bullet.parent.removeChild(bullet);
			if (enemy.updateHealth(-1) == 0) {
				enemies.splice(k, 1);
				enemy.parent.removeChild(enemy);
			}
			break;
		}
	}
}

We use ActionScript’s hitTestObject function to check for collision between the bullet and enemy. If the collsion occurs, the bullet is removed in the same way as when it leaves the stage. The enemy’s health is then updated using the updateHealth method, to which bullet‘s damage property is passed. If the updateHealth function returns an integer less than or equal to 0, this means the enemy is dead and so we remove it in the same way as the bullet.

And our collision detection is done!


Step 15: Why Reverse the “For” Loops?

Remember that we traverse the enemies and bullets in reverse in our game loop. Let’s understand why. Let suppose we used an ascending for loop. We are on index i=3 and we remove a bullet from the array. On removal of the item at position 3, its space is filled by the item then at position 4. So now the item previously at position 4 is at 3. After the iteration i increments by 1 and becomes 4 and so item at position 4 is checked.

Oops, you see what happened just now? We just missed the item now at position 3 which shifted back as the result of splicing. And so we use a reverse for loop which removes this problem. You can see why.


Step 16: Displaying the Turret’s Range

Let’s add some extra stuff to make the game look good. We’ll add functionality to display a turret’s range when the mouse is hovered on it. Switch over to the Turret class and add some variables to it:

private var range:int;
private var reload_time:int;
private var local_time:Number = 0;
private var body:Sprite;
private var range_circle:Sprite;

Next update the draw function to the following:

private function draw():void {
	range_circle = new Sprite();
	g = range_circle.graphics;
	g.beginFill(0x00D700);
	g.drawCircle(0, 0, range);
	g.endFill();
	range_circle.alpha = 0.2;
	range_circle.visible = false;
	addChild(range_circle);

	body = new Sprite();
	var g:Graphics = body.graphics;
	g.beginFill(0xD7D700);
	g.drawCircle(0, 0, 20);
	g.beginFill(0x800000);
	g.drawRect(0, -5, 25, 10);
	g.endFill();
	addChild(body);
}

We break the graphics of the turret into two parts: the body and the range graphic. We do this so as to give an ordering to the different parts of the turret. Here we require the range_circle to be behind the turret’s body, and so we add it first to the stage. Finally, we add two mouse listeners to toggle the range graphic:

private function onMouseOver(e:MouseEvent):void {
	range_circle.visible = true;
}

private function onMouseOut(e:MouseEvent):void {
	range_circle.visible = false;
}

Now attach the listeners to the respective events at the end of the constructor:

body.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
body.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);

If you run the game and try to deploy a turret, you will see a flickering when hovering on the placeholders. Why is that?



See the flicker?

Step 17: Removing the Flicker

Remember we set the mouseEnabled property of the ghost turret to false? We did that because, the ghost turret was capturing mouse events by coming in between the mouse and the placeholder. The same situation has arrived again as the turret itself has two children now – its body and the range sprite – which are capturing the mouse events in between.

The solution is the same. We can set their individual mouseEnabled properties to false. But a better solution is to set the ghost turret’s mouseChildren property to false. What this does is restrict all the children of ghost turret from receiving mouse events. Neat, huh? Go ahead and set it to false in the Main constructor:

ghost_turret = new Turret();
ghost_turret.alpha = 0.5;
ghost_turret.mouseEnabled = false;
ghost_turret.mouseChildren = false;
ghost_turret.visible = false;
addChild(ghost_turret);

Problem solved.

Step 18: What Next?

We could extend this demo to include much more advanced features and turn it into a playable game. Some of which could be:

  1. Better AI logic for selecting and shooting enemies.
  2. Different type of turrets, bullets and enemies in the game.
  3. Complex enemy paths instead of straight lines.

Let’s see what you can come up with from this basic demo. I’ll be glad to hear about you tower defense games, and your comments or suggestions for the series.



View full post on Activetuts+

Nov 10, 2011 Posted on Nov 10, 2011 in Hints and Tips | 10 comments

TimelineLite Ultimate Starter Guide: Basic Methods and Properties

This entry is part 2 of 2 in the series TimelineLite Ultimate Starter Guide

In the first part of this series we took a general look at the capabilities of TimelineLite. In this video I’ll show you how to get up and running with your first TimelineLite animation. You’ll learn about the various methods and properties that will be a foundation for all of the lessons moving forward.


TimelineLite in Action

You can find all the files used to create the SWF above in the source files for this tutorial.


Watch the Screencast

Don’t like ads? Download the screencast, or subscribe to Activetuts+ screencasts via iTunes!


TimelineLite Basic Methods

The following methods are used to add tweens to a TimelineLite. It’s very important to understand the subtle differences as covered in the video.

insert() – Adds tweens to a timeline at a specific time. If no insertion time is specified the tween will be inserted at a start time of zero seconds.

//this tween will be inserted at the beginning of the timeline
 tl.insert( TweenLite.to( mc, 1, {x:100} ) );
//this tween will be inserted 2 seconds into the timeline
 tl.insert( TweenLite.to( mc, 1, {x:100} ), 2);

append() – Adds tweens to a timeline relative to the end of the timeline. The offset value can be positive or negative. A negative offset will allow tweens to overlap.

//this tween will directly after all previous tweens have finished
 tl.append( TweenLite.to( mc, 1, {x:100} ) );
<pre>//this tween will play 1 second before all previous tweens have finished
 tl.append( TweenLite.to( mc, 1, {x:100} ), -1 );

prepend() – Adds tweens to the beginning of a timeline and pushes all existing tweens forward in time.

//this tween occur before any other tweens that exist in the timeline
 tl.prepend( TweenLite.to( mc, 1, {x:100} ) );

TimelineLite Basic Properties

The following properties are very useful for adding functionality to your timelines and for debugging:

  • timeScale – Multiplier describing the speed of the timeline where 1 is normal speed, 0.5 is half-speed, 2 is double speed, etc.
  • currentProgress – Value between 0 and 1 indicating the progress of the timeline according to its duration where 0 is at the beginning, 0.5 is halfway finished, and 1 is finished.
  • duration – Duration of the timeline in seconds

TimelineLite Special Properties

When constructing a TimelineLite you can pass a number of "special properties" into the constructor. The video demonstates onUpdate, onComplete, and paused. The special properties are all contained in a vars object.

//this timeline will be paused initially and when it is done
//it will call a function called completeHandler
tl = new TimelineLite( {onComplete:completeHandler, paused:true} );

TimelineLite has many more methods, properties and “special properties” which are too numerous to list here. I urge you to investigate all there is to offer in the Official TimelineLite Documentation. The ones listed above are the most important to understand when getting started. As this series progresses I will be introducing more of the tools you will be using to gain advanced control over the setup and playback of your animation sequences.

The next video in this series will focus on controlling a TimelineLite while it is playing. It will cover everything from basic play() and reverse() to adding an interactive scrubber control.


TimelineLite Code Sample

Below is a sample of the code used in the video to illustrate the basic structure of a TimelineLite.

			//constructor
			tl = new TimelineLite();

			//tweens that introduce car.
			//insert() puts them all at a time of 0 seconds
			tl.insert( TweenMax.from(gti_mc, .5, {x:-500, blurFilter:{blurX:140}}) );
			tl.insert( TweenLite.from(gti_mc.wheel1_mc, .5, {rotation:-180}) );
			tl.insert( TweenLite.from(gti_mc.wheel2_mc, .5, {rotation:-180}) );

			//append() adds tweens relative to the end of the timeline
			//.5 seconds after previous tweens end this text will show for 1 second and then fade out
			tl.append( TweenMax.from(hello_mc, .5, {alpha:0, repeat:1, repeatDelay:1, yoyo:true}) ,.5);

			//introduce second text .5 seconds after previous tween ends
			tl.append( TweenMax.from( colors_mc, .5, {alpha:0}), .5 );

			//tint sequence
			tl.append( TweenMax.to( gti_mc.body_mc, .2, {tint:blue}) , .5);
			tl.append( TweenMax.to( gti_mc.body_mc, .2, {tint:red}) , .5);
			tl.append( TweenMax.to( gti_mc.body_mc, .2, {tint:black}) , .5);

			//last text
			tl.append( TweenMax.from( black_mc, .5, {alpha:0}), 1 );

			//optional: inserts black box reveal at the beginning of the timeline
			tl.prepend( TweenLite.from ( cover_mc, .5, {y:0}) );



View full post on Activetuts+

Apr 24, 2011 Posted on Apr 24, 2011 in Hints and Tips | 10 comments

Create a Basic Drawing Application in Flash

Twice a month, we revisit some of our readers’ favorite posts from throughout the history of Activetuts+. This tutorial was first published in August, 2009.

In this tutorial, we’ll create a Drawing Application with basic functions and an easy to use interface. Feeling artistic? Then let’s go..


Step 1: Overview

This application will feature a series of tools such as pencil, eraser, text tool, and also the possibility to save your drawing in png format using the Adobe’s PNG Encoder.


Step 2: Setting Up

Open Flash and create a new Flash File (ActionScript 3).

Set the stage size to 600x350px and the frame rate to 25fps.

””

Step 3: Board

Draw a 600x290px white rectangle and convert it to MovieClip. Set its instance name to "board" and align it to the top-left of the stage.

This will be the area on which we’ll be able to draw.


Step 4: Tools Panel

Create a 600px wide 60px high gray (#DFDFDF) rectangle and align it to the bottom of the stage. This will be our background for the Tools Panel.


Step 5: Tool Icons

I’m not going to cover the creation of the tools icons since that isn’t the intention of the turorial, still, you can see how they are made in the Fla file included in the Source.

As you can see in the image, we’re going to use two icons, one in a gray tone and the other one in color.

Convert the gray pencil icon to a Button (F8) and name it "pencilTool", double click to edit it and add a KeyFrame (F6) in the "over" state. Here’s where we’re going to put the color version of the icon.

Lastly, add another KeyFrame in the "hit" state, and draw a 30x30px square to act as the button’s hit area.

Repeat this process with all your tool icons, don’t forget to give them the correct instance names (eraserTool, textTool, saveButton, clearTool).

In order to display the active tool icon, we’re going to use the color version of the icon and place it in the same position of the button we created before. The instance names will be "pencil", "eraser" and "text".

We’ll hide these icons later using ActionScript.


Step 6: Save Dialog

When we use the save option we’re going to display a "save successful" message.

Create a 600x350px black rectangle with 50% alpha to use as a background.

Add a black rounded rectangle in the center with the save button icon and some text indicating that the save has been completed.

Create a close button and align it in the top-left of the rounded rectangle, name it "closeBtn". As you can imagine, this button will close the Save Dialog.

Convert all the elements to a single MovieClip and mark the "Export for ActionScript" checkbox. Set the Class textfield to "SaveDialog".

We’ll instantiate this class when the user presses the SaveButton and the save is completed.


Step 7: Size Panel

The Size Panel is the area where you can change the size of the pencil, eraser and text tool. You can do that by clicking in the panel area or the oval inside it.

Select the Rectangle Primitive Tool, set the corner radius to 4 and create a #EFEFEF 80x50px rectangle. Convert it to a MovieClip and name it "sizePanel".

Open the Filters panel and add a Drop Shadow with the following values:

Now use the Oval Tool to create a 5x5px black circle and center it in the Size Panel, convert it to MovieClip and set its instance name to "shapeSize".


Step 8: Default Colors

We’ll create a default color palette instead of using the Color Picker Component.

Create a 22x22px circle using the Oval Tool, set its color to #EEEEEE and convert it to MovieClip. Add the same Drop Shadow Filter we used in the Size Panel.

Draw a second circle of 16x16px and use black for the color this time. Center the circles and repeat this process changing the last circle color to the following:

Align them to end up with something like this:

Convert all the colors to a single MovieClip, name it "colors" and be sure to set the Registration Point to the Top-Left, since we’re going to get pixel data using the Bitmap Class.


Step 9: Adobe PNG Encoder

In order to use the Save function we’ll need the Adobe PNG Encoder wich is part of the as3corelib that you can find in Google Code.

To use this class outside of the package it comes with as default, we need to change one line. Open the PNGEncoder.as file and change the line "package com.adobe…" to just "package". This will let us call the class in the directory where the Fla file is.


Step 10: Main Class

A single Class will handle this application. Open the Properties Panel in the Fla file and set the Document Class as "Main".

Create a new ActionScript Document and save it as "Main.as" in the same directory where the Fla file is.


Step 11: Import Required Classes

These are the classes we’re going to need in this app. Remember to check the Flash Help (F1) if you’re unsure of a specific class.

package
{
	import PNGEncoder;
	import flash.display.MovieClip;
	import flash.display.Shape;
	import flash.display.DisplayObject;
	import flash.text.TextField;
	import flash.text.TextFormat;
	import flash.text.TextFieldType;
	import flash.text.TextFieldAutoSize;
	import flash.display.BitmapData;
	import flash.geom.ColorTransform;
	import flash.events.MouseEvent;
	import flash.events.Event;
	import flash.utils.ByteArray;
	import flash.net.FileReference;

Step 12: Extending the Class

We’re extending the MovieClip class since we use this class’ specific properties and methods.

public class Main extends MovieClip
{

Step 13: Variables

These are the variables we’ll use. They’re all explained in the code comments.

/* Pencil Tool shape, everything drawn with this tool and the eraser tool is stored inside board.pencilDraw */

var pencilDraw:Shape = new Shape();

/* Text format */

var textformat:TextFormat = new TextFormat();

/* Colors */

var colorsBmd:BitmapData; //We'll use this Bitmap Data to get the pixel RGB Value when clicked
var pixelValue:uint;
var activeColor:uint = 0x000000; //This is the current color in use, displayed by the shapeSize MC

/* Save dialog instance */

var saveDialog:SaveDialog;

/* Active var, to check which tool is active */

var active:String;

/* Shape size color */

var ct:ColorTransform = new ColorTransform();

Step 14: Main Function

The main function will take care of setting the Text Format of the Text Tool, converting the Colors MovieClip to Bitmap Data so we can extract the Pixels RGB Value, adding the listeners and hiding the active icons.

public function Main():void
{
	textformat.font = "Quicksand Bold Regular"; // You can use any font you like
	textformat.bold = true;
	textformat.size = 16;

   /* We create these functions later */

	convertToBMD();

	addListeners();

	/* Hide tools highlights */

	pencil.visible = false;
	hideTools(eraser, txt);
}

Step 15: Tools Actions

The tools actions are each split into four functions.

The first one will set the tool to its Active state, the second and third ones will handle the Mouse Events (like Drawing or Erasing) and the fourth one will stop those Events.


Step 16: Pencil Tool

These functions handle the Pencil Tool, read the comments in the code for a better understanding.

The set to active function:

private function PencilTool(e:MouseEvent):void
{
	/* Quit active tool */

	quitActiveTool(); //This function will be created later

	/* Set to Active */

	active = &quot;Pencil&quot;; //Sets the active variable to &quot;Pencil&quot;

	/* Adds the listeners to the board MovieClip, to draw just in it */

	board.addEventListener(MouseEvent.MOUSE_DOWN, startPencilTool);
	board.addEventListener(MouseEvent.MOUSE_UP, stopPencilTool);

	/* Highlight, sets the Pencil Tool Icon to the color version, and hides any other tool */

	highlightTool(pencil);
	hideTools(eraser, txt);

   /* Sets the active color variable based on the Color Transform value and uses that color for the shapeSize MovieClip */

	ct.color = activeColor;
	shapeSize.transform.colorTransform = ct;
}

The Start function; this function is called when the Board MovieClip is pressed.

private function startPencilTool(e:MouseEvent):void
{
	pencilDraw = new Shape(); //We add a new shape to draw always in top (in case of text, or eraser drawings)
	board.addChild(pencilDraw); //Add that shape to the board MovieClip

	pencilDraw.graphics.moveTo(mouseX, mouseY); //Moves the Drawing Position to the Mouse Position
	pencilDraw.graphics.lineStyle(shapeSize.width, activeColor);//Sets the line thickness to the ShapeSize MovieClip size and sets its color to the current active color

	board.addEventListener(MouseEvent.MOUSE_MOVE, drawPencilTool); //Adds a listener to the next function
}

The Draw function; called when the user presses the Board MovieClip and moves the mouse.

private function drawPencilTool(e:MouseEvent):void
{
	pencilDraw.graphics.lineTo(mouseX, mouseY); //Draws a line from the current Mouse position to the moved Mouse position
}

Stop function, executed when the user releases the mouse.

private function stopPencilTool(e:MouseEvent):void
{
	board.removeEventListener(MouseEvent.MOUSE_MOVE, drawPencilTool); //Stops the drawing
}

Step 17: Eraser Tool

The Eraser Tool is pretty much the same as the Pencil Tool, except that we don’t use any color other than White.

private function EraserTool(e:MouseEvent):void
{
	/* Quit active tool */

	quitActiveTool();

	/* Set to Active */

	active = "Eraser";

	/* Listeners */

	board.addEventListener(MouseEvent.MOUSE_DOWN, startEraserTool);
	board.addEventListener(MouseEvent.MOUSE_UP, stopEraserTool);

	/* Highlight */

	highlightTool(eraser);
	hideTools(pencil, txt);

   /* Use White Color */

	ct.color = 0x000000;

	shapeSize.transform.colorTransform = ct;
}

private function startEraserTool(e:MouseEvent):void
{
	pencilDraw = new Shape();
	board.addChild(pencilDraw);

	pencilDraw.graphics.moveTo(mouseX, mouseY);
	pencilDraw.graphics.lineStyle(shapeSize.width, 0xFFFFFF); //White Color

	board.addEventListener(MouseEvent.MOUSE_MOVE, drawEraserTool);
}

private function drawEraserTool(e:MouseEvent):void
{
	pencilDraw.graphics.lineTo(mouseX, mouseY);
}

function stopEraserTool(e:MouseEvent):void
{
	board.removeEventListener(MouseEvent.MOUSE_MOVE, drawEraserTool);

}   

As you can see, the code is the same except for the White color changes.


Step 18: Text Tool

The Text Tool has only two functions; one in charge of setting it to active, and the other one for handling the text writing. Let’s take a look:

private function TextTool(e:MouseEvent):void
{
	/* Quit active tool */

	quitActiveTool();

	/* Set to Active */

	active = "Text";

	/* Listener */

	board.addEventListener(MouseEvent.MOUSE_UP, writeText);

	/* Highlight */

	highlightTool(txt);
	hideTools(pencil, eraser);
}

private function writeText(e:MouseEvent):void
{
   /* Create a new TextField Object, this way we won't replace older instances */

	var textfield = new TextField();

	/* Set Formats, position, and focus */

	textfield.type = TextFieldType.INPUT;
	textfield.autoSize = TextFieldAutoSize.LEFT;
	textfield.defaultTextFormat = textformat;
	textfield.textColor = activeColor;
	textfield.x = mouseX;
	textfield.y = mouseY;
	stage.focus = textfield;

	/* Add text to Board */

	board.addChild(textfield);
}

This one was easy, remember that you can change the size and color using the shapeSize and the Colors MovieClips.


Step 19: Save Option

The save option handled by the saveButton will make use of the Adobe’s PNGEnconder Class to save the artwork as a PNG file.

private function export():void
{
	var bmd:BitmapData = new BitmapData(600, 290);//Creates a new BitmapData with the board size

	bmd.draw(board);//Draws the board MovieClip into a BitmapImage in the BitmapData

	var ba:ByteArray = PNGEncoder.encode(bmd); //Creates a ByteArray of the BitmapData, encoded as PNG

	var file:FileReference = new FileReference(); // Instantiates a new File Reference Object to handle the save

	file.addEventListener(Event.COMPLETE, saveSuccessful); //Adds a new listener to listen when the save is complete

	file.save(ba, "MyDrawing.png"); //Saves the ByteArray as a PNG
}

private function saveSuccessful(e:Event):void
{
	saveDialog = new SaveDialog();// Instantiates a new SaveDialog Class

	addChild(saveDialog); //Adds the SaveDialog MovieClip to the Stage

	saveDialog.closeBtn.addEventListener(MouseEvent.MOUSE_UP, closeSaveDialog);//Adds a listener to the close button of the dialog
}

private function closeSaveDialog(e:MouseEvent):void
{
	removeChild(saveDialog); //Removes the dialog of the Stage
}

private function save(e:MouseEvent):void
{
	export(); //Calls the export function to begin the saving process
}

Step 20: Clear Tool

The Clear Tool will add a white screen in front of all the elements in order to leave the board ready to draw again.

private function clearBoard(e:MouseEvent):void
{
	/* Create a white rectangle on top of everything */

	var blank:Shape = new Shape();

	blank.graphics.beginFill(0xFFFFFF);
	blank.graphics.drawRect(0, 0, board.width, board.height);
	blank.graphics.endFill();

	board.addChild(blank);
}

Step 21: Get Colors Value

To get the value of the colors we’re using in the Colors MovieClip, we convert it to a BitmapData Object and use the getPixel method to obtain the RGB value of the pixel clicked.

private function convertToBMD():void
{
	colorsBmd = new BitmapData(colors.width,colors.height);
	colorsBmd.draw(colors);
}

private function chooseColor(e:MouseEvent):void
{
	pixelValue = colorsBmd.getPixel(colors.mouseX,colors.mouseY);//Gets the cliked pixel RGB value
	activeColor = pixelValue;

  /* Use a ColorTransform object to change the shapeSize MovieClip color */

	ct.color = activeColor;
	shapeSize.transform.colorTransform = ct;
}

We’ll add the chooseColor listener in the addListeners function later in the code.


Step 22: Active Tool

Earlier, we declared a variable to set the active or current tool in use, and we call this function to remove the corresponding listeners in order to have just one active tool.

Basically, the function checks the "active" variable in a switch loop, then depending on its value removes the listeners it has.

private function quitActiveTool():void
{
	switch (active)
	{
		case "Pencil" :
			board.removeEventListener(MouseEvent.MOUSE_DOWN, startPencilTool);
			board.removeEventListener(MouseEvent.MOUSE_UP, stopPencilTool);
		case "Eraser" :
			board.removeEventListener(MouseEvent.MOUSE_DOWN, startEraserTool);
			board.removeEventListener(MouseEvent.MOUSE_UP, stopEraserTool);
		case "Text" :
			board.removeEventListener(MouseEvent.MOUSE_UP, writeText);
		default :
	}
}

We also need to highlight the active tool and hide the other ones:

private function highlightTool(tool:DisplayObject):void
{
	tool.visible=true; //Highlights tool in the parameter
}

/* Hides the tools in the parameters */

private function hideTools(tool1:DisplayObject, tool2:DisplayObject):void
{
	tool1.visible=false;
	tool2.visible=false;
}

Step 23: Shape Size

We click the Size Panel or the ShapeSize MovieClip to change the size of the Pencil, Eraser and Text Tool. The size is changed in intervals of 5, and is reset when the size is bigger or equal to 50. Take a look at the code:

private function changeShapeSize(e:MouseEvent):void
{
	if (shapeSize.width >= 50)
	{
		shapeSize.width = 1;
		shapeSize.height = 1;

		/* TextFormat */

		textformat.size = 16;
	}
	else
	{
		shapeSize.width += 5;
		shapeSize.height=shapeSize.width;

		/* TextFormat */

		textformat.size+=5;
	}
}

Step 24: Add Listeners

A function to add all the listeners.

private function addListeners():void
{
	pencilTool.addEventListener(MouseEvent.MOUSE_UP, PencilTool);
	eraserTool.addEventListener(MouseEvent.MOUSE_UP, EraserTool);
	textTool.addEventListener(MouseEvent.MOUSE_UP, TextTool);
	saveButton.addEventListener(MouseEvent.MOUSE_UP, save);
	clearTool.addEventListener(MouseEvent.MOUSE_UP, clearBoard);
	colors.addEventListener(MouseEvent.MOUSE_UP, chooseColor);
	sizePanel.addEventListener(MouseEvent.MOUSE_UP, changeShapeSize);
	shapeSize.addEventListener(MouseEvent.MOUSE_UP, changeShapeSize);
}

Step 25: Test

Test your app by pressing cmd+return and check if everything is working as expected.

Use all the tools, colors and functions and start drawing your scene!


Conclusion

This Flash Movie can be easily adapted as a kids drawing application, it has a friendly user interface and basic tools that can teach how the mouse works whilst having some colorful fun in the process.

You can also explore the rest of the as3corelib and read its documentation to learn some new ActionScript features.

Thanks for reading!



View full post on Activetuts+

Feb 18, 2011 Posted on Feb 18, 2011 in Hints and Tips | 0 comments

Getting Started with Strobe Media Playback: Basic Configuration

This entry is part 1 of 1 in the series Getting Started with Strobe Media Playback

Strobe Media Playback is the open source video playback module that provides not only a customizable video playback solution for developers, but also serves as a great entry point for developing applications with the Open Source Media Framework.

In this tutorial, we will see an example of how to configure SMB by using the built-in skinning configuration mechanisms and creating our custom skin with Adobe Fireworks.


Watch the Screencast

Don’t like ads? Download the HD 720 screencast, or subscribe to Activetuts+ screencasts via iTunes!



View full post on Activetuts+

Jan 3, 2011 Posted on Jan 3, 2011 in Flash Video Training | 1 comment

Create a Flash button (basic)


in this tutorial you will learn how to create a basic button

Page 1 of 41234»
search search search search search
Find an Article
Categories
  • Flash Video Training
  • Hints and Tips
  • Recommended
Please Support Our Sponsors
Recent Posts
  • Tuts+ Community Meetup in New York!
  • HTML5 Canvas Optimization: A Practical Example
  • Recreate the Cover Flow Effect Using Flash and AS3
  • Drawing Activetuts+ to a Close
  • Intro to Dart: Creating a Marquee
Tag Cloud
2011 ActionScript Active Activetuts+ Adobe animation Basic Basix Best Build Button Character Code Create Creating Critique Custom design Effect Effects Files Flash from Game Guide HTML5 Introduction Macromedia Motion Muzzle part Player Premium Professional Quick Silverlight Simple Text Tool Tutorial Tuts+ Using Video website Workshop
About Our Site:

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!

Go Back In Time
May 2013
M T W T F S S
« Jul    
 12345
6789101112
13141516171819
20212223242526
2728293031  
Pretty Blank Box
top

Blogroll

  • Development Blog
  • Documentation
  • Plugins
  • Suggest Ideas
  • Support Forum
  • Themes
  • WordPress Planet

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Archives

  • July 2012
  • June 2012
  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • November 2011
  • October 2011
  • September 2011
  • August 2011
  • July 2011
  • June 2011
  • May 2011
  • April 2011
  • March 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • August 2010
  • July 2010
  • June 2010
  • May 2010
  • April 2010
Powered by WordPress  |  Designed by Elegant Themes  |  Lightning Fast Hosting by Site 5 Hosting