It’s Halloween, nobody came this year to get chocolate, and so while I was eating all of it I finished another nice world building feature. I already showed how easy it is now to include mazes. A similar concept but with a totally different feeling in VR is walking on a narrow path up high. So here we go: random paths.
While walking in a maze is great, it can become dull if it’s the only element. I wanted to have something where the exit can already be seen but getting there would be the challenge. I see two variations so far:
- Walk across a narrow path without falling down
- Have a solid ground in front of you but you have to find out onto which tiles you can actually step, the others are traps
The first one is more a balancing sensation. The second one goes right into Indiana Jones and Tomb Raider. This will be awesome!
Path Generation
While I initially thought I’d create a super clever algorithm I quickly abandoned this thought. While interesting, it was solved countless times before and it turned out I can simply buy it for 5 Euros. The keyword is: A*.
It’s a great algorithm, can handle obstacles of all sorts and is fast. I scanned the Unity Asset Store for candidates and ended up with two:
I owned the first one so that was the natural candidate. It turns out, it is somehow a bit complicated to use for the uninitiated. The second one caught my attention as it had the grid based path finding as its main example which was exactly my use-case. I tried it next and have to say: wow. This is a great asset. Well thought through and easily useable at run-time.
It accepts a starting and an end point and will spit out a series of steps that form a path. All one has to do is implement a function which returns all possible neighbor cells. A second function can be implemented to return the cost for each direction. Why is that useful? Path finding will typically spit out the best path. For a random path connecting two points, I don’t care about best. Simply returning random values for the costs solves this and the paths will always be valid, but different.
protected override float GetDistance(BasicEntity from, BasicEntity to, List<BasicEntity> path)
{
if (useRandomWeights)
{
return UnityEngine.Random.Range(weights.x, weights.y);
}
else
{
return base.GetDistance(from, to, path);
}
}
One hint to others using it since I struggled with that for a while: you need to ensure your path segments implement hashcode() and equals() as they will be indices of a map in the asset. And equals() must return true for segments at the final position when compared to the specified end segment. I had to strip down my entities before sending them to the path calculation so that only position was the differentiating one in the end.
World Building
So the Tiled importer needed to learn some new properties. It turned out I could reuse big parts of the maze generation logic and therefore introduced a MazeType property which can for now be MAZE or PATH. It’s also important to specify which object should be instantiated along the path (ObjectType) and that’s already it.
Incidentally the random path fits nicely to another feature I did some days ago: underground floors. So far all floors were above ground. Initially I thought this will be enough as I can always position the player intelligently but there were more and more scenarios (think looking out of the window) where a real underground would be much easier. So floors can now be flagged as underground and will stack as well, just as above ground.
This means we now have a random path and if the player looks down he will see the underground floor and if he falls down he will… erm.. nothing yet or rather, simply stand there. The concept of death and level reset is something on my ToDo list.
Putting that all together, including the ability to scale rooms (to 4 by 4 in this case), the above Tilemap will result in this nice path being generated from the top right to the lower left.