Archive for the ‘actionscript’ Category.

Double-buffering with ActionScript 3

Ever wondered why, when you create a Flash game or animation that requires a lot of movement, Flash’s performances aren’t so great? Ever wondered how come other people can make theirs behave correctly? The answer is simple: double buffering. If you are not familiar with the term, here’s a simple explanation:

The principle of double buffering is to create two separate buffers to render your graphics. The first buffer, called the “Frame Buffer” is used to build out your frame. The second buffer, called the “Render Buffer”, is used for display only. Let’s say, for example, that you have 10,000 objects on your stage, that are animating. Normally, Flash would freak out, even with a resolution of 550×400, giving you a very poor performance. Have you ever tried NOT displaying anything on the stage, but keep the simulation running? Yep! Flash runs at 30fps, like it was set to. Flash’s weak point is the rendering. Let’s set that heavy lifting aside and tell Flash to render differently. In a lot of scenarios, perfomance will be more important than graphics sharpness or scalability. Already, taking away the vector graphics and replacing it with bitmap graphics enhances Flash’s performance greatly. But, we’re not out of the woods yet. Flash still can’t animate 10,000 objects simulatneously and keep a good framerate. For Flash to render properly, you will need a “camera”. The camera is simply your field of view, the boundaries of the visible stage. Your main movie clip animating might be 40,000×40,000 pixels large, but your stage is 550×400, or 1024×768, or whatever size you decide to give it. Just not 40,000×40,000. By moving the “camera”, you simply move the X and Y coordinates of the animating movie clip in the opposite direction, so it looks like the user is actually moving the camera over a 2D plane.

The concept is to replace Flash’s timeline timer completely and make it do what you want. Even if you have animated movie clips on your stage, they will all need to be stopped. All the frames of all objects will need to be rendered once, at the beginning and stored somewhere, as bitmap data. So, the first thing we’ll do is loop through them all, loop through all their frames, and take a bitmap snapshot of each frame and store them into a mutli-dimensional array, like so:

private var renderedAssets:Array = new Array();
private var assets:Array = new Array();

// Cycling through the base assets and create the original objects, which will be used to populate the
// other arrays.
for (var i:int = 0; i < base_assets.length; i++) {
    // Creates a reference to the class reference contained in the array.
    var baseClass:Class = base_assets[i] as Class;
    // This creates the actual dynamic object.
    var baseObj:MovieClip = new baseClass();

    // Cycling through all the dynamic objects, extracting their frames.
    // Skipping the first frame, as it is the empty tile.
    for (var j:int = 0; j < (baseObj.totalFrames - 1); j++) {
        // Initializing the renderedAssets array.
        renderedAssets[assets.length] = new Array();
         // Moving to the correct frame before taking a bitmap snapshot
         baseObj.gotoAndStop(j+2);
         // Check if the child object in this frame is a movie clip. If it's not, we know there is no need
         // to cycle through its frames to extract the bitmap information. There's only 1 frame.
         if (baseObj.getChildAt(0) is MovieClip) {
             // Checking to see if there is more than one frame. If not, we know there is only one and can extract
             // that single frame without a loop.
             if ((baseObj.getChildAt(0) as MovieClip).totalFrames > 1) {
                // Looping through all the frames within the base object's child
                for (var k:int = 0; k < ((baseObj.getChildAt(0) as MovieClip).totalFrames - 1); k++) {
                    // Postioning the timeline to the right frame
                    (baseObj.getChildAt(0) as MovieClip).gotoAndStop(k+2);
                    renderedAssets[assets.length][k] = getAssetBitmap(baseObj.getChildAt(0) as MovieClip);
                }
            }
            // Only 1 frame
            else {
                // Adding the rendered snapshot to the rendered assets array.
                renderedAssets[assets.length].push(getAssetBitmap(baseObj.getChildAt(0)));
            }
        }
        // Not a MovieClip, only 1 frame
        else {
            // Adding the rendered snapshot to the rendered assets array.
            renderedAssets[assets.length].push(getAssetBitmap(baseObj.getChildAt(0)));
        }
        // Add the object to the assets repository array.
        assets.push(baseObj);
    }
    // Clear the baseObj object (free memory)
    baseObj = null;
}

