A university module required the creation of a game that looks at and implements an advanced physics topic, and an advanced AI topic. For the physics topic I looked at gravity such that an object being an attractee could be attracted to another object the attractor, allowing the attractees to be attracted to and move around an attractor. Then for the AI I wanted agents that could move around the surface of the attractor, this led me to discover flow field pathfinding. This led to the creation of a game where the player can move around small differently shaped planets shooting enemies that chase them, the game had an added element of uniqueness as players can shoot themselves when their bullets wrap back around the planet to hit them.

Physics: Gravity

The functionality is split out into two main parts, attractors and attractees. By doing so this allows control over which objects are attracted to the planets, and which objects serve as the planets. Attractees work using Unity’s rigidbody – however the rotation is frozen giving control of the rotation, and gravity disabled, allowing for a custom gravity implementation. The behaviour of an attractee is to find the attractors face that the attractee is nearest; this is done by ray casts. Once an attractor is found, use the surface normal from the ray cast to orient the object so that its up is in line with the surface normal. First a ray is cast downwards from the attractee, in most cases this will find the attractor, and for a spherical planet is the only method required. However, for cube shaped planets this alone will not work as walking off the edge of a body will not find the surface. In this scenario a cone of rays is cast below the player.

WalkDemo

Also implemented are projectiles that can be shot by the player. A projectile is an attractee, combining this with a constant forward force allows the projectile to move forwards. As it moves around a surface its forwards will change allowing it to wrap around a sphere. Most basic unity meshes have been tested that would make sense as a play space, such as sphere, cube, capsule, and cylinder. All allow the projectiles to move around them in a believable way.

Selfshoot

For this, assumptions are made that there is no air resistance, or changes in air pressure. The level of gravity also remains the same regardless of the distance from the surface, or centre of mass for the attractor. Additionally, all objects are assumed to be rigid. These assumptions are made, as including them would add extra complexity which is unnecessary for the game feel. As the attractor to use is always decided by looking below the attractee then we cannot transition from the sphere to the cube. The angle is too large between the two to be recognised. Another limitation is that models used as attractors must be fairly high poly for attractees to smoothly follow the shape of the object. Otherwise a low poly sphere for example may not feel very sphere like to move around.

AI: Flow field pathfinding

Flow-field pathfinding is used to allow pathfinding on the exterior of 3d objects. One of the main difficulties to implementing this is generating the nodes and connections to apply the pathfinding to. To generate the nodes the mesh data of the object is used. Foreach triangle in the mesh a node is created which is connected to the other nodes in the triangle. Only the shortest of the two connections are connected to avoid diagonal connections, diagonals can cause issues when obstacles are present. Once converted there will be multiple nodes with the same position where the triangles meet. So, merge nodes with the same position into one node containing all connections of the nodes in the same position. This can generate a grid to find a path on.

SphereGrid

As mesh data is used, this can present issues with there being too few nodes. To counter this the mesh may be subdivided multiple times first, decreasing the size of the mesh triangles but increasing the number of nodes in the grid making it more accurate. A comparison of a cube subdivided 0 times against 3 times can be seen below. To subdivide the mesh an external source has been used. Subdiv

With the grid generated the flow-field technique can be applied. The main code that does this can be seen below. Within to represent a collision a nodes cost is set to 255, so to generate we skip evaluating the connection if the connected has a cost of 255. Additionally, the target nodes direction is set to point directly to the target position given. This allows agents to get to the target position not just the target node.

// Code that generates the flow field
SetAllUnreachable();
targetNode.SetValue(0);
targetNode.SetDirection(targetPosition - targetNode.Position());

Node currentNode = targetNode;
List<Node> open = new List<Node> {currentNode};
while (open.Count > 0) {
    currentNode = open[0];
    open.Remove(currentNode);
    foreach (int connectedNodeID in currentNode.connectedNodes) {
        Node connectedNode = _nodes.Find(node => node.id == connectedNodeID);
        if (connectedNode.Active()) {
            int pathLength = currentNode.Value + connectedNode.Cost;
            if (pathLength < connectedNode.Value) {
                if (!open.Contains(connectedNode)) {
                    open.Add(connectedNode);
                }

                connectedNode.SetValue(pathLength, currentNode);
            }
        }
    }
}

To make an agent that follows the field, a forward force is given, then when moving update the rotation to look in the direction of the flow-field. The agent uses this rotation to slowly rotate towards, causing it to follow the field smoothly without instantly snapping to the new direction. To resolve issues on the very edge of the cube the agent will ignore the flow-fields direction if it will cause the agent to look at the walkable surface. Only after it gets over the edge will it then use its direction. An example flow-field with a player as the target point and an agent trying to get to the player with a collision can be seen below. The Lines between the nodes show the nodes direction vector, a greener line also helps visualise its closeness to the target.

FlowField

Thanks for reading

Download game here

Source code here

Updated: