Porting a simple Flash game to Tizen

Introduction

This article describes how to port an existing flash game, written in the Actionscript 3.0 language, to JavaScript on a Tizen mobile device. There are many topics involved in porting such a game from one language to the other. We will show you only the most important guidelines that are crucial to port a game from Flash to Tizen. The rest can be found directly in the attached example applications – basketgame.wgt (for Tizen) and basketgame.swf for (Flash). The Tizen sample application has been created and tested on the Tizen SDK 2.3. The Flash application has been created using the Adobe Flash CS6 and with the FlashDevelop programming IDE. Please download both applications (figure 1) and examine their code carefully.

 

Figure 1 – preview of both the basketgame.wgt (left) and basketgame.swf (right) sample game applications

 

First sight similarities and differences

The first thing is to show what is similar between Tizen and Flash and on the other hand show what is different while coding in both ecosystems. What is similar for sure is that both JavaScript and Actionscript 3.0 languages have the same origin – the ECMAScript language. That makes it quite easy to port the code between AS 3.0 and JS. But there are differences. Flash for example has emerged as a more graphical and animation tool in its beginnings. And then acquired a programming language in the toolset. From a developers' perspective what differs at first sight is that AS 3.0 has traditional – Java like classes which can be extended or that can implement interfaces. In JS we need to create classes by creating for example functions which will stand for our object classes. JavaScript in contrary to Actionscript 3.0, it is not a typed language by default. But the most important is that Flash has an easily manageable display list and objects called MovieClips, which are ideal for implementing animations. So all in all, both languages are very similar and at the same time are different in certain places. This can lead to simple, yet annoying mistakes in the porting process. That is why whenever you encounter an error while porting from AS 3.0 to JS, check everything many times. This can save you time. You can reduce the amount of time spent on debugging.

 

Let the porting begin!

So, what is the best way to start porting a Flash game to the Tizen platform? As said earlier, Flash has the advantage of using the display list with the MovieClip objects. JavaScript on the other hand does not have such helpful objects. But since many talented flash developers have migrated over the years to JavaScript programming, there showed up many libraries which imitate more or less the display list concept from flash. The one which does the best job (and has MovieClips) is the Pixi.js library, described earlier at developer.tizen.org. Not only it imitates the display list concept almost one to one, but gives you the ability to use the GPU acceleration for your games in 60 fps, through WebGL (like Stage3D does that for flash). The second library worth using when porting Flash games to Tizen is the TweenMax.js library. It gives you much flexibility in animating just anything through the JavaScript code. And it originated as a Flash library and after some years was ported to JS. Flash also has neat sound playing capabilities. The equivalent for that on the JavaScript side can be the buzz.js library. It is easy to use and implement and supports a variety of web sound formats. And you can use the font.js library to manage fonts easier in your projects. There is no way to embed fonts in JavaScript using the Flash like way. So you can use the @font-face to load up your custom fonts or the mentioned above font.js. It is a good habit when porting games from Flash to JavaScript to use a performance meter. It enables you to control the performance of your ported game. One of the simplest and best is the stats.js performance meter. Mostly because stats.js like TweenMax.js first originated on Flash and was ported later to JavaScript. After acknowledging those basic information please look on the source code of both sample applications in Tizen and Flash, attached to this article. It will be easier for you to go on with this article while comparing on the fly the code of JavaScript and Actionscript 3.0 of our sample Basket Game. As mentioned in the beginning of this article we will show you the crucial moments for a successful port of our Flash game to Tizen.

 

Crucial points

When opening the main.js file of the Tizen basketgame project you will first notice that all the graphical game assets are being loaded via the PIXI.AssetLoader(). You didn’t had to do that in Flash in most cases because you could just upload the necessary assets to the Flash IDE library with few mouse clicks, give them class names and you could easily instantiate complex animations with your code. On Tizen in JavaScript with Pixi.js we can either use texture atlases via the JSON format or use single graphical files through the asset loader.  To keep things simple, the second method was used in the basketgame.wgt example. What has also changed in comparison to flash is the way of how the classes look like. Let’s have a peek at a comparison of the Hero class both in Flash and in JavaScript. Both classes are presented here as an out of context overview just to show how a same class looks in JavaScript and Actionscript 3.0. To understand the inner workings of both classes you should work on the source code of the sample applications provided with this article.

 

The Flash Hero class (Actionscript 3.0):

[…]
 
package src.elements 
{
	import com.greensock.TweenMax;
	import flash.display.MovieClip;
	import flash.events.Event;
	
	public class Hero extends MovieClip
	{
		public var basket_hit_area:MovieClip;
		public var wasHit:Boolean = false;
		
		public function Hero() 
		{
			addEventListener(Event.ADDED_TO_STAGE, onStage);
		}
		
		private function onStage(e:Event):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, onStage);
			trace("HERO ADDED TO STAGE");
			setAnimation(0);
		}
		
		public function setAnimation(_animNum):void
		{
			switch(_animNum) {
				case 0: // FRONT
					 gotoAndStop("front");
				break;
				
				case 1: // LEFT
					 gotoAndStop("left");
				break;
				
				case 2: // RIGHT
					 gotoAndStop("right");
				break;
				
				case 3: // JUMP-FRONT
					 gotoAndStop("front_jump");
				break;
				
				case 4: // JUMP-LEFT
					 gotoAndStop("left_jump");
				break;
				
				case 5: // JUMP-RIGHT
					 gotoAndStop("right_jump");
				break;
			}
		}
		
		public function hitHero():void
		{
		wasHit = true;
		alpha = 0;
		TweenMax.to(this, 0.1, { alpha:1, yoyo:true, repeat:40, onComplete: resetHit } );
		}
		
		private function resetHit():void 
		{
			wasHit = false;
		}	
	}
}

[…]

 

The JavaScript (with Pixi.js add-ons) Hero class:

[…]
 
function Hero() {  // create our Hero class
    	 		
		var self = this;
		 		
		this.x = 0;
		this.y = 0;
		 		
		this.wasHit = false;
		 		
		this.CLIP_OFFSET = 33;
		 		
		this.container = new PIXI.DisplayObjectContainer();
		this.container.x = this.x;
		this.container.y = this.y;
		 		
		this.anim_walk_front = new PIXI.Sprite(textureAssets.wl_front);
		 		
		this.width = this.anim_walk_front.width;
		this.height = this.anim_walk_front.height;	
		 		
		this.anim_walk_left = new PIXI.MovieClip(animations.walk_left);
		this.anim_walk_left.animationSpeed = 0.1;
		this.anim_walk_left.loop = true
		this.anim_walk_left.x -= this.CLIP_OFFSET;
		this.anim_walk_left.stop();
		 		
		this.anim_walk_right = new PIXI.MovieClip(animations.walk_right);
		this.anim_walk_right.animationSpeed = 0.1;
		this.anim_walk_right.loop = true
		this.anim_walk_right.x += this.CLIP_OFFSET;
		this.anim_walk_right.stop();
		 			
		this.anim_jump_front = new PIXI.Sprite(textureAssets.j_front);
		 		
	        this.anim_jump_left = new PIXI.MovieClip(animations.jump_left);
		this.anim_jump_left.animationSpeed = 0.1;
		this.anim_jump_left.loop = true
		this.anim_jump_left.x -= this.CLIP_OFFSET;
		this.anim_jump_left.stop();
				
		this.anim_jump_right = new PIXI.MovieClip(animations.jump_right);	
		this.anim_jump_right.animationSpeed = 0.1;
		this.anim_jump_right.loop = true
		this.anim_jump_right.x += this.CLIP_OFFSET;
		this.anim_jump_right.stop();
		 		
		this.heroStateArray = [this.anim_walk_front, 
		 		       this.anim_walk_left,
		 		       this.anim_walk_right,
		 		       this.anim_jump_front,
		 		       this.anim_jump_left,
		 		       this.anim_jump_right]; 		
		 		
		// Add all hero states to our container
		   for (var i=0; i < this.heroStateArray.length; i++) {
		 	this.container.addChild(this.heroStateArray[i]);
		   }	
		 		
		 gameContainer.addChild(this.container);
		 		
		 this.hitHero = function()
		 {	
		        self.wasHit = true;
		 	self.container.alpha = 0;
			TweenMax.to(self.container, 0.1, { alpha:1, yoyo:true, repeat:40, onComplete: resetHit } );		
		 }
				
		 function resetHit()
		 {		
			self.wasHit = false;	
		 }
		 		
		 	
}
		 	
Hero.prototype.hideAllAnimationStates = function() 
{
	for (var i=0; i < this.heroStateArray.length; i++) {
	    this.heroStateArray[i].visible = false;
	 			
	    // only for MovieClip stopping, which only have the playing variable
	    if (this.heroStateArray[i].playing == true) this.heroStateArray[i].play();	 			
	}	 		
}
		 	
Hero.prototype.setAnimation = function(_animNum)
{		 		
	this.hideAllAnimationStates();	
	this.heroStateArray[_animNum].visible = true;
		 		
	// only for MovieClips, which by default have the playing attribute
	if (this.heroStateArray[_animNum].playing == false) this.heroStateArray[_animNum].play();		 		
}
			
// *** HERO SETTERS ***
		 	
Hero.prototype.setX = function(_x) {
	this.x = _x;
	this.container.x = this.x;		
}
		 	
Hero.prototype.setY = function(_y) {
	this.y = _y;
	this.container.y = this.y;
}
		 	
// *** HERO GETTERS ***
		 	
Hero.prototype.getX = function() {
        return this.x;
}
		 	
Hero.prototype.getY = function() {
	return this.y;
}
		 	
Hero.prototype.getWidth = function() {
	return this.width;
}
		 	
Hero.prototype.getHeight = function() {
	return this.height;
}

[…]

 

As you might expect the JavaScript version of the Hero class is much longer than the Actionscript 3.0 Hero class. The main difference goes for the lack of the Flash timeline.  You cannot just stack different animations in one super animation with the graphical IDE and use for example gotoAndStop(“left-jump”) to switch between different movement animations of our hero. In Pixi.js with JavaScript you have to manually code the Hero and all his move states. Of course Pixi.js supports its own MovieClip objects, but you can’t create them using a graphical IDE. There is no way to shorten this trip like in Flash and do it the visual way. Also you have to create additional getters and setters in JavaScript for the Pixi.js graphic representation of our Hero to be controlled. The same change of complexity goes for hit test detection. Which in flash is an obvious thing with the usage of hitTestObject() and HitTestPoint() methods. Let’s compare both the Tizen JavaScript and Flash ways to detect the collision between the hero and the evil tentacle lurking on the planet the action of our sample game takes place.

 

The Flash way:

[…]
// ********** CHECK THE PLAYERS COLLISIONS WITH THE TENTACLE ***********
    		
	if (hero.hitTestObject(monster.tentacle) == true && hero.wasHit == false)
	{
				
		trace("HERO HIT BY THE TENTACLE!!!!");
		hero.hitHero();
				
		GameManager.instance.currentHealth -= GameManager.TENTACLE_HEALTH_LOSS;
				
		lifePanel.updateEnergy();
				
	} 
[…]

 

The Tizen in JavaScript way:

[…]
// ********** CHECK THE PLAYERS COLLISIONS WITH THE TENTACLE ***********

if (hitTest(monster.getX() + 40, 
            monster.getSpriteY() + 30, 
            monster.getWidth() - 40, 
            monster.getHeight(), 
            hero.getX() + 20, 
            hero.getY() + 10, 
            hero.getWidth() - 20, 
            hero.getHeight() - 10) == true 
            && hero.wasHit == false) {

hero.hitHero();
						
GameManager.getInstance().setCurrentHealth(GameManager.getInstance().getCurrentHealth()-GameManager.TENTACLE_HEALTH_LOSS);
						
lifePanel.updateEnergy();
						
} 
            
[…]

 

Looks almost the same but there is no hitTestObject() method in JavaScript. So you need your own collision testing. The simplest way to achieve collision detection is to compare if the coordinates of one object with his width and height overlap a seconds’ object position along with the width and height parameters. The proposed way to achieve collision detection in out basketgame.wgt can be found in the basketgame.wgt sample application and below.

[…]

function hitTest(x1, y1, w1, h1, x2, y2, w2, h2) // <== hit testing
{
    if (x1 + w1 > x2)
	if (x1 < x2 + w2)
	    if (y1 + h1 > y2)
		if (y1 < y2 + h2)
		    return true;
};

[…]		

 

Also when you take a look at Pixi.js masks and Flash masks, then you can see that in both cases you can use vector graphics. For the time being it is not so straightforward to port a Flash IDE mask to Pixi.js. This artcile will not cover the process of porting masks from Flash to Tizen. But this will be one of the subjects of upcoming articles. So stay tuned for more articles on porting Flash content to Tizen.

The good news is that the GameManager.as Singleton Flash class can be easily ported into JS. Only few modifications were needed. This is very convenient. If you look closer to the source code of the sample applications, then you can see that the majority of the code is the same in the Tizen version as in the Flash version. Of course the Tizen version has all its code pushed into one main.js file. But this is not mandatory. There are ways to separate the classes of JavaScript in a way that they can be used as Java like or Flash like classes imported with the use of the <script src=”yourclass.js”></script> HTML tag. But we will omit this topic as it is not crucial for this article.

Finally please remember that in the sample game applications we have showed the porting of a desktop Flash game to a Tizen mobile game. Which means that the control system is constructed in a different way. The Flash desktop game is based on the keyboard arrows control, meanwhile the Tizen mobile game controls are based on the devices' accelerometer read out and on the screen touch event. 

 

Summary

Summing up the topic of this article we once again advise you to precisely go through the code of both sample applications and study their code side by side to get the feel of both languages. Please keep in mind that this article covers only the basic and most troublesome topics for any flash developer switiching to Tizen JavaScript development. We showed you what are the basic differences and similarities in Actionscript 3.0 and JavaScript. There have been showed libraries to use in JavaScript to give flash developers a seamingless expierience while switiching to Tizen JavaScript game development and good practices associated with it. We have also showed you differences in class creation in JavaScript and Actionscript 3.0. There have been also mentioned workarounds for implementing a JavaScript equivalent of the Flash native hitTestObject() function. We hope that this article will help you in converting your Flash game projects to Tizen JavaScript.