Nov
9
CommandQueue – memento, undos and more

I’ve been experimenting with creating a sort of queue pool of commands that could be executed at any specified interval.  But rather than creating a glorified tween sequencer, I wanted to have it be more generic and be able to “save” the previous state.   The way I did this is via the often blogged about deep object copying using serialization.  Unfortunately, it’s not possible to deep object copy a sprite or MovieClip directly so instead I added a type or proxying as well.

This is really the 0.1 verision of the class with quite a few bug fixes probably needed down the road but it shows some of the over-all concepts.


package com.pj_co.core
{
        import com.pj_co.interfaces.IRegisteredDispatcher;
        import com.pj_co.models.Command;
        import com.pj_co.util.ObjectUtils

        import flash.utils.Timer;
        import flash.net.registerClassAlias;
        import flash.net.getClassByAlias
        import flash.events.TimerEvent;
        import flash.events.EventDispatcher;

        /**
        * Cues commands using a timer based upon the delay param passed to the addCommand method
        * @author Patrick Cousins    pj@pj-co.com
        * @version 0.1
        */
        public class CommandQueue extends EventDispatcher //implements IRegisteredDispatcher
        {

                private var					queuePool			: Array;
                private var					_undoObjArray		: Array;

                private var					_index				: uint				= 0;
                private var					_isRunning			: Boolean			= false;
                private var					looping				: Boolean			= false;
                private var					numOfTimesToRun		: uint				= 0;

                private var					timer				: Timer;
                private var					direction			: String;

                public static const			PLAY_FORWARD		: String			= "playCommandQueueForward";
                public static const			PLAY_REVERSE		: String			= "playCommandQueueReversed";

                function CommandQueue ( )
                {
                        init ( ) ;
                }

                public function get index			():uint 	{ return _index; }
                public function get isRunning		():Boolean 	{ return _isRunning; }
                public function get undoObjArray	():Array 	{ return _undoObjArray; }

                private function init ( ):void
                {
                        queuePool 		= new Array ( ) ;
                        _undoObjArray	= new Array ( ) ;
                }

                public function addCommand ( 	func		: Function,
                                                                       argArray 	: Array 	= null,
                                                                       delay 		: uint 		= 0,
                                                                       obj			: *			= null,
                                                                       objClass	: Class 	= null,
                                                                       useDeepCopy : Boolean	= false
                ) : void
                {
                        // the problem with args is we need to apply them to the func in
                        // a way that matches that method's signature

                        var command 	: Command 		= new Command ( ) ;

                        command.func			 		= func;
                        command.args 					= argArray;
                        command.delay 					= delay;
                        command.obj						= obj;
                        command.objClass				= objClass;
                        command.useDeepCopy				= useDeepCopy;

                        queuePool.push ( command ) ;

                }

                public function execute ( 	direction 		: String 	= CommandQueue.PLAY_FORWARD,
                                                         numOfTimesToRun : uint 		= 1
                ) : void
                {
                        this.direction 			= direction;
                        this.numOfTimesToRun 	= numOfTimesToRun;
                        _isRunning 				= true;
                        looping					= numOfTimesToRun != 1 ? true : false

                        runNext ( ) ;

                }

                public function stop ( ) : void
                {
                        try
                        {
                                timer.removeEventListener 		( TimerEvent.TIMER_COMPLETE, runCommand ) ;
                                timer.stop 						( ) ;
                                timer 							= null;
                        }
                        catch ( e : Error )
                        {
                                //no timer to remove
                        }
                        finally
                        {
                                _isRunning = false;
                        }
                }

                private function runNext ( ) : void
                {

                        if (  _index >= queuePool.length   ||  _index < 0   )
                        {

                                if ( looping && numOfTimesToRun > 1 )
                                {
                                        numOfTimesToRun --;
                                        runQueue ( ) ;
                                }
                                else if ( looping && numOfTimesToRun == 1 )
                                {
                                        looping = false;
                                        numOfTimesToRun --;
                                        runQueue ( ) ;
                                }
                                else
                                {
                                        stop ( ) ;
                                }

                        }
                        else
                        {
                                runQueue ( ) ;
                        }

                }

                private function runQueue (  ):void
                {
                        try
                        {
                                timer.removeEventListener 		( TimerEvent.TIMER_COMPLETE, runCommand ) ;
                                timer.stop 						( ) ;
                                timer 							= null;
                        }
                        catch ( e : Error )
                        {
                                //no timer to remove
                        }

                        var command 		: Command 		= queuePool [ _index ] ;
                        timer								= new Timer ( command.delay, 1 ) ;

                        timer.addEventListener 				( TimerEvent.TIMER_COMPLETE, runCommand ) ;

                        timer.start 						( ) ;
                }

                private function runCommand ( te : TimerEvent ) : void
                {

                        var command 		: Command 		= queuePool [ _index ] ;
                        var argsWithObj 	: Array			= command.args

                        makeCopy ( command ) ;
                        argsWithObj.unshift	( command.obj ) ;
                        command.func.apply ( null, argsWithObj ) ;
                        timer.removeEventListener ( TimerEvent.TIMER_COMPLETE, runCommand ) ;

                        _index								= direction == CommandQueue.PLAY_FORWARD ? _index + 1 : _index - 1;
                        runNext ( ) ;
                }

                private function makeCopy ( cmd : Command ) : void
                {
                        trace ( "makeCopy" ) ;
                        var undoObj : *
                        trace ( cmd.useDeepCopy ) ;
                        if ( cmd.useDeepCopy  )
                        {
                                undoObj = ObjectUtils.deepCopy ( cmd.obj, cmd.objClass ) ;
                        }
                        else
                        {
                                undoObj = ObjectUtils.shallowCopy ( cmd.obj, cmd.objClass ) ;
                        }

                        _undoObjArray.push( undoObj );
                }

        }

}

filed under: ActionScript, Scripts | permalink

Leave a Reply

You must be logged in to post a comment.

© 2012 pajamacode | Theme by DemusDesign, Theme Lab, and Search Optimization | Powered by WordPress