A * Pathfinding voor 2D op grid gebaseerde platformers unidirectionele platforms toevoegen

In deze korte tutorial zullen we onze platformer-pathfinder uitbreiden zodat hij kan omgaan met eenrichtingsplatforms: blokken waar het personage doorheen kan springen en ook op kan stappen. (Technisch gezien zijn dit tweerichtingsplatforms, omdat je er vanuit beide richtingen doorheen kunt springen, maar laten we de haren niet splitsen!)

demonstratie

U kunt de Unity-demo of de WebGL-versie (100 MB +) spelen om het uiteindelijke resultaat in actie te zien. Gebruik WASD om het personage te verplaatsen, links klikken op een plek om een ​​pad te vinden dat je kunt volgen om er te komen, klik met de rechtermuisknop een cel om de grond op dat punt te wisselen, en middelste muisknop om een ​​eenrichtingsplatform te plaatsen.

De kaart wijzigen in One-Way-platforms

Om de eenrichtingsplatforms te verwerken, moeten we een nieuw tegeltype toevoegen aan de kaart:

public enum TileType Empty, Block, OneWay

Eenrichtingsplatforms hebben hetzelfde padgewicht als lege tegels, dat wil zeggen, 1. Dat komt omdat de speler ze altijd kan passeren bij het springen; ze stoppen hem alleen als hij valt, en dat beïnvloedt op geen enkele manier de beweging van het personage.

We hebben ook een functie nodig die ons laat weten of de tegel op een bepaalde positie specifiek een eenrichtingsplatform is:

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

Eindelijk moeten we veranderen Map.IsGround terugbrengen waar als een tegel een massief blok is of een eenrichtingsplatform:

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

Dat is het kaartgedeelte van de code gesorteerd; nu kunnen we aan de pathfinder zelf werken.

Filtervoorwaarden voor nieuwe knooppunten toevoegen

We moeten ook twee nieuwe voorwaarden voor het filteren van knooppunten aan onze lijst toevoegen. Vergeet niet dat onze lijst er momenteel zo uitziet:

  1. Het is het startknooppunt.
  2. Het is het eindknooppunt.
  3. Het is een springknoop.
  4. Het is een eerste in-luchtknooppunt in een side jump (een knooppunt met sprongwaarde gelijk aan 3).
  5. Het is het landingsknooppunt (een knooppunt met een niet-zeo-sprongwaarde wordt dat 0).
  6. Het is het hoogtepunt van de sprong (het knooppunt tussen omhoog bewegen en naar beneden vallen).
  7. Het is een knoop die rond een obstakel gaat.

We willen deze twee voorwaarden toevoegen:

  • Het knooppunt bevindt zich op een eenrichtingsplatform.
  • Het knooppunt bevindt zich op de grond en het vorige knooppunt bevond zich op een eenrichtingsplatform (of vice versa).

Inclusief knooppunten die eenrichtingsplatforms zijn

Het eerste punt: we willen altijd een knooppunt opnemen als het op een eenrichtingsplatform is:

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

Inclusief grondknooppunten als eerder knooppunt een eenrichtingsplatform was

Het tweede punt: we moeten een knooppunt opnemen als het zich op de grond bevindt en het vorige knooppunt zich op een eenrichtingsplatform bevindt:

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

Alles samen, dan ...

Hier is een vernieuwde lijst met knooppuntfiltercondities; het algoritme zal elk knooppunt doorlaten dat aan een van de volgende vereisten voldoet:

  1. Het is het startknooppunt.
  2. Het is het eindknooppunt.
  3. Het knooppunt bevindt zich op een eenrichtingsplatform.
  4. Het knooppunt bevindt zich op de grond en het vorige knooppunt bevond zich op een eenrichtingsplatform (of vice versa).
  5. Het is een springknoop.
  6. Het is een eerste in-luchtknooppunt in een side jump (een knooppunt met sprongwaarde gelijk aan 3).
  7. Het is het landingsknooppunt (een knooppunt met een sprongwaarde die niet gelijk is aan nul) 0).
  8. Het is het hoogtepunt van de sprong (het knooppunt tussen omhoog bewegen en naar beneden vallen).
  9. Het is een knoop die rond een obstakel gaat.

En hier is de code die al deze voorwaarden controleert:

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) // mark sprongen start || (fNodeTmp.JumpLength == 0 && fPrevNodeTmp.JumpLength! = 0) // markeer landingen || (fNode.y> mSluit [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);

Hoe filteren eruit ziet met One-Way Platforms

Ten slotte is hier een voorbeeld van filteren met eenrichtingsplatforms.

Conclusie

Dat is alles wat er is! Het is echt een simpele toevoeging. In de volgende zelfstudie in deze serie voegen we een iets ingewikkelder (maar nog steeds redelijk eenvoudige) uitbreiding toe, waardoor het padvervalsalgoritme omgaat met tekens die groter zijn dan 1x1 blokken.