Flash game creation tutorial – part 5.2

Read all posts about "" game

March 14th update: part 5.3 released.

Now we will discuss about code optimization (the boring – but very important – part) and some visual tricks to make the game look better, and some more issues.

Code optimization

In tutorials 1 to 5.1, I always include the ball actionscript in the ball object. This is correct, but it might create confusion when you have to deal with a lot of objects.

You just can’t remember where did you put that piece of code. Imagine to pick up a game coded in this way after some weeks… would you really remember where did you put that collision script?

So, we will learn how to put all the code in a single frame.

Example 1: the ball

This is the same movie seen in the “No walls and speed limit” example covered in tutorial 5.1.

This time, as said, there is no actionscript in the objects, just the main script in frame 1

_root.attachMovie("hero", "hero_on_stage", 10000, {_x:200,_y:20});
power = 0.65;
yspeed = 0;
xspeed = 0;
wind = 0.00;
gravity = 0.1;
upconstant = 0.75;
friction = 0.99;
hero_on_stage.onEnterFrame = function() {
	if (Key.isDown(Key.LEFT)) {
		xspeed = xspeed-power;
	}
	if (Key.isDown(Key.RIGHT)) {
		xspeed = xspeed+power;
	}
	if (Key.isDown(Key.UP)) {
		yspeed = yspeed-power*upconstant;
	}
	if (Key.isDown(Key.DOWN)) {
		yspeed = yspeed+power*upconstant;
	}
	xspeed = (xspeed+wind)*friction;
	yspeed = yspeed+gravity;
	if (xspeed>15) {
		xspeed = 15;
	}
	if (xspeed<-15) {
		xspeed = -15;
	}
	if (this.yspeed>15) {
		this.yspeed = 15;
	}
	if (yspeed<-15) {
		yspeed = -15;
	}
	this._y += yspeed;
	this._x += xspeed;
	if (this._x<0) {
		this._x += 500;
	}
	if (this._y<0) {
		this._y += 350;
	}
	if (this._y>350) {
		this._y -= 350;
	}
	if (this._x>500) {
		this._x -= 500;
	}
	this._rotation = this._rotation+xspeed;
};

Let’s see the script:

Line 1: I attach the movie “hero” (the ball) on the stage and call it as “hero_on_stage” (this will be the instance name). The 10000 is the depth of the movie. An object with a higher depth than another will appear “in front” of it. Just imagine that an object with an higher depth is on an higher layer. The {_x:200,_y:20} means that the _x value is set to 200 and the _y to 20. Basically, this line acts like I took the hero from the library panel, instanced as “hero_on_stage” and position it to 200,20

Lines 2-8: Here I put the declarations previously included in the onClipEvent (load)

Line 9: The main loop previously called onClipEvent (enterFrame) now is called in this way.

The other lines work in the same way as in the previous example. Just notice that all attributes like _x, _y, _rotation are defined using this._x, this._y, this._rotation…

Example 2: The scrolling

To optimize the scrolling example seen in tutorial 5.1 we are using the same technique: one single actionscript in the first frame.

_root.attachMovie("kira", "kira", 8000, {_x:234, _y:159});
_root.attachMovie("wall", "wall", 10000, {_x:240, _y:0, _width:5700, _height:5700});
yspeed = 0;
xspeed = 0;
wind = 0.00;
power = 0.65;
gravity = 0.1;
upconstant = 0.75;
friction = 0.99;
kira.onEnterFrame = function() {
	if (Key.isDown(Key.LEFT)) {
		xspeed = xspeed-power;
	}
	if (Key.isDown(Key.RIGHT)) {
		xspeed = xspeed+power;
	}
	if (Key.isDown(Key.UP)) {
		yspeed = yspeed-power*upconstant;
	}
	if (Key.isDown(Key.DOWN)) {
		yspeed = yspeed+power*upconstant;
	}
	xspeed = (xspeed+wind)*friction;
	yspeed = yspeed+gravity;
	if (xspeed>0) {
		this.kira.gotoAndStop(1);
	} else {
		this.kira.gotoAndStop(2);
	}
	_root.wall._y -= yspeed;
	_root.wall._x -= xspeed;
	if (_root.wall.hitTest(this._x, this._y, true)) {
		xspeed = 0;
		yspeed = 0;
		_root.wall._x = 240;
		_root.wall._y = 0;
	}
};

