Saturday, January 16, 2010

Invoking the Flex Compiler via Native Process API in AIR 2.0

AIR 2.0 comes with the ability to interact with native processes. This means we can launch a process from the AIR application and communicate with its standard input/output. However, applications using the native process api must be packaged into native installer. Therefore, you must compile it separately in Windows, Mac and Linux to get 3 files as compared with 1 AIR file for all platforms.

Working the Native Process API is fairly easy. All the operations are performed using the NativeProcess class. To start a native process, you have to call the start method. The parameter passed to the start method is of type NativeProcessStartupInfo. This basically is used to represent the location of the process to be started and also to specify arguments(if any) for the process. I've created a very simple application which uses the Flex compiler (mxmlc) to compile an application.

First off, according to the Developer FAQ at Adobe Labs , bat files cannot be directly launched. Instead we launch the command prompt and then pass the command as input. Once a native process has started, we can write to its input and read from its output by using the standardInput and standardOutput objects. Here is a little screenshot of the application :



We get the location of the Flex SDK directory, the main application file and the output file. When the compile button is clicked, we create a compilation command using the three data (eg : /bin/mxmlc /app.mxml /app.swf) and execute the command. When the output is received, we use the file.openWithDefaultApplication() property to run the SWF file.

Note:
While running the application from the native installer, the command prompt also opens up beside it (which does not occur when you run from within Flash Builder).
Also note that this example assumes your application file has no errors. This is just a proof-of-concept to show how easy it is to build an application like this.

Resources :
AIR 2 (Adobe Labs)
Interacting with a native process (Adobe AIR Developer Center)

Here are the source files for the application :
The FXP file
The compiled native installer .exe file (Windows only)


There are still concerns about updating applications using native installers as the update framework will not work with this. I'm definitely looking forward to more cool demos from the community.

Tuesday, September 22, 2009

Squiggly - Spell Check Engine Example

We've been waiting for a spell check engine in Flash for a long time. Now, Adobe has released Squiggly. From Adobe Labs :
Squiggly is a spell checking engine for Adobe® Flash® Player and Adobe AIR®. The Squiggly library allows you to easily add spell checking functionality in any Flex 3 based text control.
While the included UI class requires the Flex SDK, the core spell checking engine can be used in pure Flash applications without any dependency on Flex packages.

Currently, only English dictionary is available but you can create your own dictionaries with a bundled AIR app.

The 3 main classes we'll be using are SpellChecker, SpellingDictionary and SpellUI all of which belong to the com.adobe.linguistics.spelling. package. There are several sub packages but they need not be used directly.

Usage :

If we are using the Flex SDK, then we can use the SpellUI class to spell check any Flex component like ,
SpellUI.enableSpelling(textArea, "usa.zwl");
where usa.zwl is the dictionary file.

However, if you are not using the Flex SDK, then the SpellUI class cannot be used. In that case, we can use the SpellChecker class directly to perform spell checking. Here's a sample demo class i've put together.

Hope that's useful for anyone. Happy coding :D

Sunday, August 16, 2009

Creating a game with APE - APEOut - Part 3

In the third and final part of this tutorial, we'll finish off this game by adding collision detection and scoring.Before we start, make sure you've read the first and the second part of this series. So, lets get to it.

Adding collision detection :

In order to add collision detection, we'll need to add an Event listener to the ball. After the ball defnition, add the following code :

ball.addEventListener(CollisionEvent.COLLIDE, onCollision);

Now, we have to code what happens if a collision occurs. Create the onCollision event handler as follows :

private function onCollision(e:CollisionEvent):void
{
var collidingItem:* = e.collidingItem;

if (collidingItem != topWall && collidingItem != bat &&
collidingItem != leftWall && collidingItem != rightWall)
{
--brickCount;
group.removeParticle(collidingItem);
}
}


Here the collidingItem will refer to the object that comes in contact with the ball. Now, we have to remove the object if it is a brick or do nothing if its the bat or the walls. So, we check if the collidingItem is not one of the walls or the bat, then we remove it from the group and reduce the brickCount.

Finishing up the game :

Now, run the game, our bat is moving with the mouse, the ball is bouncing and destroying the bricks that it comes in contact with. Everything is working as it is supposed to. But every good game needs scores, right, so declare a score variable as a Number and a TextField to display the score.We also need a Boolean variable to see if the game is over or not. Here's the final full code :

package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;

import org.cove.ape.APEngine;
import org.cove.ape.CircleParticle;
import org.cove.ape.CollisionEvent;
import org.cove.ape.Group;
import org.cove.ape.RectangleParticle;
import org.cove.ape.VectorForce;

/**
* APEOut - A Breakout clone using the ActionScript Physics Engine (APE)
* @author Pradeek
*/

