Category Archives: ActionScript

SignalCommandMap extension, a pure AS3 example

Currently busy learning the Starling framework; but as I recently decided to apply Joel Hooks SignalCommandMap extension to a project I was working on, I decided to do a quick typeup slash demo project of this extension. The demo which can be downloaded here as a zipped project is not Flex based in difference to the original demo located here.

This extension been around for a long time so no big news in this post, just providing a pure AS3 example.

The SignalCommandMap extension let’s you eliminate all native Flash Events in your application and since Object rather than String based, ripe the benefits of not having to deal with String based Custom Events. (Not long ago I had two custom events not working cause despite differently named constants the string identifier by mishap was identical, a genre…)

Below is a minimalist example of the SignalCommandMap extension at work. Events are passed to the framework from the NavigationViewMediator using a Signal that carries a ValueObject which tells wether the User selected a tomato or an orange. A Command is mapped to this Signal and when recieved, sets the data upon the Model which notifies the Framework. As a result the ContentView which holds a ScrollPane updates with either a tomato or an orange:

Get Adobe Flash player

This is the code for the NavigationViewMediator. As you can see it dispatches the ValueObject as a parameter: addItem.dispatch(action) where action is our ValueObject:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package view.mediator {
   import model.vo.ItemVO;
   import org.robotlegs.mvcs.Mediator;
   import signals.AddItem;
   import view.component.NavigationView;

   public class NavigationViewMediator extends Mediator {

      [Inject]
      public var view:NavigationView;

      [Inject]
      public var addItem:AddItem;

      public function NavigationViewMediator() {
         super();
      }

      override public function onRegister():void {
         this.view.itemSelected.add(handleItemSelected);
      }

      protected function handleItemSelected(action:ItemVO):void {
         addItem.dispatch(action);
      }
   }
}

The Signal itself is pretty simple. Note that in the super constructor we pass the relevant ValueObject:

1
2
3
4
5
6
7
8
9
package signals {
   import model.vo.ItemVO;
   import org.osflash.signals.Signal;
   public class AddItem extends Signal {
      public function AddItem() {
         super(ItemVO);
      }
   }
}

The Command mapped to the Signal is mapped inside another Command or could (as in the original example – and perhaps better you could say) be mapped directly in the Context. To be able to map a Signal to a Command in a Command, as I like to use Commands to bootstrap my application, all we need to do however is to make sure that the Command extends the SignalCommand class:

1
2
3
4
5
6
7
8
9
10
11
package controller.command {
   import org.robotlegs.mvcs.SignalCommand;
   import signals.AddItem;

   public class PrepSignalCommand extends SignalCommand {
      override public function execute():void {
         injector.mapSingleton(AddItem);
         signalCommandMap.mapSignalClass(AddItem, AddItemCommand);
      }
   }
}

And that’s it! I recommend a download of the original example by Joel Hooks to see the difference perhaps, and a download of my example in case you want to take the pure AS3 approach!

This post is now included in the robotlegs knowledgebase here
http://knowledge.robotlegs.org/discussions/resources/33-links-to-robotlegs-resources-examples-tutorials

Small note and afterthought: I wrote this pretty fast so in effect ideally I would not have had the images embed in the View class but be set in VO from Model…

Robotlegs, read-only config Value Objects

FlashdevelopI’ve decided to knock a bad habit of using too many static constants in my code. A Config VO provides a less coupled but also injectable recipe. To enforce ‘read-only-mode’ the config VO is mapped to an interface.

In Robotlegs, to map to interface we use mapSingletonOf:

1
injector.mapSingletonOf(IConfig,ConfigVO);

The interface enforces the usage of getters only in our ConfigVO class and could for example look like:

1
2
3
4
5
6
package com.domain.project.feature.api.core {
   public interface IConfig {
      function get numrows():int;
      function get numimages():int
   }
}

What’s needed in our ConfigVO implementation should be evident from the IConfig Interface. Dependency Injection now makes it a breeze to access the ConfigVO from any Model:

1
2
   [Inject]
   public var configVO:IConfig;

Where we type the instance to the Interface!
-(Thanks to RL forum support for clearing out my confusion about this).

Loading external Papervision3D Models, a Simple Robotlegs Example

Actually the title for this post was gonna be ‘Preoading external Papervision3D Models, a Simple Robotlegs Example” but unless I have some strong Coffe, I think it best to add the preoloader part in next update. Below is a really simple example of an external DAE model Loaded in, the classes structured within the Robotlegs framework.

