Showing posts with label actionscript. Show all posts
Showing posts with label actionscript. Show all posts

Thursday, September 9, 2010

Message Oriented Architecture (Code 2/2)

Second and final part of the code.
private function _addEventListener(idChannel:String, type:String, listener:iEventListener):void {
   if(!(idChannel in hashChannel)) { // first add channel check
      // there is no hashType for that sender so we create one
      hashChannel[idChannel] = new Object();
   }
   if (!(type in hashChannel[idChannel])) { // first add type check
      // there is no such event listener registred
      hashChannel[idChannel][type] = new Array();
   }
   var array:Array = hashChannel[idChannel][type] as Array;
   if(array.indexOf(listener) != -1) { // second add listener check
      // the array does contain "listener", so we don't add twice
      return;
   } else {
      // the only really useful code
      array.push(listener);
   }
}
 
Be careful with all those checks, without them, you could have problems. By example if you put the EventCenter as an external project like me, you don't have to change for each project the type of channels, types etc. So keep in mind that you need to check each time if the channel exist, if the type exist etc. The code itself is not complex but the number of case could me it hard to understand. Now you know of to add a listener. Let's see of to remove on, that is the last part.
private function _removeEventListener(idChannel:String, type:String, listener:iEventListener):void {
   if(!(idChannel in hashChannel)) {
      // there is no hashType for that sender so we return
      return;
   }
   var hashType:Object = hashChannel[idChannel];
   if (!(type in hashType)) {
      // You try to remove a listener that has not the good type
   } else {
      var array:Array = hashType[type] as Array;
      var index:int = array.indexOf(listener);
      if(index != -1) {
         // remove the listener from the array
         array.splice(index, 1);
         if (array.length == 0) {
            // the array is empty, so we delete it
            delete hashType[type];
         } else {
            hashType[type] = array;
         }
      } else {
         // the listener is not in the array
      }
   }
}
 
The splice method of Array, permit the deletion when we specify the index of the item and 1 as the number of item we want to remove. When we need Array.remove(item), we need to use Array.splice(Array.indexOf(item), 1), but be careful, if you forget to write the "1" all the array from the index will be removed, quite hard to find in debug.
I think we are done with the subject of EventCenter, good luck using this new way of messaging.

Message Oriented Architecture (Code 1/2)

Here I present you the code of the EventCenter. I show your parts of code incrementally, to be able to add some comments at each step.
public class EventCenter {
   private static var instance:EventCenter = new EventCenter();
   private var hashChannel:Object;
   
   public function EventCenter():void {
      this.hashChannel = new Object();
   }
 
You have here the initial code of the class. We use the singleton pattern without any protection, you can improve that if you want but it's not the goal of this tutorial. The only one variable of this class is the hashChannel that is the HashMap that contains the different channels. In ActionScript 3, we don't have native HashMap like in Java, but we have the Object class that can contains dynamical property like an HashMap.
public static function reset():void {
      instance = new EventCenter();
   }

   public static function dispatchEvent(idChannel:String, type:String, args:Object = null):void {
      instance._dispatchEvent(idChannel, type, args);
   }

   public static function addEventListener(idChannel:String, listener:iEventListener, ...type):void {
      for each(var t:String in type) {
         instance._addEventListener(idChannel, t, listener);
      }
   }

