2009-05-26 15 views
5

Ho Tile s che rappresentano le tessere nel mondo bidimensionale di un gioco. Le tessere possono avere muri su qualsiasi numero dei loro 4 lati. Ho qualcosa di simile al momento:Bel modo di farlo nel moderno linguaggio OO C-like?

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

Da qualche altra parte ho anche 16 immagini, una per ogni configurazione rivestimento parete possibile. Qualcosa di simile a questo:

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

Voglio scrivere un

static Image getWallImage(Tile tile) 

Quello che mi piacerebbe evitare di è il supplizio di passare attraverso le possibilità come

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

Qualcuno conosci un modo carino per fare questo?

risposta

15

Go go gadget maschere di bit. Usa una maschera a 4 bit per ogni piastrella, indicando quale lato ha un muro.

A B C D 

Bit A indica un muro in alto, B a destra, C in basso, D a sinistra. Definire le costanti per aiutarti a che si può solo logicamente si intersecano con la maschera, vale a dire

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

Per trovare l'immagine, questa maschera 4 bit produce le 16 possibilità. Usalo come un indice in un "array" di immagini, in modo da poter trovare direttamente l'immagine corretta senza alcuno sforzo.

+0

OMG! Suggerisco vivamente di utilizzare i metodi (o le proprietà in C#), non i test manuali come "if (tile.Walls e (WALL_LEFT | WALL_RIGHT).) Il metodo manuale aggiunge dettagli non necessari al codice. I dettagli devono essere sempre estratti. Naturalmente questo commento non è contro il metodo a 4 bit. – jrharshath

+5

Le maschere di bit sono IMO la soluzione sbagliata qui (e in genere un brutto attacco) .Il codice dell'OP è puramente procedurale e ha chiesto una soluzione OO –

+0

bel trucco: usali, ma scrivi i predicati che vuoi come metodi statici (che JIT vuole, saranno in linea) – plinth

0

Non puoi fare qualcosa con enumerazione di bandiera?

0

La configurazione del muro deve essere inserita in una singola variabile e creare una mappatura di questa variabile nelle immagini del riquadro.

4

Gli oggetti piastrella hanno altre proprietà? In caso contrario (o se è possibile escluderne uno), è possibile trasformare gli oggetti piastrella in un'enumerazione di 16 costanti con un metodo Tile.getImage() che restituisce un'immagine fissa inviata al costruttore. Questo è noto come il 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 
} 

In Java, si potrebbe anche implementare questo come un enum "reale".

Per una mappa che si compone di piastrelle, si potrebbe o avere un semplice array a 2 dimensioni di riferimenti piastrelle, o se avete bisogno di altri dati per singole tessere, avere un altro SpecificTile classe che contiene la "altri dati" e un riferimento a uno degli oggetti Tile sopra.

+0

Ancora meglio dopo la modifica. +2 da me se fosse possibile :) – willcodejavaforfood

2

Suggerisco di creare un enumerazione di bit come il seguente.

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

Quindi è possibile utilizzare un dizionario per mappare dalle posizioni del muro alle immagini.

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

Almeno in C# si potrebbe anche estendere la definizione enum con tutti i 16 casi.

[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

Invece di fare WALLS_ALL_AROUND un'immagine, ne fanno un oggetto che comprende l'immagine, nonché qualsiasi altra logica necessaria per gestire movimenti permessi e quant'altro. In un oggetto Location è sufficiente impostare la proprietà walls su quello WALLS_ALL_AROUND, che è possibile richiedere per l'immagine e gestire l'altra logica relativa al muro.

Poiché sono necessarie solo sedici istanze di questi oggetti (immutabili) per ogni set di immagini (ognuna è probabilmente un sottolinguaggio Singleton di Tile se si dispone di un solo set di immagini), si salva anche la memoria.

0

Una soluzione OO decente probabilmente coinvolgerebbe lo Strategy Pattern. Una possibile implementazione sarebbe avere una classe WallConfiguration e una WallFactory per crearli. Una tessera quindi conterrà una configurazione del muro. Attuazione (stile C++) sarebbe simile a questa:

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

Uno dei vantaggi interessanti di questo è che ora, quando si aggiunge la possibilità di far saltare in aria le pareti (e c'mon ... tu lo sai' Però, perché tutti amiamo far esplodere le cose), puoi aggiungere questa responsabilità alla classe WallConfiguration, che saprà come ottenere l'istanza corretta di se stessa quando esploderai la parete sinistra, per esempio.

Problemi correlati