The theory is the same of the previous example, just notice lines 25-29 that makes the player (kira) face left if she is going to the left, and right if she is going to the right. How can I did it? Simply inserting two frames in the kira object, one with kira facing left, one with kira facing right.

And that’s where the boring part ends.

Now…

Eye Candy 1: Trails

Even if you may think a flash game can be funny even with simple graphics, you should improve the visual appeal as much as you can. Let’s see some tricks.

We will have our ball leaving a trail when it moves. In a very simple way.

First, you need to create a new movieclip with a shape on it, then you have to create another new movieclip with the previously created movieclip in it.

This way:

(never mind if you should find it a bit unclear, you will find all source codes at the end of the tutorial)

1: The shape itself: a red circle with a blue border

2: The movieclip where we draw the shape

3: Another movieclip, with the movieclip seen at 2 inside of it

4: Look how I instanced the movieclips

And now the actionscript:

_root.attachMovie("hero", "hero_on_stage", 10000,{_x:200,_y:20});
_root.attachMovie("trail_sprite", "trail_mc", 8000);
trailbitmap = new flash.display.BitmapData(500, 350, true,0x000000);
_root.createEmptyMovieClip("trail", 1);
trail.attachBitmap(trailbitmap, 0);
trail_mc._visible = false;
power = 0.65;
yspeed = 0;
xspeed = 0;
wind = 0.00;
gravity = 0.1;
upconstant = 0.75;
friction = 0.99;

hero_on_stage.onEnterFrame = function() {
	if (Key.isDown(Key.LEFT)) {
		xspeed = xspeed-power;
	}
	if (Key.isDown(Key.RIGHT)) {
		xspeed = xspeed+power;
	}
	if (Key.isDown(Key.UP)) {
		yspeed = yspeed-power*upconstant;
	}
	if (Key.isDown(Key.DOWN)) {
		yspeed = yspeed+power*upconstant;
	}
	xspeed = (xspeed+wind)*friction;
	yspeed = yspeed+gravity;
	if (xspeed>15) {
		xspeed = 15;
	}
	if (xspeed<-15) {
		xspeed = -15;
	}
	if (yspeed>15) {
		yspeed = 15;
	}
	if (yspeed<-15) {
		yspeed = -15;
	}
	this._y += yspeed;
	this._x += xspeed;
	if (this._x<0) {
		this._x += 500;
	}
	if (this._y<0) {
		this._y += 350;
	}
	if (this._y>350) {
		this._y -= 350;
	}
	if (this._x>500) {
		this._x -= 500;
	}
	this._rotation = this._rotation+xspeed;
	_root.trail_mc.trail_sprite._x = this._x;
	_root.trail_mc.trail_sprite._y = this._y;
	_root.trailbitmap.draw(_root.trail_mc);
	trail_rectangle = new flash.geom.Rectangle(0, 0, 500, 350);
	trail_blur = new flash.filters.BlurFilter(2, 2, 3);
	_root.trailbitmap.applyFilter(_root.trailbitmap, trail_rectangle, new Point(0, 0), trail_blur);
};

Line 2: I attach the trail_sprite object (the one containing the movieclip with the shape) on a depth lesser than the hero’s one (it will be behind the ball)

Line 3: I create a new BitmapData object called trailbitmap.

What is a BitmapData?

From macromedia livedocs: The BitmapData class lets you create arbitrarily sized transparent or opaque bitmap images and manipulate them in various ways at runtime. This class lets you separate bitmap rendering operations from the Flash Player internal display updating routines. By manipulating a BitmapData object directly, you can create very complex images without incurring the per-frame overhead of constantly redrawing the content from vector data.