   public static function removeEventListener(idChannel:String, listener:iEventListener, ...type):void {
      for each(var t:String in type) {
         instance._removeEventListener(idChannel, t, listener);
      }
   }
 
This part of the code is actually the interface we show to the world. All those methods are public static, we could also add final but it's out of the bounds of this tutorial. All the real code is hidden in the instance field. The reset method only serves if you want to reinitialize the EventCenter. The idChannel is the identifier of the channel on/from which we send/receive messages. The iEventListener listener is the object that will receives the message, we call its method onEvent with the correct arguments. Finally the ...type allows us to add as many type as we want thanks to the "..." syntax that will transform type into an Array.
public interface iEventListener {
   function onEvent(type:String, args:Object):void;
}
 
Here is the simple code for the interface. One iEventListener can listens to as many Channel as it wants. It is the time to show the concrete code:
private function _dispatchEvent(idChannel:String, type:String, args:Object):void {
   if(idChannel in hashChannel) {
      var hashType:Object = hashChannel[idChannel];
      if (type in hashType) {
         this._dispatch(hashType, type, args);
      } else {
         // No such listener
      }
   } else {
      // there is no listener for this sender
   }
}
 
We use the properties of objects to store elements in the pseudo HashMap. You can notice the "in" operator that is quite faster than the "hasProperty...". With this, we know if there is an entrance with key=idChannel, if so, we know there are some listener for that channel. Then, we search into the HashMap corresponding to the channel if there is the type we look for, in this case we can call the _dispatch sub-function.
private function _dispatch(hashType:Object, type:String, args:Object):void {
   var array:Array = hashType[arrayType] as Array;
   if (!array) { // first assert
      // The array is null
      delete hashType[type];
   } else {
      if (array.length == 0) { // second assert
         // Array is empty => property removed
         delete hashType[arrayType];
      } else {
         for each(var listener:iEventListener in array) {
            listener.onEvent(type, args);
         }
      }
   }
}
 
As you will see in other function, especially in "_removeEventListener" we never keep an Array of listeners empty or null, so I call the two conditions "assert". Normally we never came into their braces.
This function allow us to dispatch / trigger / fire an event to all the corresponding listeners. The args contains also an HashMap.
Here is some examples of use:
EventCenter.dispatchEvent("Score_Channel", "Reset_Score");
EventCenter.dispatchEvent("Score_Channel", "Add_Score", {incr:13});
EventCenter.dispatchEvent("Score_Channel", "Decrease_Score", {decr:11});
EventCenter.dispatchEvent("Score_Channel", "Change_Score", {old:12, new:39, forPlayer:'Bob'});
 
The args is optionnal and moreover could have as many item as you want, identified by the keys. I think this is the most flexible we can do. Remember how complex it is with the native system of event. You have to create a new type of Event for each... new type you want. But with my solution, you just have to change the name. For my use, I always make constants representing the events with in commentary the format of the keys, with that when I code a dispatch, I always see with the doc, what is the format. Next part of the code, in next message.

Friday, September 3, 2010

Tools ?

What are the tools we can use to draw/code a game in ActionScript3 ?

The best tool to design some flash is the classic Flash CS5. The problem with Flash CS5 is that you can draw, design, animate all your things but not really code. Actually you can, but it's horrible, like coding with a pen and paper : no good auto completion, no incremental compilation, lots of error message that are not very useful etc. Get Flash CS5

The best new things with CS5 is the integration of Flash Builder (previously Flex Builder) with Flash IDE. With Flash Builder you can write your code very easily. The bridge between both program is relatively easy to use. It is a plugin for Eclipse. There is a lot of functionalities that make your coding "effort" as low as possible. Get Flash Builder

Because I like incremental things, the third tool I present you now is (for me) better than the two other. It is FDT. Also a plugin for Eclipse (that is really nice for Java coding), FDT is for me, the most intuitive tool for ActionScript 3. It has approximatively the same advantage as Flash Builder but the team behind is more reactive. Get FDT

Now, not necessarily the best, but the most profitable because it is free, FlashDevelop. Very nice to code with, it is based on Visual Studio Layout, you have a lot of options, you can link projects directly with your IDE etc. You can notice that FlashDevelop has the best auto completion I never seen before: when you type a word like "add" the IDE also propose you "onAdded" function. It's very useful when you code function with some prefix modifiers like get, set, link, add, etc. Get FlashDevelop, it's free, try it !


Now, I hope, you are ready to start coding ActionScript 3 and making good games.