ActionScript 游戏,在实现装饰器时遇到问题 class

ActionScript game, having trouble implementing decorator class

所以,我在 ActionScript 中创建了一个基于方块的 "match 3" 游戏,其中有几种不同类型的方块,主要方块只是字母方块,还有特殊方块,例如炸弹每个磁贴都有相似的功能,但每个磁贴都有特殊的功能。

现在,我只有一个 Tile class 可以处理所有功能,这不是可行的方法。我认为装饰器 class 是最好的方法,但是实现它,我 运行 遇到了问题。

下面是我的结构,我将如何处理将图块存储在 Vector 中?我将如何添加到舞台上?

目前,我将图块存储在 Vector 中。(我有一个图块 class 可以处理所有丑陋的类型)。如果我要转向装饰器模式,似乎我将存储一个 ITile 向量,我将如何添加 "Itiles" ,它们本质上是 LetterTiles 和 BombTiles 到阶段?我在尝试时遇到类型强制错误。

此外,装饰器模式似乎基本上是一个接口,所有类型都会实现它,例如,如果我要在舞台上使用现有的 LetterTile 并说它需要转换为 BombTile,如何我会着手将当前图块更改或更新为炸弹图块吗?

示例:

public interface ITile
{
    function create():void;
    function remove():void;
}

和BaseTile.as

public class BaseTile extends Sprite
{
    public function create():void
    {
        throw new IllegalOperationError("Must override in concrete class");
    }

    public class remove():void
    {
        throw new IllegalOperationError("Must override in concrete class");
    }
}

LetterTile.as

public class LetterTile extends BaseTile implements ITile
{
    public override function create():void
    {
        trace("Letter Tile Created");
    }

    public override function remove():void
    {
        trace("Letter Tile Removed");
    }
}

BombTile.as

public class BombTile extends BaseTile implements ITile
{
    public override function create():void
    {
        trace('Bomb tile created');
    }

    public override function remove():void
    {
        trace('Bomb tile removed');
        doExplosion();
    }

    public function doExplosion():void
    {
         //This would do something different than regular letter tile.
    }
}

希望这是有道理的,我需要在不创建 TL;DR 的情况下尽可能多地添加信息

如果您只想使用装饰器,您可以将其视为使您的图块与数据对象不同的东西,然后 "Decorate" 具有提供功能的 "shell" 的数据。

所以:

public class Bomb implements ITileData {
    public function get tileName():String{
        return 'bomb';
    }

    public function get specialEvent():Event{
        return new BombEvent();//you'd write this class elsewhere
    }

    public function get displayClass():DisplayObject {
        return BombSprite;
    }
}
   public class Tile extends Sprite {
       protected var _tileData:ITileData;
       public function Tile(tileData) {
           _tileData = tileData;
       }
       public function create():void {
           trace(_tileData.tileName, 'created');
           addChild(new _tileData.displayClass();
       }
       public function interact():void {
           dispatchEvent(_tileData.specialEvent);
       }
       //etc.
   }

但老实说,您不需要单独的 class 装饰来使它们看起来都一样。您可以只拥有一种数据对象类型,您可以根据需要加载数据。


编辑:我喜欢 Aaron 如何内联您的问题并说明他的代码如何回答问题。我要偷了

how would I add "Itiles" which are essentially LetterTiles and BombTiles to stage?

如图所示的 Tile class 扩展了 Sprite,因此您可以将它添加到舞台上。

if I were to take an existing LetterTile on stage and say it needs to convert to a BombTile, How would I go about changing or updating the current tile into a Bomb tile?

在上面的代码中,我将 ITileData 作为构造函数参数传入,但您可以通过 getter/setter 对设置 tileData 来轻松更改图块的类型。您想要删除旧图形并在 setter 触发时替换它。

specialEvent 会告诉您的父级 class 当用户与磁贴交互时发生了什么,而父级 class 将负责处理炸弹事件或信件的结果事件触发。

正如我在评论中所说,这并不是真正的 decorator pattern,它只是一个抽象 class BaseTile

回答你是使用装饰器还是基础的问题class:你需要使用转换。具体来说:

how would I handle storing the tiles in a Vector?

var tiles:Vector.<ITile> = new <ITile>[];

tiles.push(new BombTile());

要检查向量中有哪些特定的图块类型,请使用 is 运算符,然后使用 as 运算符转换为特定的图块类型:

for each(var tile:ITile in tiles){
    if(tile is BombTile){
        var bombTile:BombTile = tile as BombTile;
        bombTile.explode();
    }else if(tile is LetterTile){
        var letterTile:LetterTile = tile as LetterTile;
        letterTile.letter = "A";
    }
}

and how would I add to stage?

如果你有 ITile,你必须强制转换为显示对象:

stage.addChild(tile as DisplayObject);

如果您有一个 BaseTile,它已经扩展 Sprite,所以不需要转换。

if I were to take an existing LetterTile on stage and say it needs to convert to a BombTile, How would I go about changing or updating the current tile into a Bomb tile?

这真的取决于你到底想做什么。您不能将一个对象更改为另一个对象,但您当然可以通过各种方式替换它:

var tiles:Vector.<ITile> = new <ITile>[];
tiles.push(new LetterTile(), new LetterTile(), ...etc);

function replaceTile(existingTile:ITile, replacementTile:ITile):void {
    var index:int = tiles.indexOf(existingTile);
    stage.removeChild(existingTile as DisplayObject);
    tiles[index] = replacementTile;
    stage.addChild(replacementTile as DisplayObject);
}

function changeTileType(tile:ITile, type:Class):void {
    if( !(tile is type)){
        replaceTile(tile, new type());
    }
}

// Example:
changeTileType(tiles[0], BombTile);