Using Mementos to Make Actions Redoable in the Proximity Game


Now that we have added an undo feature to the Proximity game, we'll complete our modifications to the game by adding code that redoes actions we have just undone.

Defining the Redoable Command

The first step in making the commands redoable is to create a redoable command class. Define a class, com.peachpit.aas3wdp.proximity.commands.RedoableGamePlayCommand, that extends UndoableGamePlayCommand and adds redo functionality by implementing IRedoableCommand.

     package com.peachpit.aas3wdp.proximity.commands {         import com.peachpit.aas3wdp.proximity.data.PieceData;         import com.peachpit.aas3wdp.proximity.data.GamePlayer;         import com.peachpit.aas3wdp.proximity.data.GamePlayers;         import com.peachpit.aas3wdp.proximity.data.GameboardData;         import com.peachpit.aas3wdp.proximity.commands.UndoableGamePlayCommand;         import com.peachpit.aas3wdp.iterators.IIterator;         import com.peachpit.aas3wdp.proximity.mementos.GamePieceMemento;         import com.peachpit.aas3wdp.commands.IRedoableCommand;         import com.peachpit.aas3wdp.proximity.data.NullOwner;         public class RedoableGamePlayCommand extends UndoableGamePlayCommand implements             IRedoableCommand {            private var _nextGamePieceMemento:GamePieceMemento;            public function RedoableGamePlayCommand(piece:PieceData) {               super(piece);            }            override public function undo():void {               _nextGamePieceMemento = GameboardData.getInstance().newGamePiece.getMemento();               super.undo();            }            public function redo():void {               var gameboard:GameboardData = GameboardData.getInstance();               var newGamePiece:PieceData = gameboard.newGamePiece;               var currentGamePlayer:GamePlayer = newGamePiece.owner;               _piece.owner = currentGamePlayer;               _piece.count = newGamePiece.count;               // Retrieve all adjacent pieces.               var iterator:IIterator = gameboard.getProximityPieces(_piece);               var piece:PieceData;               while(iterator.hasNext()) {                  piece = PieceData(iterator.next());                  // If the game piece has the same owner as                   // the clicked game piece, increment the                  // count. If they have different owners (and                   // the owner isn't NullOwner) then test if                   // the clicked game piece has a higher                  // count. If so, make it the new owner.                  if(piece.owner == _piece.owner) {                     piece.count++;                  }                  else if(!(piece.owner is NullOwner)) {                    if(piece.count < _piece.count) {                       piece.owner = currentGamePlayer;                    }                  }               }               GameboardData.getInstance().setMemento(_nextGamePieceMemento);             }          }       }


The redoable command redoes a command by essentially replaying based on the new game piece. It then uses a memento to restore the next new game piece state.

Editing the Factory Class

Next we'll edit the CommandFactory class so that it returns a RedoableGamePlayCommand object when the type property is set to REDOABLE. Here's the updated getGamePlayCommand() method:

     public static function getGamePlayCommand(data:PieceData):ICommand {         if(_type == NORMAL) {            return new GamePlayCommand(data);         }         else if(_type == UNDOABLE) {           return new UndoableGamePlayCommand(data);         }         else if(_type == REDOABLE) {            return new RedoableGamePlayCommand(data);         }         return null;     }


Editing the Main Class

Now we can edit the main class by assigning a value of REDOABLE rather than UNDOABLE to the CommandFactory.type property.

     CommandFactory.type = CommandFactory.REDOABLE;


Add an if clause to the onKeyboard() method so that it calls the redo() method of the next command object in the stack when the user presses the right-arrow key:

     private function onKeyboard(event:KeyboardEvent):void {         var stack:CommandStack = CommandStack.getInstance();         var command:ICommand;         if(event.keyCode == Keyboard.LEFT && stack.hasPreviousCommands()) {            command = stack.previous();            if(command is IUndoableCommand) {               IUndoableCommand(command).undo();               }               else               {                 stack.next();               }            }            // If the user pressed the right arrow key and there are next            // commands in the stack, and if the command is redoable, call             // redo().           if(event.keyCode == Keyboard.RIGHT && stack.hasNextCommands()) {              command = stack.next();              if(command is IRedoableCommand) {                 IRedoableCommand(command).redo();              }              else {                 stack.previous();              }          }      }


When you test the application now, you can press the right-arrow key to redo any action that you've previously undone.




Advanced ActionScript 3 with Design Patterns
Advanced ActionScript 3 with Design Patterns
ISBN: 0321426568
EAN: 2147483647
Year: 2004
Pages: 132

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net