Basically, the bitmap data is a “field” where we can apply various visual effects.

It is declared in this way:

BitmapData(width:Number, height:Number, [transparent:Boolean], [fillColor:Number])

So my BitmapData has a width of 500 (same of the movie), height of 350 (same of the movie), and it’s transparent. The fourth parameter, the fillcolor, is not so important since it’s transparent.

Line 4: I create an empty movieclip (a new one) called “trail” at depth 1 (behind the other ones)

Line 5: In this trail movieclip I attach the BitmapData previously created

Line 6: I set the trail_mc clip to invisible. I mean I do not want to see the trail_mc clip, I only want to see its effects on the BitmapData

The other lines are the same seen in previous examples until…

Lines 57-58: I set the _x and _y of the trail_sprite movieclip inside the trail_mc movieclip to the same values of hero’s _x and _y. I mean that I am moving the shape movieclip inside the trail_mc movieclip that is the one containing the movieclip with the shape. Don’t worry if you think you can’t understand it… we will discuss about it in other tutorials.

Line 59: I draw the trail_mc movieclip (with its inner movieclip updated) inside the BitmapData object

Line 60: I define a rectangle starting at (0,0) with width = 500 and height = 350. This is the rectangle where we are going to create the special effect.

Line 61: Defining a blur filter. This filter has 3 parameters: The amount of horizontal blur (set to 2, I noticed it works better with multiples of 2), the amount of vertical blur (same thing) and the number of times to perform the blur (when it’is set to 1, the result is a softly unfocused look, when it’s set to 3, it approximates a Gaussian blur filter)

Line 62: The effect is applyed. It’s easier than it may seem, I am considering about creating a complete tutorial about it anyway.

Eye Candy 2: Explosions

If in the previous example we had a trail, in this one we will consider an explosion.

Let’s apply the same theory to the tunnel game:

_root.attachMovie("kira", "kira", 8000, {_x:234, _y:159});
_root.attachMovie("wall", "wall", 10000, {_x:240, _y:0, _width:5700, _height:5700});
_root.attachMovie("trail_sprite", "trail_mc", 4000);
trailbitmap = new flash.display.BitmapData(500, 350, true, 0x000000);
_root.createEmptyMovieClip("trail", 1);
trail.attachBitmap(trailbitmap, 0);
trail_mc._visible = false;
yspeed = 0;
xspeed = 0;
wind = 0.00;
power = 0.65;
gravity = 0.1;
upconstant = 0.75;
friction = 0.99;
die = 0;
kira.onEnterFrame = function() {
	if (Key.isDown(Key.LEFT)) {
		xspeed = xspeed-power;
	}
	if (Key.isDown(Key.RIGHT)) {
		xspeed = xspeed+power;
	}
	if (Key.isDown(Key.UP)) {
		yspeed = yspeed-power*upconstant;
	}
	if (Key.isDown(Key.DOWN)) {
		yspeed = yspeed+power*upconstant;
	}
	if (!die) {
		xspeed = (xspeed+wind)*friction;
		yspeed = yspeed+gravity;
	}
	if (xspeed>0) {
		this.kira.gotoAndStop(1);
	} else {
		this.kira.gotoAndStop(2);
	}
	_root.wall._y -= yspeed;
	_root.wall._x -= xspeed;
	if (_root.wall.hitTest(this._x, this._y, true)) {
		if (die<100) {
			xspeed = 0;
			yspeed = 0;
			_root.trail_mc.explosion._x = this._x;
			_root.trail_mc.explosion._y = this._y;
			_root.trail_mc.explosion.gotoAndPlay(die*2+1);
			this._alpha = 0;
			_root.trailbitmap.draw(_root.trail_mc);
			trail_rectangle = new flash.geom.Rectangle(0, 0, 500, 350);
			trail_blur = new flash.filters.BlurFilter(2, 2, 3);
			_root.trailbitmap.applyFilter(_root.trailbitmap, trail_rectangle, new Point(0, 0), trail_blur);
			die+=0.5;
		} else {
			die = 0;
			xspeed = 0;
			yspeed = 0;
			this._alpha = 100;
			_root.wall._x = 240;
			_root.wall._y = 0;
		}
	}
};

