A * Pathfinding pentru Platforme 2D Grid-Based Adăugarea Platformelor One-Way

În acest tutorial scurt, vom extinde platformerul platformerului nostru, astfel încât să se poată ocupa de platforme unidirecționale: blocuri pe care personajul să le poată trece și, de asemenea, să facă pasul. (Din punct de vedere tehnic, acestea sunt platforme bidirecționale, deoarece puteți sări prin ele din ambele direcții, dar să nu împărțim firele de păr!)

Demo

Puteți reda demonstrația Unity sau versiunea WebGL (100MB +), pentru a vedea rezultatul final în acțiune. Utilizare WASD pentru a muta caracterul, stânga-clic pe un loc pentru a găsi o cale pe care să o poți urma pentru a ajunge acolo, Click dreapta o celulă pentru a comuta la sol în acel moment și -Clic mijloc pentru a plasa o platformă unidirecțională.

Schimbarea hărții pentru a găzdui platforme unice

Pentru a trata platformele cu sens unic, trebuie să adăugăm pe hartă un nou tip de plăci:

public enum TileType Gol, Blocare, OneWay

Căile de acces pe o singură cale au aceeași greutate pentru traseu ca și plăcile goale - adică, 1. Acest lucru se datorează faptului că jucătorul poate trece mereu prin ele când sare în sus; îl opresc doar când cade, și asta nu afectează în nici un fel mișcarea personajului.

Avem, de asemenea, nevoie de o funcție care să ne permită să aflăm dacă placa dintr-o anumită poziție este în mod specific o platformă unidirecțională:

boolul public IsOneWayPlatform (int x, int y) if (x < 0 || x >= mWidth || y < 0 || y >= mHeight) return false; retur (plăci [x, y] == TileType.OneWay); 

În cele din urmă, trebuie să ne schimbăm Map.IsGround a se intoarce Adevărat dacă o piesă este fie un bloc solid sau o platformă unică:

boolul public IsGround (int x, int y) if (x < 0 || x >= mWidth || y < 0 || y >= mHeight) return false; retur (plăci [x, y] == TileType.OneWay || dale [x, y] == TileType.Block); 

Aceasta este partea de hartă a codului sortată; acum putem lucra la Pathfinderul însuși.

Adăugarea condițiilor de filtrare a nodurilor noi

De asemenea, trebuie să adăugăm două noi condiții de filtrare a nodurilor pe lista noastră. Rețineți că, în prezent, lista noastră arată astfel:

  1. Acesta este nodul de start.
  2. Acesta este nodul final.
  3. Este un nod de salt.
  4. Acesta este un prim nod în aer într-un salt lateral (un nod cu o valoare de salt egală cu 3).
  5. Acesta este nodul de aterizare (un nod care a avut o valoare non-zeo salt devine 0).
  6. Este punctul cel mai înalt al săritului (nodul între deplasarea în sus și în jos).
  7. Este un nod care se învârte în jurul unui obstacol.

Vrem să adăugăm aceste două condiții:

  • Nodul se află pe o platformă cu sens unic.
  • Nodul este la sol și nodul anterior era pe o platformă cu sens unic (sau invers).

Inclusiv noduri care sunt platforme One-Way

Primul punct: intotdeauna dorim sa includem un nod daca este pe o platforma cu sens unic:

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

Includeți nodurile de bază dacă nodul anterior a fost o platformă unică

Al doilea punct: trebuie să includem un nod dacă acesta este la sol și nodul anterior este pe o platformă cu sens unic:

dacă (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);

Toți împreună, atunci ...

Iată o listă actualizată a condițiilor de filtrare a nodurilor; algoritmul va permite prin orice nod care îndeplinește oricare dintre următoarele cerințe:

  1. Acesta este nodul de start.
  2. Acesta este nodul final.
  3. Nodul se află pe o platformă cu sens unic.
  4. Nodul este la sol și nodul anterior era pe o platformă cu sens unic (sau invers).
  5. Este un nod de salt.
  6. Acesta este un prim nod în aer într-un salt lateral (un nod cu o valoare de salt egală cu 3).
  7. Acesta este nodul de aterizare (un nod care a avut o valoare non-zero salt devine 0).
  8. Este punctul cel mai înalt al săritului (nodul între deplasarea în sus și în jos).
  9. Este un nod care se învârte în jurul unui obstacol.

Iată codul care verifică toate aceste condiții:

dacă (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) // marchează săriturile începe || (fNodeTmp.JumpLength == 0 && fPrevNodeTmp.JumpLength! = 0) // marchează debarcările || (fNode.y> mClose [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);

Cum arată filtrarea cu platforme cu sens unic

În sfârșit, iată un exemplu de filtrare cu platforme unidirecționale.

Concluzie

Cam despre asta e! Este un simplu plus, într-adevăr. În următorul tutorial din această serie, vom adăuga o extensie puțin mai complicată (dar totuși destul de simplă), permițând algoritmului de trasare a traseului să se ocupe de caracterele care sunt mai mari decât blocurile 1x1.