// Populating the grid with 10000 objects.
for (i = 0; i < 10000; i++) {
    // If this is a new row, create a new array and put it in.
    if (grid[(i % 100)] == null) {
        grid[(i % 100)] = new Array(100);
    }
    var randNum:int = (Math.floor(Math.random() * assets.length));
    // Add a random number, associated with the index of the assets repository array.
    grid[(i % 100)][Math.floor(i / 100)] = randNum;
}

private function getAssetBitmap(baseObj:DisplayObject, secondObj:MovieClip = null):BitmapData
{
	// Creating an empty BitmapData, the size of the asset.
	var tmpBMData:BitmapData = new BitmapData(baseObj.width, baseObj.height);
	// Taking the bitmap snapshot of the current frame.
	tmpBMData.draw(baseObj);

	if (secondObj != null) {
   	tmpBMData.draw(secondObj, new Matrix(1, 0, 0, 1, (baseObj.width / 2 - secondObj.width / 2), (baseObj.height / 2 - secondObj.height / 2)));
	}
	// Returning the rendered snapshot.
	return tmpBMData;
}

Setup the stage to listen to the ENTER_FRAME event. The callback will become your application’s main loop.

addEventListener(Event.ENTER_FRAME, renderFrame);

In your main loop, you will determine which frame you are on by increasing a counter.

private function renderFrame(evt:Event):void
{
	frameCounter++;
}

Knowing where all our objects are supposed to be positioned, we can begin building our frame buffer. Looping through each individual objects that is supposed to be animating, or be present on the stage, determine if they should be visible, according to their X and Y coordinates, as well as their width and height. If you have determined that the object should NOT be visible at that time, skip it completely. One down! 9,999 to go!

Once we reach an object that needs to be shown (even 1 pixel of it!), we need render it. To do that, we’ll need a Bitmap data from that particular object, of its current state. We will then position the movie clip’s frame to (totalFrameCounter % mcNumFrames). That is, the total number of frames we went through in the application main loop and divide it by the number of total frames in the animating movie clip. Move to the rest of the division. Here is the function I wrote to determine that:

private function buildFrame(frameCounter:uint):BitmapData
{
    // Create a new BitmapData, the size of the stage.
    frameBuffer = new BitmapData(stage.stageWidth, stage.stageHeight);
    // Cycle through all the grid elements
    for (var i:int = 0; i < 10000; i++) {
        var gridValue:uint = grid[(i % 100)][Math.floor(i / 100)];
        // If the element we're on is supposed to be visible, according to the camera position, we need to render.
        if (
            (((i % 100) * (cellSize * (renderedAssets[gridValue][0].width / cellSize))) + cameraX) < stage.stageWidth &&
            ((Math.floor(i / 100) * (cellSize * (renderedAssets[gridValue][0].width / cellSize))) + cameraY) < stage.stageHeight &&
             ((i % 100) * (cellSize * (renderedAssets[gridValue][0].width / cellSize))) >= (-(cameraX) - (cellSize * (renderedAssets[gridValue][0].width / cellSize))) &&
            (Math.floor(i / 100) * (cellSize * (renderedAssets[gridValue][0].width / cellSize))) >= (-(cameraY) - (cellSize * (renderedAssets[gridValue][0].width / cellSize)))

        ) {
            // Positions the point to the right position in the frame buffer
            pt.x = (((i % 100) * (cellSize * (renderedAssets[gridValue][0].width / cellSize))) + cameraX);
            pt.y = ((Math.floor(i / 100) * (cellSize * (renderedAssets[gridValue][0].width / cellSize))) + cameraY);

            try {
                // Calculates which frame needs to be showing. Since the assets might not have the same amount of frames,
                // the modulo takes care of that by returning a relative position.
                var frame:uint = frameCounter % renderedAssets[gridValue].length;
                // Copies the actual pixels into the frame buffer.
                frameBuffer.copyPixels(renderedAssets[gridValue][frame], rect, new Point(pt.x, pt.y));
            }
            // Oh shit!
            catch (e:Error) {
            }
        }
    }
    // Return the frame buffer.
    return frameBuffer;
}

