2009-05-26 6 views
5

Tengo Tile s que representan las fichas del mundo bidimensional de un juego. Las fichas pueden tener paredes en cualquier número de sus 4 lados. Tengo algo como esto en la actualidad¿Una buena manera de hacer esto en el moderno lenguaje OO C-like?

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

En algún otro lugar que también tiene 16 imágenes, una para cada configuración de la pared del azulejo sea posible. Algo como esto:

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

Quiero escribir un

static Image getWallImage(Tile tile) 

Lo que me gustaría evitar es la tortura de pasar por las posibilidades como

if (tile.isWallTop && tile.isWallRight 
    && !tile.isWallBottom && !tile.isWallLeft) { 
    return WALL_ON_TOP_AND_RIGHT; 
} 

¿Hay alguien ¿sabes una manera más linda de hacer esto?

Respuesta

15

Go go gadget bitmasks. Use una máscara de 4 bits para cada azulejo, indicando qué lado tiene una pared.

A B C D 

Bit A indica una pared en la parte superior, B el derecho, C la parte inferior, D la izquierda. Definir constantes para ayudarle a que sólo puede lógicamente se cruzan con la máscara, es decir

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

Para encontrar la imagen, esta máscara de 4 bits produce las 16 posibilidades. Úselo como un índice en una "matriz" de imágenes, para que pueda encontrar directamente la imagen correcta sin ningún esfuerzo.

+0

OMG! Sugiero encarecidamente que se usen métodos (o propiedades en C#), no pruebas manuales como "if (tile.Walls & (WALL_LEFT | WALL_RIGHT)). El método manual agrega detalles innecesarios a su código. Los detalles siempre se deben abstraer. Por supuesto, este comentario no va en contra del método de 4 bits. – jrharshath

+5

Las máscaras de bits son la solución incorrecta aquí (y en general un hack feo). El código del OP es puramente de procedimiento y pidió una solución de OO. –

+0

Las máscaras de bits son bastante encantador, utilícelos, pero escriba los predicados que desee como métodos estáticos (lo que JIT quiere, se alineará). – plinth

0

¿No puedes hacer algo con enumeraciones de banderas?

0

Debe colocar la configuración de muro en una sola variable y crear una asignación de esta variable a las imágenes de mosaico.

4

¿Los objetos de mosaico tienen alguna otra propiedad? Si no (o si puede factorizar los), podría convertir los objetos del mismo en una enumeración de 16 constantes con un método Tile.getImage() que devuelve una imagen fija pasada al constructor. Esto se conoce como la 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 
} 

En Java, incluso se podría aplicar esto como una enumeración "real".

Para un mapa que consta de mosaicos, puede tener una matriz bidimensional simple de referencias de teselas, o si necesita otros datos para teselas individuales, tener otra clase SpecificTile que contenga los "otros datos" y una referencia a uno de los objetos Tile arriba.

+0

Aún mejor después de la edición. +2 de mí si fuera posible :) – willcodejavaforfood

2

Sugiero crear un bit flag enum como el siguiente.

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

Luego puede usar un diccionario para asignar las ubicaciones de las paredes a las imágenes.

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); 
// .... 

Al menos en C# que también podría ampliar la definición de enumeración con los 16 casos.

[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 
} 
0

En lugar de hacer WALLS_ALL_AROUND una imagen, lo convierten en un objeto que incluye la imagen, así como cualquier otra lógica necesaria para hacer frente a los movimientos permitidos y otras cosas. En un objeto Location puede simplemente establecer la propiedad walls en ese WALLS_ALL_AROUND, que puede consultar para la imagen y tener que lidiar con su otra lógica relacionada con la pared.

Como solo necesita dieciséis instancias de estos objetos (inmutables) para cada conjunto de imágenes (cada una es probablemente una subcategoría singleton de Tile si solo tiene un conjunto de imágenes), también ahorra memoria.

0

Una solución de OO decente probablemente involucre el Strategy Pattern. Una posible implementación sería tener una clase WallConfiguration y un WallFactory para crearlas. A Tile contendría una WallConfiguration. Implementación (estilo C++) sería algo como esto:

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); 
    } 

Una de las interesantes ventajas de esto es que ahora, cuando se agrega la capacidad para hacer estallar las paredes (y vamos ... que sabes' Vamos a, 'porque a todos nos gusta explotar las cosas), puedes agregar esa responsabilidad a la clase WallConfiguration, que sabrá cómo obtener la instancia adecuada de sí mismo cuando rompas la pared izquierda, por ejemplo.

Cuestiones relacionadas