Get Adobe Flash player

One of the many fun things with Robotlegs is that it helps us structure data and hand out single responsibilites for tasks to classes. For loading remote data we create a Service class which can connect to a webservice.

However for data that is loaded locally and not really said to be remote the word/concept of a Proxy meaning “Something that stands in for something else to achieve something” can be useful.
In this case our proxy is called DAELoaderProxy and looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package model.proxies
{
import model.data.DataLogic;

import org.papervision3d.events.FileLoadEvent;
import org.papervision3d.objects.parsers.DAE;
import org.robotlegs.mvcs.Actor;

public class DAELoaderProxy extends Actor
{
[Inject]
public var dataLogic:DataLogic;

private var mod:*;
private var _pathtomod:String;

public function DAELoaderProxy()
{
}

public function loadModel ():void {
mod = new DAE();
mod.load(this.pathtomod)
mod.addEventListener(FileLoadEvent.LOAD_ERROR, onModelLoadError);
mod.addEventListener(FileLoadEvent.LOAD_COMPLETE, onModelLoaded);
//TODO :PRELOADER THAT NOTIFIES MODEL OF PROGRESS, MODEL NOTIFIES PRELOADER MEDIATOR OF PROGRESS, PRELOADER VIEW UPDATES
}

private function onModelLoaded(event:FileLoadEvent):void
{
dataLogic.deemodel = mod;
}

private function onModelLoadError(event:FileLoadEvent):void
{
trace("error")
}

//get - set
public function set pathtomod (value:String):void {
_pathtomod = value;
}

public function get pathtomod ():String {
return _pathtomod;
}
}
}

The DAELoaderProxy does one thing: it (obviously) loads a DAE model for our cool Papervision3d. Once the 3D model is loaded the Proxy class calls a setter upon the data Model class (in this case called DataLogic.as) and passes the 3D model to it.

This way the responsibility of updating the framework is handed over to the Model. The Model dispatches an event with the DAE 3d model as payload and our ViewMediator catches the event and adds the model to our 3D View.

Proxies seem to me very single minded. We can in effect write an alternative KMZLoaderProxy class for google Sketchup models without needing to know more than the code that gets that particular job done. Of course we might as well call the DAELoaderProxy class for ‘DAELoader’ but for me personally I like the word proxy as it underlines the “Stand in” part.

And whereas a loader in not structured code often ends up notifying the Observers the proxy does not. It let’s Model do it’s part instead.

You can download project files here (Flashbuilder project). It should contain all needed to run locally.

SWFAddress seo, the quick and dirty

SWFAddress from http://www.asual.com allows for easy deep linking of Flash sites. There’s quite a lot written about how to set SWFAddress up with SWFObject for deep linking but less about the SEO sample option.

The page for all samples can be found here. The SEO option is described as “Advanced sample which showcases the search engine indexing capabilities of SWFAddress 2.x. It also demonstrates the usage of query parameters and handling of 404 errors. The sample requires Apache 1.3+ and PHP 4+. ”

So here’s how to get the SEO alternative up and running. First thing if you have no local server installed, I recommend downloading xxamp lite from here. Xxamp is a handy apache/php5 distribution. Download .exe, install. That’s it. (However you can skip right to the code part below, this is just a tip.)