Modulo (the % sign) is a mathematical operator that will perform an integer division and return the rest. For example, 7 % 3 will return 1. 7 divided by 3 will obviously return a fraction so, we’ll take the “floor” value of that fraction, and multiply it by the divider (which is 3). The floor of 7 / 3 is 2. 2 multiplied by 3 is 6. 7 minus 6 = 1. It is a pretty complicated mathematical operation, but ActionScript takes care of all that for you.

Once all your visible assets are determined and rendered to the frame buffer, it’s time to take a big screenshot of that framebuffer and push that to the render buffer. Let’s add more code to our rendreFrame function:

private function renderFrame(evt:Event):void
{
	// Build the frame buffer.
    frameBuffer = buildFrame(frameCounter);
    // Clone the frame buffer into the render buffer.
    renderBuffer = frameBuffer.clone();
    // Destroy the frame buffer.
    frameBuffer.dispose();

    // Draw the render buffer into the document class' graphics using the BitmapFill.
    // Since we're already dealing with bitmap data, no need to create heavy objects such as flash.display.Bitmap.
    this.graphics.clear();
    this.graphics.beginBitmapFill(renderBuffer);
    this.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
    this.graphics.endFill();

 	frameCounter++;
}

Now, every time the application enters a frame, all those operations will be performed. Tada! We now have a double buffering application. As long as Flash can compute the coordinates of all the objects we need to animate, we should get a decent framerate.

To make a long story short, instead of making Flash “Render object -> Display object, Render object -> Display object” 10,000 times, we do “Render object, Render object, Render object, … , Display visibible objects”. Makes much more sense.

I attached a test project I wrote using that principle. The code is pretty detailed. It uses Simcity Classic assets (Micropolis). Some of them are animated, some of them are not. You’ll see!

DoubleBuffering.zip

Thanks for reading and please, feel free to leave comments!

How to create a jagged array in Objective-C

I don’t know if you ever ran into that kind of problem before, where you need to initialize a jagged array with Objective-C, but I did. I was disappointed to find out that Objective-C doesn’t have any easy way of recursively call a variadic method. I read several posts talking about using NSInvocation to achieve this, but as Apple stated, it’s not capable of doing so. Setting an argument on the NSInvocation object that is beyond the static arguments returned by the method signature will result in an out of bounds exception.

I found a way, it’s not super pretty, but it works just fine. Here’s a few examples of how simple this task is using other languages:

PHP:

<?php
    function createJaggedArray($length) {
        $args = func_get_args();
        array_shift($args); // We don't need the first parameter, it's already defined.
        
        $arr = array();
        while ($length--) {
            $arr[$length] = count($args) ? call_user_func_array('createJaggedArray', $args) : 0;
        }
        return $arr;
    }

    $jaggedArray = createJaggedArray(3, 3, 4, 4); // creates var[3][3][4][4]
    $jaggedArray2 = createJaggedArray(10, 3, 9); // creates var[10][3][9]

?>

ActionScript 3:

package {
    public class ArrayUtil {
        public static function createJaggedArray(len:int, ...args):Array {
            var arr:Array = new Array(len);
            
            while(len--) {
                arr[len] = args.length ? createJaggedArray.apply(null, args): 0;
            }

            return arr;
        }
    }
}

var myArray:Array = createJaggedArray(3, 3, 4, 4); // creates var[3][3][4][4]
var myArray2:Array = createJaggedArray(10, 3, 9); // creates var[10][3][9]

Here’s what I came up with for Objective-C. As you can tell, it’s quite convoluted. I’m sure there’s a better way of executing this, but at least, if you need something right away, that might answer *some* questions:

