A * Pathfinding per platformer 2D basati su griglia aggiunta di piattaforme a una via

In questo breve tutorial, estenderemo il nostro pathfinder platform in modo che possa gestire piattaforme a senso unico: blocchi che il personaggio può attraversare e anche avanzare. (Tecnicamente, queste sono piattaforme a due vie, dato che puoi saltarle da entrambe le direzioni, ma non dividiamo i capelli!)

dimostrazione

Puoi giocare alla demo di Unity o alla versione WebGL (100 MB +), per vedere il risultato finale in azione. Uso WASD spostare il personaggio, sinistro del mouse su un punto per trovare un percorso che puoi seguire per arrivarci, tasto destro del mouse una cella per alternare il terreno in quel punto, e middle-click posizionare una piattaforma a senso unico.

Modifica della mappa per adattarsi alle piattaforme a una via

Per gestire le piattaforme a senso unico, è necessario aggiungere un nuovo tipo di tessera alla mappa:

public enum TileType Empty, Block, OneWay

Le piattaforme a senso unico hanno lo stesso peso del pathfinder delle tessere vuote, ovvero, 1. Questo perché il giocatore può sempre passare attraverso di loro quando salta in su; lo fermano solo quando cade, e ciò non sminuisce in alcun modo il movimento del personaggio.

Abbiamo anche bisogno di una funzione che ci faccia sapere se il riquadro in una data posizione è specificamente una piattaforma a senso unico:

public bool IsOneWayPlatform (int x, int y) if (x < 0 || x >= mWidth || y < 0 || y >= mHeight) return false; return (tiles [x, y] == TileType.OneWay); 

Infine, dobbiamo cambiare Map.IsGround ritornare vero se una tessera è un blocco solido o una piattaforma a senso unico:

public bool IsGround (int x, int y) if (x < 0 || x >= mWidth || y < 0 || y >= mHeight) return false; return (tiles [x, y] == TileType.OneWay || tiles [x, y] == TileType.Block); 

Questa è la parte della mappa del codice ordinata; ora possiamo lavorare sul pathfinder stesso.

Aggiunta di nuove condizioni di filtro dei nodi

Abbiamo anche bisogno di aggiungere due nuove condizioni di filtraggio dei nodi alla nostra lista. Ricorda, il nostro elenco al momento è simile a questo:

  1. È il nodo di partenza.
  2. È il nodo finale.
  3. È un nodo di salto.
  4. È un primo nodo in aria in un salto laterale (un nodo con valore di salto uguale a 3).
  5. È il nodo di atterraggio (un nodo con un valore di salto non-zeo diventa) 0).
  6. È il punto più alto del salto (il nodo tra muoversi verso l'alto e cadere verso il basso).
  7. È un nodo che aggira un ostacolo.

Vogliamo aggiungere queste due condizioni:

  • Il nodo si trova su una piattaforma unidirezionale.
  • Il nodo è a terra e il nodo precedente era su una piattaforma a senso unico (o viceversa).

Compresi i nodi che sono piattaforme a una via

Il primo punto: vogliamo sempre includere un nodo se si trova su una piattaforma a senso unico:

if ((mClose.Count == 0) || (mMap.IsOneWayPlatform (fNode.x, fNode.y - 1)) ... mClose.Add (fNode);

Includere i nodi di massa se il nodo precedente era una piattaforma a una via

Il secondo punto: dobbiamo includere un nodo se è a terra e il nodo precedente è su una piattaforma a una via:

if ((mClose.Count == 0) || (mMap.IsOneWayPlatform (fNode.x, fNode.y - 1)) || (mGrid [fNode.x, fNode.y - 1] == 0 && mMap.IsOneWayPlatform (fPrevNode.x, fPrevNode.y - 1)) ... mClose.Add (fNode);

Tutti insieme, quindi ...

Ecco un elenco aggiornato delle condizioni del filtro del nodo; l'algoritmo consentirà di passare attraverso qualsiasi nodo che soddisfi uno dei seguenti requisiti:

  1. È il nodo di partenza.
  2. È il nodo finale.
  3. Il nodo si trova su una piattaforma unidirezionale.
  4. Il nodo è a terra e il nodo precedente era su una piattaforma a senso unico (o viceversa).
  5. È un nodo di salto.
  6. È un primo nodo in aria in un salto laterale (un nodo con valore di salto uguale a 3).
  7. È il nodo di atterraggio (diventa un nodo con un valore di salto diverso da zero) 0).
  8. È il punto più alto del salto (il nodo tra muoversi verso l'alto e cadere verso il basso).
  9. È un nodo che aggira un ostacolo.

Ed ecco il codice che controlla tutte queste condizioni:

if ((mClose.Count == 0) || (mMap.IsOneWayPlatform (fNode.x, fNode.y - 1)) || (mGrid [fNode.x, fNode.y - 1] == 0 && mMap.IsOneWayPlatform (fPrevNode.x, fPrevNode.y - 1)) || (fNodeTmp.JumpLength == 3) || (fNextNodeTmp.JumpLength! = 0 && fNodeTmp.JumpLength == 0) // contrassegna salti inizia || (fNodeTmp.JumpLength == 0 && fPrevNodeTmp.JumpLength! = 0) // contrassegna atterraggi || (fNode.y> mChiudi [mClose.Count - 1] .y && fNode.y> fNodeTmp.PY) || (fNode.y < mClose[mClose.Count - 1].y && fNode.y < fNodeTmp.PY) || ((mMap.IsGround(fNode.x - 1, fNode.y) || mMap.IsGround(fNode.x + 1, fNode.y)) && fNode.y != mClose[mClose.Count - 1].y && fNode.x != mClose[mClose.Count - 1].x)) mClose.Add(fNode);

Come si presenta il filtraggio con le piattaforme a una via

Infine, ecco un esempio di filtraggio con piattaforme a una via.

Conclusione

Questo è tutto ciò che c'è da fare! È un'aggiunta semplice, davvero. Nel prossimo tutorial di questa serie, aggiungeremo un'estensione leggermente più complicata (ma ancora abbastanza semplice), che consente all'algoritmo del pathfinder di trattare i caratteri che sono più grandi dei blocchi 1x1.