用现代的OO C语言做这个的好方法?

时间:2009-05-26 11:54:23

标签: c# java c++ data-structures

我有Tile代表游戏二维世界中的牌。瓷砖的4面可以有任意数量的墙。我现在有这样的事情:

interface Tile {
    boolean isWallAtTop();
    boolean isWallAtRight();
    boolean isWallAtLeft();
    boolean isWallAtBottom();
}

在其他地方我也有16张图片,每张图片都有一张图片。像这样:

static final Image WALLS_ALL_AROUND = ...
static final Image WALL_ON_TOP_AND_RIGHT = ...
/* etc etc all 16 possibilities */

我想写一个

static Image getWallImage(Tile tile)

我想要避免是对经历诸如

之类的可能性的折磨
if (tile.isWallTop && tile.isWallRight 
    && !tile.isWallBottom && !tile.isWallLeft) {
    return WALL_ON_TOP_AND_RIGHT;
}

有没有人知道这样做的可行方法?

7 个答案:

答案 0 :(得分:15)

Go go小工具位掩码。对每个瓷砖使用4位掩模,说明哪一面有墙。

A B C D

位A表示顶部的墙,B表示右侧,C表示底部,D表示左侧。定义常量以帮助您在逻辑上与掩码相交,即

if (tile.Walls & (WALL_LEFT | WALL_RIGHT))
  // Do stuff

为了找到图像,这个4位掩码产生16种可能性。使用它作为图像“数组”的索引,这样您就可以毫不费力地直接找到正确的图像。

答案 1 :(得分:4)

tile对象是否有其他属性?如果不是(或者你可以将它们分解出来),你可以将tile对象本身变成16个常量的枚举,并使用Tile.getImage()方法返回传递给构造函数的固定图像。这称为Flyweight pattern

class Tile {
    public final boolean isWallAtTop;
    public final boolean isWallAtRight;
    public final boolean isWallAtLeft;
    public final boolean isWallAtBottom;
    public final Image image;

    private Tile(boolean top, boolean right, boolean left, 
                 boolean bottom, Image image)
    {
        this.isWallAtTop = top;
        this.isWallAtRight = right;
        this.isWallAtLeft = left;
        this.isWallAtBottom = bottom;
        this.image = image;
    }

    public static final Tile WALLS_ALL_AROUND = 
        new Tile(true, true, true, true, new Image("allWalls.png"))
    // more constants here, plus other methods that work with
    // only the wall data
}

在Java中,您甚至可以将其实现为“真正的”枚举。

对于由图块组成的地图,您可以拥有一个简单的二维Tile引用数组,或者如果您需要其他数据用于单个图块,则需要另一个包含“其他数据”的SpecificTile类以及对上面一个Tile对象的引用。

答案 2 :(得分:2)

我建议像下面那样创建一个标志枚举。

[Flags]
public enum WallLocations
{
    None = 0,
    Left = 1,
    Right = 2,
    Top = 4,
    Bottom = 8
}

然后,您可以使用字典从墙壁位置映射到图像。

Dictionary<WallLocations, Image> map = new Dictionary<WallLocations, Image>();

map.Add(WallLocations.None, image0000);
map.Add(WallLocations.Left, image1000);
map.Add(WallLocations.Right, image0100);
map.Add(WallLocations.Top, image0010);
map.Add(WallLocations.Bottom, image0001);
map.Add(WallLocations.Left | WallLocations.Right, image1100);
// ....

至少在C#中,您还可以使用所有16​​个案例扩展枚举定义。

[Flags]
public enum WallLocations
{
    None = 0,

    Left = 1,
    Right = 2,
    Top = 4,
    Bottom = 8,

    LeftAndRight = Left | Right,
    LeftAndTop = Left | Top,
    LeftAndBottom = Left | Bottom,
    RightAndTop = Right | Top,
    RightAndBottom = Left | Bottom,
    TopAndBottom = Top | Bottom,

    AllExceptLeft = Right | Top | Bottom,
    AllExceptRight = Left | Top | Bottom,
    AllExceptTop = Left | Right | Bottom,
    AllExceptBottom = Left | Right | Top,

    All = Left | Right | Top | Bottom
}

答案 3 :(得分:0)

你能不能用旗帜枚举做什么?

答案 4 :(得分:0)

您应该将墙配置放入单个变量中,并构建此变量到平铺图像的映射。

答案 5 :(得分:0)

不是将WALLS_ALL_AROUND设为图像,而是将其作为包含图像的对象,以及处理允许的移动和诸如此类所需的任何其他逻辑。在Location对象中,您可以将walls属性设置为WALLS_ALL_AROUND,您可以查询该图像并处理与其他墙相关的逻辑。

由于每组图像只需要16个这些(不可变)对象的实例(如果你只有一组图像,每个图像可能是Tile的单个子级),你也可以节省内存。 / p>

答案 6 :(得分:0)

一个体面的OO解决方案可能涉及Strategy Pattern。一种可能的实现方式是使用WallConfiguration类和WallFactory来创建它们。然后,Tile将包含WallConfiguration。实现(C ++风格)看起来像这样:

class Tile
{
private:
    WallConfiguration walls;
    // Other Tile data

public:
    enum Walls
    { 
        TOP,
        BOTTOM,
        LEFT,
        RIGHT,
        TOP_RIGHT,
        TOP_LEFT
        // Fill in the rest
    }; //Enums have a place!
    Tile(Walls wall)
    {
        walls = WallFactory.getConfiguration(wall);
    }

这方面的一个有趣的优点是,现在,当你添加爆炸墙的能力(并且来吧......你知道你要去,'因为我们都喜欢把事情搞砸了),你可以将这个职责添加到WallConfiguration类中,例如,当你炸掉左墙时,它会知道如何获得正确的自身实例。