Line 15: A new variable called die. It will states if the player... died...

Lines 29-32: xspeed and yspeed are updated only if the player didn't die.

Line 41: Things to do if the player hit the wall and die < 100 Line 46: Tell the explosion movieclip (the "trail_sprite" in the previous example) to goto and play frame die*2+1. Now we have no more a shape but an explosion movieclip to be blurred

Line 47: Set the player alpha to 0 (to "remove" the bubble from stage)

Line 52: Increment die by 0.5. In this way we will remain inside this loop until die < 100... 200 frames or so. Lines 52-60: Things to do if die >=100 (the player died some frames ago): set the _alpha to 100 (return visible), set die to 0 again and reset wall _x and _y and speed.

Now that some visual effects are done, it's time to...

Adding sound

In this example we want to add a sound effect to our explosion.

First, you must import the sound in the library and instance it. When you have a linkage, the actionscript is very simple:

_root.attachMovie("kira", "kira", 8000, {_x:234, _y:159});
_root.attachMovie("wall", "wall", 10000, {_x:240, _y:0, _width:5700, _height:5700});
_root.attachMovie("trail_sprite", "trail_mc", 4000);
trailbitmap = new flash.display.BitmapData(500, 350, true, 0x000000);
_root.createEmptyMovieClip("trail", 1);
trail.attachBitmap(trailbitmap, 0);
trail_mc._visible = false;
exp_sound = new Sound();
exp_sound.attachSound("boom");
yspeed = 0;
xspeed = 0;
wind = 0.00;
power = 0.65;
gravity = 0.1;
upconstant = 0.75;
friction = 0.99;
die = 0;
kira.onEnterFrame = function() {
	if (Key.isDown(Key.LEFT)) {
		xspeed = xspeed-power;
	}
	if (Key.isDown(Key.RIGHT)) {
		xspeed = xspeed+power;
	}
	if (Key.isDown(Key.UP)) {
		yspeed = yspeed-power*upconstant;
	}
	if (Key.isDown(Key.DOWN)) {
		yspeed = yspeed+power*upconstant;
	}
	if (!die) {
		xspeed = (xspeed+wind)*friction;
		yspeed = yspeed+gravity;
	}
	if (xspeed>0) {
		this.kira.gotoAndStop(1);
	} else {
		this.kira.gotoAndStop(2);
	}
	_root.wall._y -= yspeed;
	_root.wall._x -= xspeed;
	if (_root.wall.hitTest(this._x, this._y, true)) {
		if (!die) {
			exp_sound.start();
		}
		if (die<100) {
			xspeed = 0;
			yspeed = 0;
			_root.trail_mc.explosion._x = this._x;
			_root.trail_mc.explosion._y = this._y;
			_root.trail_mc.explosion.gotoAndPlay(die*2+1);
			this._alpha = 0;
			_root.trailbitmap.draw(_root.trail_mc);
			trail_rectangle = new flash.geom.Rectangle(0, 0, 500, 350);
			trail_blur = new flash.filters.BlurFilter(2, 2, 3);
			_root.trailbitmap.applyFilter(_root.trailbitmap, trail_rectangle, new Point(0, 0), trail_blur);
			die += 0.5;
		} else {
			die = 0;
			xspeed = 0;
			yspeed = 0;
			this._alpha = 100;
			_root.wall._x = 240;
			_root.wall._y = 0;
		}
	}
};

Line 8: Defines a variable (exp_sound) for a new sound

Line 9: Attaching the sound. In this case, boom is the linkage name of the sound

Lines 43-45: When the collision is checked and die is equal to 0 (it's the first frame where we are checking the collision), play the sound.

Now download the source code of all examples, give me feedback and proceed to part 5.3

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

214 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers