Conservare i muri tra le piastrelle


8

Sto scrivendo il motore isometrico in c ++. Ho deciso di adottare un approccio più realistico e fare in modo che i muri occupino spazio tra due tessere, non una singola tessera intera, come mostrato nella figura sotto (proprio come in The Sims).

grafica concettuale di ciò che voglio ottenere

Il mio problema è che non ho idea di come archiviare i dati relativi alla mappa delle tessere in qualcosa che non è griglia. In questa situazione, credo che dovrò renderlo A * amichevole, quindi ci saranno nodi e bordi tra le piastrelle non divise da muri. Ecco un'altra immagine che mostra ciò che voglio ottenere:

Quindi, ecco le domande:

Come dovrei:

  • memorizzare l'intera mappa, sia piastrelle che pareti
  • ottimizzalo per il rendering
  • usarlo per A * e altri algoritmi piuttosto semplici da implementare su una griglia semplice ma ora usando pareti (bordi) per determinare visibilità, collisione ecc.?

Devi essere in grado di vederlo da diverse angolazioni? In tal caso, vuoi applicare trame diverse ai lati opposti della stessa parete? Ad esempio carta da parati rosa da un lato, blu dall'altro?
jzx,

Avrò bisogno della capacità di ruotare la mappa e di usare diversi tipi di vernici e materiali su entrambi i lati delle pareti. Ora penso che la parte superiore del muro dovrebbe mostrare anche materiale all'interno del muro (ad esempio, cemento, mattoni, legno)
Tchayen,

Risposte:


7

Comincio con i sistemi di coordinate: le coordinate per le posizioni della griglia sono (x, y) ma, come indicato da Krom in una risposta diversa, per i muri possono esserci fino a due muri per ogni posizione della griglia. Ciò porta a un secondo sistema di coordinate, per i bordi tra le piastrelle . In questo articolo ho usato Ovest e Sud, quindi i bordi possono essere (x, y, Ovest) o (x, y, Sud), ma puoi sceglierne due purché siano coerenti.

Coordinate del bordo per una griglia quadrata

Questi due sistemi di coordinate (riquadri e bordi della griglia) sono correlati. Ti consigliamo di chiedere: quali quattro bordi circondano una piastrella?

Bordi che circondano una piastrella

Per l'individuazione del percorso, A * vuole sapere quali tessere sono vicine (B) della tessera corrente (A). Invece di restituire tutte e quattro le tessere adiacenti, puoi controllare i quattro bordi. Includi la tessera B come vicino solo se non ci sono muri tra A e B.

Invece di memorizzare due muri per ogni piastrella, come suggerisce Krom, di solito mantengo i muri in una struttura dati separata: un insieme di coordinate del bordo. Quando A * vuole sapere se B è un vicino di A, controllerò se quel bordo è nell'insieme. Se lo è, non restituisco B.

Probabilmente non hai bisogno di questo per A *, ma per altre cose probabilmente vorrai sapere per qualsiasi bordo, a cui sono collegate due tessere:

Piastrelle che circondano un bordo

Vedere la sezione "Algoritmi" della pagina per i calcoli per queste due operazioni.

Nota anche: per alcuni tipi di mappe, in realtà vorrai memorizzare quattro bordi per riquadro della griglia, in modo da poter supportare le mosse a senso unico.


4

In ogni tessera puoi conservare le pareti che ha a nord e ad est. In questo modo ogni tessera deve memorizzare solo altri 2 booleani (o ints, se si desidera memorizzare il tipo di muro). Il rovescio della medaglia è che le tessere lungo i bordi sud e ovest non possono avere muri su sud e ovest a meno che non si aggiunga un'altra fila di tessere nascoste che le avranno.


2

In ogni riquadro, potrebbe archiviare i vicini (o la connettività) a cui ha accesso. Forse come bitmap. Le pareti sono dove le due piastrelle adiacenti non sono collegate. Questo è molto amichevole con A *.

Il secondo approccio consiste nell'archiviare la connettività del riquadro come enumerazione. Ad esempio, una tessera completamente aperta è 0, una tessera con muro a nord e resto aperto è 1, una tessera con muro a sud e resto aperto è 2, e così via fino a coprire tutte le possibili combinazioni.


Non credo che il tuo commento "friendly with A *" sia davvero valido, dato che presuppone che l'interfaccia ("quali tessere sono adiacenti?") Deve corrispondere all'implementazione ("riquadri vicini di negozio"). I due potrebbero essere diversi, ad esempio se si utilizza una struttura dati separata per i muri come suggerisce Amitp.
congusbongus,

1

Spero che questo C # vada bene per te - il mio c ++ è molto arrugginito:

abstract class MapFeature
{
    public void Draw();
    public bool IsWall();
}
enum Direction
{
    North, South, East, West
}
class Wall : MapFeature
{
    public bool IsWall() { return true; }
    public Tile Front, Back; // Tiles on either side of the wall, otherwise null.

    #region Implementation of MapFeature

    public void Draw()
    {
        // Wall specific drawing code...
    }

    #endregion
}
class Tile : MapFeature
{
    public bool IsWall() { return false; }

    public MapFeature North, South, East, West; // Tiles/Walls on each side, otherwise null

    public bool CanGo(Direction direction)
    {
        switch (direction)
        {
            case Direction.North:
                return !North.IsWall();
            case Direction.South:
                return !South.IsWall();
            case Direction.East:
                return !East.IsWall();
            case Direction.West:
                return !West.IsWall();
            default:
                throw new ArgumentOutOfRangeException("direction");
        }
    }

    #region Implementation of MapFeature

    public void Draw()
    {
        // Tile specific drawing code...
    }

    #endregion
}

È possibile aggiungere informazioni specifiche del muro alla classe Muro, informazioni specifiche sul riquadro alla classe Tile e perfezionare ulteriormente le condizioni nel metodo "CanGo". Ad esempio, quando un muro è in realtà una porta chiusa, ad esempio una classe Porta.

Per disegnare questo, inizieresti con una tessera arbitraria, ad esempio la tessera nel mezzo della posizione corrente della telecamera. Quindi spostati verso e a sinistra della videocamera in base alle dimensioni delle piastrelle. Quindi esegui una prima traversata dei nodi IMapFeature, disegnando ogni parete / piastrella nell'ordine riscontrato.

A * funzionerà su questa struttura, anche se ovviamente avrai bisogno di alcune modifiche per gestire qualcosa come porte chiuse.

Se lo desideri, puoi anche mantenere un indice spaziale delle tessere, che includerebbe implicitamente le pareti, al fine di scoprire quali tessere erano all'interno dei limiti della telecamera.

Dovresti comunque scegliere solo una tessera iniziale e una distanza da percorrere in base alla dimensione della tessera.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.