[SWF(width = 600, height = 400)]
public class APEOut extends Sprite
{
private var group:Group;
private var leftWall:RectangleParticle;
private var rightWall:RectangleParticle;
private var topWall:RectangleParticle;
private var bat:RectangleParticle;
private var ball:CircleParticle;
private var brickCount:Number;

private var score:Number;
private var scoreText:TextField;
private var gameOver:Boolean;

public function APEOut():void
{
initAPE();
initObjects();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

private function initAPE():void
{
APEngine.init();
APEngine.container = this;
APEngine.addForce(new VectorForce(false, 0, 4));
}

private function initObjects():void
{
gameOver = false;

score = 0;
scoreText = new TextField();
scoreText.x = 400;
scoreText.y = 25;
addChild(scoreText);

group = new Group(true);

leftWall = new RectangleParticle( -10, 0, 10, 1000, 0, true, 1, 0.3, 1);
rightWall = new RectangleParticle(610, 0, 10, 1000, 0, true, 1, 0.3, 1);
topWall = new RectangleParticle(0, -10, 1200, 10, 0, true, 1, 0.3, 1);

bat = new RectangleParticle(250, 325, 125, 10, 0, true, 1, 0.50, 1);
bat.alwaysRepaint = true;
bat.setFill(0x0000FF);

ball = new CircleParticle(220, 225, 15, false, 1, 0.65, 1);
ball.setFill(0xFF0000);
ball.addEventListener(CollisionEvent.COLLIDE, onCollision);

var rows:int = 5;
var cols:int = 8;

brickCount = rows * cols;

var currentX:Number = 100;
var currentY:Number = 100;

var brickWidth:Number = 50;
var brickHeight:Number = 10;

for (var i:uint = 0; i < uint =" 0;" rectangleparticle =" new" currentx =" 100;" px =" mouseX;" text = "Score : "> 400)
{
gameOver = true;
group.removeParticle(ball);
scoreText.text = "Game Over. \nYou lose. \nFinal Score : " + score.toString();
}

if (brickCount == 0)
{
gameOver = true;
group.removeParticle(ball);
scoreText.text = "Game Over. \nYou win. \nFinal Score : " + score.toString();
}
}
}
}


Hope the series was a bit useful to you. If you have any questions or suggestions, please drop a comment. Thanks for reading :D

Creating a game with APE - APEOut - Part 2

In part 2 of this tutorial, we're going to add the bricks and add motion for the bat. Make sure you've read the first part of this tutorial and lets get going.

Creating the bricks :

Add the following code to the initObjects method after creating the ball.Also create a private variable brickCount for the number of bricks in the stage.
var rows:int = 5;
var cols:int = 8;

brickCount = rows * cols;

var currentX:Number = 100;
var currentY:Number = 100;

var brickWidth:Number = 50;
var brickHeight:Number = 10;

for (var i:uint = 0; i < rows; i++)
{
for (var j:uint = 0; j < cols; j++)
{
var brick:RectangleParticle = new RectangleParticle(currentX, currentY, rickWidth, brickHeight, 0, true, 1, 0.3, 1);
brick.setFill(Math.random() * 0xFFFFFF);
group.addParticle(brick);
currentX += brickWidth + 5;
}
currentX = 100;
currentY += brickHeight + 5;
}
What we're doing here is simply creating a brick at the position (currentX,currentY) and incrementing with the brickWidth and a gap value. We also set a random color for the bricks. Run the file. You'll see a ball bouncing on the bat and about 40 bricks lined up in 5 rows. When the ball collides with the brick, it just bounces off. Moving the bat : To move the bat just add the line
bat.px = mouseX;
before the APEngine.step() call in the onEnterFrame event handler. If you run the game now, you'll see that the image of the bat doesn't move but if you move your mouse, the ball will fall down. So, add the following line under the bat defnition.
bat.alwaysRepaint = true;

Now, it looks something like a game. We have the bat, the ball and the bricks. All we need is to add collision detection and scores. We'll do that in the next post.
Stay tuned.

Saturday, August 15, 2009

Creating a game with APE - APEOut - Part 1

Following up on my introductory blog post on APE, Today we are going to create a simple Breakout clone with APE. I'm going to call this APEOut having just 1 level. I'll split this tutorial into 3 parts. In the first part, we'll create a bat, ball and the boundaries. In the second part, we'll create the bricks and add movement for the bat. In the third part, we'll add collision detection and scores.
So, lets get started.

package
{
import flash.display.Sprite;
import flash.events.Event;

import org.cove.ape.APEngine;
import org.cove.ape.Group;
import org.cove.ape.VectorForce;

/**
* APEOut - A Breakout clone using the ActionScript Physics Engine
* @author Pradeek
*/

[SWF(width = 600, height = 400)]
public class APEOut extends Sprite
{
private var group:Group;

public function APEOut():void
{
initAPE();
initObjects();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}

private function initAPE():void
{
APEngine.init();
APEngine.container = this;
APEngine.addForce(new VectorForce(false, 0, 4));
}

private function initObjects():void
{
group = new Group(true);
APEngine.addGroup(group);
}

private function onEnterFrame(e:Event):void
{
APEngine.step();
APEngine.paint();
}

}

}

The above code is similar to the one we wrote in the last post. Basically, we're setting up the engine, creating a group and updating and drawing on the ENTER_FRAME event. Next, we create the 3 boundaries - top, left and right and the bat and the ball. Create objects of the RectangleParticle class for topWall, leftWall , rightWall and bat and the CircleParticle class for the ball. Modify the initObjects method as follows :

private function initObjects():void
{
group = new Group(true);

leftWall = new RectangleParticle( -10, 0, 10, 1000, 0, true, 1, 0.3, 1);
rightWall = new RectangleParticle(610, 0, 10, 1000, 0, true, 1, 0.3, 1);
topWall = new RectangleParticle(0, -10, 1200, 10, 0, true, 1, 0.3, 1);

bat = new RectangleParticle(250, 325, 125, 10, 0, true, 1, 0.50, 1);
bat.setFill(0x0000FF);

ball = new CircleParticle(220, 225, 15, false, 1, 0.65, 1);
ball.setFill(0xFF0000);

group.addParticle(leftWall);
group.addParticle(rightWall);
group.addParticle(topWall);

group.addParticle(bat);

group.addParticle(ball);

APEngine.addGroup(group);
}


A little code explanation :
We position three rectangular blocks on the top, left and the right sides. Since they are walls, we're hiding them. We create a bat and a ball and position them appropriately.
Try to run this. You should see the ball bouncing on the bat. If you wait a bit, you'll see that it hits the top and bounces back.
The next step is creating the bricks and making the bat move. We'll do that in the next post. If you have any questions, please post it in the comments. Thanks for reading.