CreateJaggedLib.h:

@interface CreateJaggedArray : NSObject {
}

- (NSArray *)createJaggedArray:(NSNumber *)len, ...;
- (NSArray *)createJaggedArrayFromArray:(NSNumber *)len childrenLengths:(NSArray *)childrenLengths;

@end

CreateJaggedArray.m:

#import "CreateJaggedArray.h"

@implementation CreateJaggedArray

- (NSArray *)createJaggedArray:(NSNumber *)len, ... {
    NSMutableArray *argArray = [[NSMutableArray alloc] init];
    NSMutableArray *buildingArray = [[NSMutableArray alloc] init];

    NSNumber *eachArgument;
    if (len) {
        va_list argumentList;
        va_start(argumentList, len);
        while (eachArgument = va_arg(argumentList, NSNumber *) {
            [argArray addObject:eachArgument];
        }
        va_end(argumentList);
    }

    NSInteger length = [len intValue];

    while (length--) {
        NSMutableArray *nextArray = [[NSMutableArray alloc] init];
        for (NSInteger i = 1; i < [argArray count]; i++) {
            [nextArray addObject:[argArray objectAtIndex:i]];
        }
        
        NSNumber *value = [NSNumber numberWithInt:[[argArray objectAtIndex:0] intValue]];
        NSArray *resultArray = [self createJaggedArrayFromArray:value childrenLengths:nextArray];
        [buildingArray addObject:resultArray];
    }
    return buildingArray;
}

- (NSArray *)createJaggedArrayFromArray:(NSNumber *)len childrenLengths:(NSArray *)childrenLengths {
    NSInteger length = [len intValue];
    NSMutableArray *buildingArray = [[NSMutableArray alloc] init];

    while (length--) {
        if ([childrenLengths count] > 1) {
            NSMutableArray *nextArray = [[NSMutableArray alloc] initWithCapacity:([childrenLengths count] - 1)];
            for (NSInteger i = 1; i < [childrenLengths count]; i++) {
                [nextArray addObject:[childrenLengths objectAtIndex:i]];
            }
            NSNumber *value = [NSNumber numberWithInt:[[childrenLengths objectAtIndex:0] intValue];
            NSArray *resultArray = [self createJaggedArrayFromArray:value childrenLengths:nextArray];
            [buildingArray addObject:resultArray];
        }
        else {
            NSMutableArray *valueArray = [[NSMutableArray alloc] init];
            for (NSInteger i = 0; i < [[childrenLengths objectAtIndex:0] intValue]; i++) {
                [valueArray insertObject:[NSNumber numberWithInt:0] atIndex:i];
            }
            [buildingArray addObject:valueArray];
        }
    }
    return buildingArray;
}

@end

Call:

NSArray *jaggedArray = [<delegate> createJaggedArray:[NSNumber numberWithInt:3], [NSNumber numberWithInt:3], [NSNumber numberWithInt:4], [NSNumber numberWithInt:4], nil]; // Creates var[3][3][4][4]
NSArray *jaggedArray2 = [<delegate> createJaggedArray:[NSNumber numberWithInt:10], [NSNumber numberWithInt:3], [NSNumber numberWithInt:9], nil]; // Creates var[10][3][9]

As you can see, this can get pretty convoluted. I had to create a method that reacts differently for all the children parameters, since the recursive call of a variadic method isn’t supported with Objective-C. You could simply call the createJaggedArrayFromArray method using an array of lengths instead of using the nil-terminated list of arguments, but sometimes, it makes it easier for porting code from one language to another, to make sure it works the same way.

If someone has a better idea on how to fix this, please share! 🙂

Handling beans with BlazeDS and Flex

I recently did a little bit of testing around some concepts with BlazeDS and Flex for a game I’m writing with a friend. The game needs to be multi-player and online. Since the game will have some synchronous (real-time) and asynchronous operations going on in the same session, I needed to have an efficient way of passing data from the messaging system to the remoting system. I decided to use a bean. Creating a singleton controller, I can put whatever data I want in my bean and keep it in memory, passing it back and forth between my controllers. Here’s a small example of how to use the classes:

Messaging Section

Let’s go ahead and create an adapter class, let’s call it JavaFlexAdapter.

package com.javaflex.adapters;

import java.util.logging.Logger;

import com.javaflex.objects.BeanController;

import flex.messaging.messages.AsyncMessage;
import flex.messaging.messages.Message;
import flex.messaging.services.MessageService;
import flex.messaging.services.ServiceAdapter;

public class JavaFlexAdapter extends ServiceAdapter
{
    private static final Logger log = Logger.getAnonymousLogger();

    @Override
    public Object invoke(Message arg0)
    {
        AsyncMessage message = (AsyncMessage) arg0;
        message.setBody("[Server] " + arg0.getBody()); // Just to say the server treated the message;
        BeanController instance = BeanController.getInstance();
        try {
            instance.populateBean("value1", "value2", "value3");
        }
        catch (Exception ex) {
            log.error(ex);
        }
        MessageService service = (MessageService) getDestination().getService();
        service.pushMessageToClients(message, false);
        return null;
    }
}

Next, comes the remoting class:

package com.javaflex.remoting;

import com.javaflex.objects.BeanController;
import com.javaflex.objects.MyBean;

public class BeanReader
{
    public MyBean returnBean()
    {
        BeanController instance = BeanController.getInstance();
        return instance.getBean();
}

Now that we got both our Java classes that Flex talk to, let’s write the glue. This is the controller:

package com.javaflex.objects;

public class BeanController
{
    private static BeanController instance = null;
    private MyBean bean = null;

    protected BeanController()
    {
        bean = new MyBean();
    }

    public static BeanController getInstance()
    {
        if (instance == null) {
            instance = new BeanController();
        }
        return instance;
    }

    public void populateBean(String val1, String val2, String val3)
    {
        bean.setValue1(val1);
        bean.setValue2(val2);
        bean.setValue3(val3);
    }

    public MyBean getBean()
    {
        return bean;
    }
}

And now, the bean itself:

package com.javaflex.objects;

public class MyBean
{
    private String value1;
    private String value2;
    private String value3;

    public String getValue1()
    {
        return value1;
    }
    public String getValue2()
    {
        return value2;
    }
    public String getValue3()
    {
        return value3;
    }
    public void setValue1(String value)
    {
        value1 = value;
    }
    public void setValue2(String value)
    {
        value2 = value;
    }
    public void setValue3(String value)
    {
        value3 = value;
    }
}

Now that everything for the backend is written, let’s take a look at the Flex application:

<?xml version="1.0" encoding="utf-8"?>
<mx:Applicataion xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init();">
    <mx:Script>
        <![CDATA[
            import mx.rpc.events.FaultEvent;
            import mx.rpc.events.ResultEvent;
            import mx.messaging.messages.AsyncMessage;
            import mx.messaging.events.MessageFaultEvent;
            import mx.messaging.events.MessageEvent;
            
            private var consumer:Consumer = null;
            private var producer:Producer = null;

            private function init():void
            {
                consumer = new Consumer();
                consumer.destination = "messaging";
                consumer.addEventListener(MessageEvent.MESSAGE, msgHandler);
                consumer.addEventListener(MessageFaultEvent.FAULT, faultHandler);
                consumer.subscribe();

                producer = new Producer();
                producer.destination = "messaging";
                producer.addEventListener(MessageFaultEvent, faultHandler);
                producer.send(new AsyncMessage("Test!"));
            }

            private function msgHandler(evt:MessageEvent):void
            {
                trace(evt.message);
                remoteObject.returnBean();
            }

            private function faultHandler(evt:MessageFaultEvent):void
            {
                trace(evt.message);
            }

            private function roMsgHandler(evt:ResultEvent):void
            {
                trace(evt.message);
            }

            private function roFaultHandler(evt:FaultEvent):void
            {
                trace(evt.message);
            }
        ]]>
    </mx:Script>
    <mx:RemoteObject id="remoteObject" destination="remoting" result="roMsgHandler(event)" fault="roFaultHandler(event)" />
</mx:Application>

When running this code, you should get the following output:

(mx.messaging.messages::AsyncMessageExt)#0
  body = "[Server] Test!"
  clientId = "746CE46E-AF0A-1EE4-804E-13FF83B3F9F0"
  correlationId = ""
  destination = "messaging"
  headers = (Object)#1
  messageId = "D2713439-8507-C778-C0D5-4771D314477C"
  timestamp = 1263919026976
  timeToLive = 0
(mx.messaging.messages::AcknowledgeMessageExt)#0
  body = (Object)#1
    value1 = "value1"
    value2 = "value2"
    value3 = "value3"
  clientId = "746CE55B-800A-EBDD-C77F-11E4902E2A4A"
  correlationId = "4082D4B5-8554-C76D-BD02-4771D34B5138"
  destination = ""
  headers = (Object)#2
  messageId = "746CE55B-801E-822C-6CF7-92A7C01FE758"
  timestamp = 1263919027072
  timeToLive = 0

Voilà! You set the bean values through the messaging system, and you’re fetching the values through the remoting system.

Please let me know if this article was useful.

Thanks for reading!

HTML in Flash/Flex

I was mandated at work to work on the company’s website. Since the site needs to incorporate a blog for several employees, the option of writing the whole site in Flash was out of the question, as people would embed whatever videos from YouTube, images from various places, etc. The support for HTML rendering with Flash Player is fairly limited.

Not anymore! Today, I decided to simply Google Flash HTML renderer and I come across this little marvel: http://code.google.com/p/htmlwrapper/. It’s a fairly advanced HTML renderer. It supports most of the features that one would need on a blog. I have yet to try this library, but I sure will as soon as I can. This puts the idea of writing the whole site with Flash and GAIA Framework back in the run!

Hope you enjoy this library!

AMF Tutorial part 3 added

Hey! I finally took the time to write up the last part of my AMF tutorial.

Hope it answers your questions!

-Simon

Read More

AMF Tutorial part 2 added

I know, I was supposed to write to my blog more often than this, but I was pretty busy. Anyway, here it is! You can access it through the Tutorial link at the top of the page!

Enjoy!

PS: Feel free to leave any feedback.

Read more

Number Formatting with AS3

I ran into a problem the other day where, I’m pretty sure a lot of you actually ran into as well, number formatting with AS3.

The big problem is that Math.round doesn’t allow you to specify a precision.

I tried to make this function work as closely as PHP’s number_format() function, here’s my attempt:

function numberFormat(num:Number, decimals:int = 0, thousands:String = ','):String
{
	var buffer:String = '';
	var truncate:Number = 0;
	var orig:String = '';
	if (decimals > 0) {
		var ratio:int = Math.pow(10, decimals);
		var tempDecimal:Number = (Math.round(num * ratio) / ratio);
		truncate = (Math.round((tempDecimal - Math.floor(num)) * ratio) / ratio);
		if (truncate == 1) {
			num += 1;
			truncate = 0;
		}
		orig = Math.floor(num).toString();
	}
	else {
		orig = Math.round(num).toString();
	}

	var iteration:int = 0;

	for (var i = (orig.length - 1); i >= 0; i--) {
		if (((iteration % 3) == 0) && (iteration > 0)) {
			buffer = thousands + buffer;
		}
		buffer = orig.charAt(i) + buffer;
		iteration++;
	}

	if (truncate > 0) {
		buffer += '.' + truncate.toString().substr(2);
	}

	return buffer;
}

Hopefully, it helps you resolve your number formatting issues.

New Tutorials Section!

Hello all, I just now added a new section to my blog, a tutorial section.

For now, there is only a partial one on AMF connectivity between ActionScript and PHP.

Read more