Boxhead 3D - Made in DirectX 11 Engine

Return

Project Description

Using a DirectX 11 component based engine I created Boxhead in 3D, an old Flash game I've played a lot when I was young. I received the barebone engine from school and expanded it myself with features like hardware skinning, static batching, shadow mapping, PhysX cloth, post processing shaders, HUD and raycasting.

Besides this I did some research in steering behaviors, A* pathfinding and behavior trees. First in Unity3D and then in C++.

Challenges

  • Static batching
  • Data driven design using json
  • Shadow mapping
  • Physx Cloth
  • Using winsock2 for online leaderboards
  • Flow field pathfinding

Technology Used

  • Visual Studio
  • Unity3D
  • Adobe Photoshop
  • Autodesk 3ds max

Language

  • C++
  • C#
  • HLSL
  • json
Source Build AI Research paper

Flow field pathfinding

Since Boxhead has enemies that have to find a way through the level, they needed some kind of way to calculate their paths. There are many kinds of pathfinding and I chose to try A* pathfinding and flow field pathfinding.

The game strongly relies on a grid system because of the object and structure placement so having a grid to work with was very beneficial.

I began with researching how flow fields work and how they were created. I started with making the heat map which indicates how far all the cells are from the target position. Every cell stores a number that holds that distance.

After doing this, I had the data I needed to create the actual flow field vectors for each cell. Calculating the vectors for each cell is actually quite easy, you simple subtract the left cell's distance from the right cell for the x value and the same for the y value but then with the lower and the upper cell respectively. Visualizing this resulted in a quite satisfying image. (see image)

Now I had the flow field, I could simply calculate the closest cell to the agent and set the velocity of that agent to the vector of that cell.

Flow field pathfinding and A* pathfinding

The main reason I chose to implement two different types of pathfinding is because I wanted to know how flow fields compete with A* pathfinding. I read almost everywhere that A* pathfinding is the standard and the "best" pathfinding solution. My goal was to both have them working in the game and eventually compare them both in different situations.

As expected, A* pathfinding performed better in general, with few agents. As Boxhead is a never-ending game, the amount of zombies keeps increasing meaning that the A* algorithm needs to calculate the path for every agent which had a great impact on the performance. Of course, there are a few simple improvements I wrote so that the paths are only recalculated when needed and that agents can acquire paths from other agents. But still, after a while, it hits the performance quite hard. That's where flow fields come in to play. The big advantage is that a flow field only has to be calculated once for all agents meaning that it is more efficient from a certain amount of agents because it takes longer to calculate a flow field than an agents path with A*.

To visualize this, I made a very simple graph.

Online highscores

I've always been interested in interaction with network but I had absolutely no experience with that. I wanted to make a highscore system so that players could see other players their scores. This required me to do some reading up on networking.

I found a great website called Dreamlo.com that hosts free scoreboards using a really simple system. To get all the highscores you make an http request and sends all the highscores. To upload a highscore, you just add the name of the player and his score to the URL. Nevertheless, making an http request didn't seem so trivial as I thought.

Since not every player would be able to connect to the internet when they were playing, I made a class that handles the online scores and a class that handles the offline scores that are saved on the client's computer. Both systems are quite alike only that the online system makes the http request.

The method that makes the request itself is made so that it can do both the uploading of scores and the receiving of scores.

On the right is a part of the OnlineHighscore class. For this, I also made a small exception handling class called "SocketError" to I could easily debug any event and log it to the console.

Click on an image to enlarge