# A* Pathfinding for 2D Grid-Based Platformers: Adding One-Way Platforms

In this short tutorial, we'll extend our platformer pathfinder so that it can deal with one-way platforms: blocks that the character can jump through and also step on. (Technically, these are two-way platforms, since you can jump through them from either direction, but let's not split hairs!)

## Demo

You can play the Unity demo, or the WebGL version (100MB+), to see the final result in action. Use **WASD** to move the character, **left-click** on a spot to find a path you can follow to get there, **right-click** a cell to toggle the ground at that point, and **middle-click** to place a one-way platform.

## Changing the Map to Accommodate One-Way Platforms

To handle the one-way platforms, we need to add a new tile type to the map:

public enum TileType { Empty, Block, OneWay }

One-way platforms have the same pathfinder weight as empty tiles—that is, `1`

. That's because the player can always go through them when jumping up; they only stop him when he's falling, and that in no way impairs the character's movement.

We also need a function that lets us know if the tile at a given position is specifically a one-way platform:

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

Finally, we need to change `Map.IsGround`

to return `true`

if a tile is either a solid block *or a one way platform*:

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

That's the map part of the code sorted; now we can work on the pathfinder itself.

## Adding New Node Filtering Conditions

We also need to add two new node filtering conditions to our list. Remember, our list currently looks like this:

- It is the start node.
- It is the end node.
- It is a jump node.
- It is a first in-air node in a side jump (a node with jump value equal to
`3`

). - It is the landing node (a node that had a non-zeo jump value becomes
`0`

). - It is the high point of the jump (the node between moving upwards and and falling downwards).
- It is a node that goes around an obstacle.

We want to add these two conditions:

- The node is on a one-way platform.
- The node is on the ground and the previous node was on a one-way platform (or vice-versa).

### Including Nodes That Are One-Way Platforms

The first point: we always want to include a node if it's on a one-way platform:

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

### Include Ground Nodes if Previous Node Was a One-Way Platform

The second point: we need to include a node if it is on the ground and the previous node is on a one-way platform:

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

### All Together, Then...

Here's a refreshed list of node filter conditions; the algorithm will let through any node that fulfils any of the following requirements:

- It is the start node.
- It is the end node.

- The node is on a one-way platform.

- The node is on the ground and the previous node was on a one-way platform (or vice-versa).

- It is a jump node.

- It is a first in-air node in a side jump (a node with jump value equal to
`3`

). - It is the landing node (a node that had a non-zero jump value becomes
`0`

). - It is the high point of the jump (the node between moving upwards and and falling downwards).
- It is a node that goes around an obstacle.

And here's the code checking all these conditions:

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 jumps starts || (fNodeTmp.JumpLength == 0 && fPrevNodeTmp.JumpLength != 0) //mark landings || (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);

## How Filtering Looks With One-Way Platforms

Finally, here's an example of filtering with one-way platforms.

## Conclusion

That's all there is to it! It's a simple addition, really. In the next tutorial in this series, we'll add a slightly more complicated (but still fairly straightforward) extension, allowing the pathfinding algorithm to deal with characters that are larger than 1x1 blocks.

Envato Tuts+ tutorials are translated into other languages by our community members—you can be involved too!

Translate this post