I am going to create an application in that i have to implement an Undo and Redo feature. In the application there will be multiple objects located on stage and
Take a look at the command pattern. It's well suited to undo/redo type problems.
package com
{
import flashx.undo.IOperation;
public class UndoOperation implements IOperation
{
private var _previousX:Number = 0;
private var _previousY:Number = 0;
private var _previousObj:Object = new Object();
private var _currentX:Number = 0;
private var _currentY:Number = 0;
private var _currentObj:Object = new Object();
private var _shape:Object = new Object();
public function TransformOperation(currentObj:Object,previousObj:Object,previousX:Number, previousY:Number, currentX:Number, currentY:Number)
{
_previousX = previousX;
_previousY = previousY;
_previousObj = previousObj;
_currentX = currentX;
_currentY = currentY;
_currentObj = currentObj;
_shape = _currentObj;
trace('Transform _previousX: '+ _previousX +' _previousY: ' +_previousY+' _currentObj '+_currentObj+' _shape '+_shape);
trace( 'trans _currentX '+ _currentX +' '+'_currentY '+ _currentY );
}
public function performUndo():void
{
_shape = _currentObj;
//trace('_shape.x '+_shape.x+" _shape.y "+_shape.y);
_shape.x = _previousX;
_shape.y = _previousY;
//trace(_previousX +' '+ _previousY +' '+ _previousWidth +' '+ _previousHeight +' '+ _previousScaleX +' '+ _previousScaleY +' '+ _previousRotation);
//trace('_shape.x '+_shape.x+" _shape.y "+_shape.y);
//trace('_currentX '+ _currentX +' '+'_currentY '+ _currentY);
}
public function performRedo():void
{
_shape.x = _currentX;
_shape.y = _currentY;
trace(_currentX+' '+ _currentY);
}
}
}
This is my customize class afor undo and redo multiple objects on stage. There is different pattern which can be used for the undo and redo operation but for me this is the simple way for undo and redo. I have perfectly and successfully implement this in my project.
To Use this class only import the class
import flashx.undo.UndoManager;
and after that
public static var _undo:UndoManager=new UndoManager();
public static var _redo:UndoManager=new UndoManager();
public static var PrevX:Number=0;
public static var PrevY:Number=0;
var operation:TransformOperation = new TransformOperation(this,this,PrevX,PrevY,this.x,this.y);
_undo.pushUndo(operation);
After that create click event for undo and redo:
public static function Undo(e:MouseEvent):void
{
_redo.pushRedo(_undo.peekUndo());
_undo.undo();
if(_undo.peekUndo()==null)
{
PlayerPosition.getClass.getChildByName("toolbar_mc").getChildByName("undo_mc").removeEventListener(MouseEvent.CLICK,Undo);
}
PlayerPosition.getClass.getChildByName("toolbar_mc").getChildByName("redo_mc").addEventListener(MouseEvent.CLICK,Redo);
}
public static function Redo(e:MouseEvent):void
{
_undo.pushUndo(_redo.peekRedo());
_redo.redo();
if(_redo.peekRedo()==null)
{ PlayerPosition.getClass.getChildByName("toolbar_mc").getChildByName("redo_mc").removeEventListener(MouseEvent.CLICK,Redo);
}
PlayerPosition.getClass.getChildByName("toolbar_mc").getChildByName("undo_mc").addEventListener(MouseEvent.CLICK,Undo);
}
For me this works fine... Hope this helps others too...:)
If you only want two different states (default and "changed"), it should be pretty trivial to implement. Store the new values and the updated values for each object in arrays, and set the positions from the relevant array when you press "undo" or "redo".
If you need something more complicated, you could store everything you do as an "action" which is undoable. Eg, there is a class (for example "Action") with several child classes ("Move", "ChangeColor" etc). They contain the change they perform (how many pixels we should move) and methods for performing the action (move object X pixels) and undoing the action (move object -X pixels).
the simplest way I can think of is creating an action object, where you have the old state and the new state and the object that changed.
every time an action that would get an undo feature is fired, fill out this data in the action object
when you hit undo, revert to the before state of the object and push the action into the redo stack.
This should be able to handle most common changes. Things like delete/undelete need a little extra tweaking. I would just put in all properties at the time of deletion, and use a create function when handling the undo.
I would suggest using a string for parameters and value combinations for the before and after states, that way you can handle additional functions without changing the undo/redo functionality.
This is more of a quick and dirty way, you can also do it using design patterns and proper OOP ways of dealing with this as others have mentioned.