Now grab the flashdevelop project SWFAddressSEO.zip (if you don’t use Flashdevelop then Main.as is your init/document class). You can see the basic demo here. (- If you want to run it locally to experiment with further and you’ve installed xxamp lite just now then just unzip and place it in the htdocs folder and go http://localhost/SWFAddressSEO/bin.)

In the unzipped example you will find:

In the bin folder there’s two php files used for the SEO deeplinking. datasource.php is where the seo content resides for each section in the site. It contains a series of case statements with content for them:

1
2
3
4
5
6
7
switch($swfaddress) {
case '/':
echo('<p>At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio.</p>');
break;
case '/ABOUT/':
echo('<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.</p>');
break;

This content is explained by index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div id="content">
<div>
<h1><a href="<?php swfaddress_link('/'); ?>">HOME</a></h1>
<ul>
<li><a href="<?php swfaddress_link('/ABOUT/'); ?>">ABOUT</a></li>
<li><a href="<?php swfaddress_link('/CONTACT/'); ?>">CONTACT</a></li>
</ul>
</div>
<div><?php swfaddress_content(); ?></div>
</div>
<script type="text/javascript">
// <![CDATA[
(new SWFObject('<?php swfaddress_resource('/c.swf?datasource=datasource.php'); ?>', 'website', '400', '400', '9', '#FFFFFF', 'high')).write('content');
// ]]>
</script>

SWFAddress urls read out as http://www.domain.com/#/yourpagename.

The “#” is the signpost of an SWFAddress url. The URL is rewritten into http://www.domain.com/yourpagename/ which is the url that can be indexed. In the index.php this indexable url exists as a link in the html above. When someone visits the indexed address, a redirect is made to the SWFAddress url.

In the case of  Spiders/Bots the address is rewritten without any redirection to http://www.domain.com/?swfaddress=/yourpagename/.

If you right click on the example page either from your local running server or from the demo you will also see this at work with datasource. The datasource.php home content (first case statement) is written out to the page. So the datasource is basically what it sounds like: the data for the spider and indexable content.

So for each section in my dummy site there exists some latin text in the swf. It is just hard copied into my concrete Decorator (or whatever way you set things up with content if you build it from scratch in AS3). And then I just take that content and put that into the datasource.php for each section to mash up some searchable content reflecting the site.

A small caveat to throw in here if we go back to the screenshot of the project folder: notice the occurrence of a “c.swf” file. This is a very minimal stripped down loader that just loads in the main .swf. The reason for doing so is that if you have  a preloader in your main .swf, it will not work with the deep linked pages. It will only work with your direct url. This is so since the deep linked pages (for some reason) are reloaded twice. So having a thin loader that just loads the site will stop your preloader in your main.swf from breaking.

I will not say that much about how to implement the ActionScript API here as it’s already been covered a lot in posts. Just have a look at SWFAddressSite.as. This class imports the two classes SWFAddress.as and SWFAddressEvent.as. We then listen for an update from the API:

1
    SWFAddress.addEventListener(SWFAddressEvent.CHANGE, getValue);

The showPageByMenu() function sets the value of SWFAddress with the static method setValue:

1
    SWFAddress.setValue("/"+e.currentTarget.name)

All that is then needed to be able to trigger the different section’s from the browser is a way to read the value. The value comes as a property of the SWFAddressEvent object:

1
2
3
private function getValue (e:*):void {
    showPageByAddress(e.value);
}

And of course always set the value before you read it. That’s about it.

EventCurb.as , removeAllListeners(object)

In AS3 we can check if an object has listeners, as in:

1
if(object.hasEventListener( type))

. But there is no method for getting all the listeners of an object. Or more importantly for removing all of them. Doh.

The hackish approach to this is to subclass EventDispatcher and write some short code that keeps a reference to each listener.

Which is what my class EventCurb does. – I should say it’s written overnight so anyone that likes can go ahead and try break their application…

Usage is as Singleton:

1
var _ev: EventCurb = EventCurb.getInstance();

To add listener:

1
2
_ev.addListener(obj, MouseEvent.MOUSE_DOWN, someFunc);
_ev.addListener(obj, MouseEvent.MOUSE_UP, someFunc);

If you try to add the same listener twice you will get a trace telling you that listener is already added, and no addition occurs.

To get all listeners of an object:

1
_ev.getListeners(obj);

This returns an Array of all listeners assigned to object which can be traversed as arr[index].type, arr[index].listener.

To remove listener of object:

1
2
_ev.removeListener(obj, MouseEvent.MOUSE_DOWN, someFunc);
_ev.removeListener(obj, MouseEvent.MOUSE_UP, someFunc);

And finally to remove All listeners of an object:

1
_ev.removeAllListeners(obj);

You can copy the class from below or download it from here. Feel free to rewrite or improve upon as you so wish.

EventCurb.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package
{
import flash.events.EventDispatcher;
import flash.utils.Dictionary;
/**
* ...
* @author Thomas James Thorstensson
* @version 1.0.1
*/

public class EventCurb extends EventDispatcher
{
private static var instance:EventCurb= new EventCurb();
private var objDict:Dictionary = new Dictionary(true);
private var _listener:Function;
private var objArr:Array;
private var obj:Object;

public function EventCurb() {
if( instance ) throw new Error( "Singleton and can only be accessed through Singleton.getInstance()" );
}

public static function getInstance():EventCurb {
return instance;
}

override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
{
super.addEventListener(type, listener, useCapture, priority, useWeakReference);
}

override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
{
super.removeEventListener(type, listener, useCapture);
}

public function addListener(o:EventDispatcher, type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void {
// the object as key for an array of its event types
if (objDict[o] == null) objArr = objDict[o] = [];
for (var i:int = 0; i &lt; objArr.length; i++) {
if ( objArr[i].type == type)
trace ("_______object already has this listener not adding!")
return
}
obj = { type:type, listener:listener }
objArr.push(obj);
o.addEventListener(type, listener, useCapture, priority, useWeakReference);
}

public function removeListener(o:EventDispatcher, type:String, listener:Function, useCapture:Boolean = false):void {
// if the object has listeners (ie exists in dictionary)
if (objDict[o] as Array !== null) {
var tmpArr:Array = [];
tmpArr = objDict[o] as Array;
for (var i:int = 0; i &lt; tmpArr.length; i++) {
if (tmpArr[i].type == type) objArr.splice(i);
}

o.removeEventListener(type, listener, useCapture);
if (tmpArr.length == 0) {
delete objDict[o]
}
}else {
trace("_______object has no listeners");
}
}

/**
* If object has listeners, returns an Array which can be accessed
* as array[index].type,array[index].listeners
* @param o
* @return Array
*/

public function getListeners(o:EventDispatcher):Array{
if (objDict[o] as Array !== null) {
var tmpArr:Array = [];
tmpArr = objDict[o] as Array;
// forget trying to trace out the function name we use the function literal...
for (var i:int = 0; i &lt; tmpArr.length; i++) {
trace("_______object " + o + " has event types: " + tmpArr[i].type +" with listener: " + tmpArr[i].listener);
}
return tmpArr

}else {
trace("_______object has no listeners");
return null
}

}

public function removeAllListeners(o:EventDispatcher, cap:Boolean = false):void {
if (objDict[o] as Array !== null) {
var tmpArr:Array = [];
tmpArr = objDict[o] as Array;
for (var i:int = 0; i &lt; tmpArr.length; i++) {
o.removeEventListener(tmpArr[i].type, tmpArr[i].listener, cap);
}
for (var p:int = 0; p &lt; tmpArr.length; p++) {
objArr.splice(p);
}

if (tmpArr.length == 0) {
delete objDict[o]
}
}else {
trace("_______object has no listeners");
}
}
}
}

Flash Builder 4 : vertical+horizontal centering
of swf in ActionScript projects

Flashdevelop It’s possible to edit the html wrapper that Flash Builder generates for the output swf – so that it centres any swf both horizontally and vertically without Flashbuilders default and slightly strange scaling.

The hack comes from how I’ve had this setup in Flashdevelop with SWFObject and only requires a few lines of CSS:

1
2
3
4
5
6
7
8
9
10
11
<style>
      #divFloat {
      position:absolute;
      top:50%;
      left:50%;
      right:50%;
      bottom:50%;
      margin:-300px;       /* Half the height of your SWF*/
      margin-left:-400px; /* Half the width of your SWF*/
   }
   </style>

To get this to work all that is needed is a div with the matching id ‘divFloat’ added to the html body of the html page that acts as a wrapper for the swf; and this will centre the swf vertically and horizontally.

Based on the CSS above we can device a similar approach and apply it to Flash Builder’s publishing method. The part to figure out is how to insert it into Flash Builders template based creation of the html wrapper.

To do so we must edit the index.template.html in the html-template folder in the Flash Builder project directory: which is the blueprint for the html file generated in the bin-debug folder.

In Flash Builder our html wrapper and swf will be based on what name we choose for our main application file (the one that initializes our application). This value is held by the variable ${application} in index.template.html. It is also the id of our embedded content in the html page that results in bin-debug, based on our index.template.

So we can write in index.template.html:

1
2
3
4
5
6
7
8
9
10
11
12
<style>
body { margin: 0px;}
#${application} {
      position:absolute;
      top:50%;
      left:50%;
      right:50%;
      bottom:50%;
      margin:-300px;       /* Half the height of your SWF*/
      margin-left:-400px; /* Half the width of your SWF*/
   }
</style>

If the application class has the name ‘OrangeApp.as’ that will translate into #OrangeApp{ in the resulting html file in the bin-debug folder and target the id of the embedded swf so that the CSS is applied to centre it.

Of course the swf still needs to have the following code in it’s application class:

1
2
stage.scaleMode = StageScaleMode.NO_SCALE
stage.align = StageAlign.TOP_LEFT

Also specify the width and height of the swf in the index.template.html as usual by just replacing ‘width’ and ‘height’ with the real width and height of our swf. That will center html the swf in Flash Builder; and remove the pesky default ‘Flex scaling’ without too much work!

Formatting XML text with html tags +
the TextFormat Class

Recently I wrongly came to the conclusion that you can’t apply a TextFormat to dynamic textfield set to htmlText = “My text” without that the TextFormat overwrites the formatting done with html tags in the XML.

It turns out that the issue I was having had more to do with not being read up on the defaultTextFormat setter.

Let us take Arial as an example. To embed it in AS3 in bold, italic, and normal formatting we would like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package
{
   import flash.display.*;
   import flash.text.*;

   /**
    * ...
    * @author Thomas James Thorstensson
    */

   public class TextFmt extends Sprite
   {

      [Embed(source='C:/Windows/Fonts/arial.ttf'
      ,fontFamily ='arialNormal'
      ,fontStyle ='normal' // normal|italic
      ,fontWeight ='normal' // normal|bold
      ,unicodeRange='U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E'
      //,cff='false'
      )]
      public static const arialNormal:Class;

      [Embed(source='C:/Windows/Fonts/arialbd.ttf'
      ,fontFamily ='arialBold'
      ,fontStyle ='normal' // normal|italic
      ,fontWeight ='bold' // normal|bold
      ,unicodeRange='U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E'
      //,cff='false'
      )]
      public static const arialBold:Class;
     
      [Embed(source='C:/Windows/Fonts/ariali.ttf'
      ,fontFamily ='arialItalic'
      ,fontStyle ='italic' // normal|italic
      ,fontWeight ='normal' // normal|bold
      ,unicodeRange='U+0020-U+002F,U+0030-U+0039,U+003A-U+0040,U+0041-U+005A,U+005B-U+0060,U+0061-U+007A,U+007B-U+007E'
      //,cff='false'
      )]
      public static const arialItalic:Class;

      public function TextFmt()
      {
         Font.registerFont(arialNormal);
         Font.registerFont(arialBold);
         Font.registerFont(arialItalic);
      }

   }
}

In our XML we can then directly refer to one of the versions of the font like so:

1
<xmlnode>Lorem ipsum<font face="arialItalic"> and some italic text</font> and end.</xmlnode>

If we set a dynamic textfield to the above content, we can still apply additional formatting to it
with a regular TextFormat as long as we use defaultTextFormat rather than setTextFormat :

1
2
3
4
5
6
arialNormal = new TextFormat();
arialNormal.font = 'arialNormal';
arialNormal.size = 11;
arialNormal.color = 0xCCCCCC;
myText.defaultTextFormat = arialNormal;
myText.htmlText= xmlnode;

The dynamic textfield will take the ‘arialNormal’ format without the arialItalic format being overwritten. The italic style will so to speak take on the arialItalic and the arialNormal.

If we instead would use setTextFormat after myText.htmlText= xmlnode; it would be the case that the formatting in the html would be overwritten by the TextFormat.

Augmented reality, lab 1

Better late than never as I’ve began to delve into Augmented Reality.

There’s much inspiring work going on in the AR community. The QT movie above is just a brief demo based on the start toolkit for FLAR over at http://saqoosha.net/en/flartoolkit/start-up-guide/ – slimmed down by me for Flashdevelop. The bitmap material is from Scuba’s latest album, Triangulation…

I’m currently looking at learning more about markers; and it’s been pointed out to me that there’s a useful marker generation tool here: http://flash.tarotaro.org/blog/2009/07/12/mgo2/.

Papervision3D, FlashDevelop template

Flashdevelop Here’s a simple FlashDevelop template to speed up the creation of a 3D render in Papervision3D 2.0. Download the template from here or copy the code below and save it as View3D.as.fdt.

In FlashDevelop go to Tools –> Application files. This will open your Explorer: Now go into the folder Templates > ProjectFiles > AS3Project and drop the template in there.

You will now if you left click on your src package and go to Add > see the option ‘BasicView’ in the menu that pops up.

The custom arguments available for template creation are listed at http://www.flashdevelop.org/community/viewtopic.php?t=1521

Here’s the template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package $(Package) $(CSLB){

   import flash.events.Event;
   import org.papervision3d.view.BasicView;

   public class $(FileName) extends BasicView {
      $(EntryPoint)
      /**
      * $(FileName)
      */

     
      public function $(FileName)():void {
         init();
         startRendering();
      }

      private function init():void {
      }
     
      override protected function onRenderTick(e:Event=null):void{
         super.onRenderTick();
      }
   
   }
}

Lastly, a good set of templates can be found over at http://www.actionscriptdeveloper.co.uk/puremvc-first-thoughts-flashdevelop-templates/