UnityLearn – AI For Beginners – Crowd Simulations – Fleeing

May 22, 2020

AI For Beginners

Crowd Simulations

Part 2


Beginner Programming: Unity Game Dev Courses

Unity Learn Course – AI For Beginners

Intro

I was going to combine both of the end parts of the Crowd Simulation tutorial into one blog, but the Flocking tutorial was rather large and interesting so I decided to break it off into its own post. Because of that, this is a smaller one just focused on the basic fleeing crowd logic.

Fleeing

This is similar to the concept covered with single AI agents, it is just being applied to many agents here. An object is introduced to the environment and the fleeing agents determine the vector towards that object, and set a new course for the exact opposite of that vector.

Key Parameters covered for their flee inducing object:
Radius of Influence – how close agents must be to be affected by the object
Cooldown – how long an agent flees before returning to standard behavior

They decided to induce fleeing by adding a cylinder object to the Nav Mesh environment by clicking. This required adding a mouse button script along with adding a dynamic obstacle to the Nav Mesh again (similar to the FPS controller from the last tutorial).

This tutorial gets into several useful NavMesh methods that have not been used yet. These are helpful references to use when expanding and developing my own pathfinding methods, since they show some useful options to give developers when working with intelligent pathfinding.

There are NavMeshPath objects which hold information about a path for the agent to some given destination. You can set these path objects using the CalculatePath method, using a vector3 position (the destination) and the NavMeshPath object as parameters to set that path with that given destination. This alone does NOT set the agent along this path, it simply gets the information for that path (this is useful for the next step).

They perform a check on the path using fields within the NavMeshPath class and an enum named NavMeshPathStatus before actually setting the new destination of the agent. The check is as follows:

NavMeshPath path = new NavMeshPath();
agent.CalculatePath(newGoal, path);

if(path.status != NavMeshPathStatus.PathInvalid){… }

You are able to access the status of a NavMeshPath with a field within the class. They use this to check that the status of the newly created path is valid by checking it against the PathInvalid option within the NavMeshPathStatus enum. Only after passing this check do they set the newly determined path of the agent. Here, they also show that NavMeshPath has a vector3 array field named corners, which are effectively the waypoints of the path the agent uses for its pathfinding.

Summary

This fleeing logic was pretty basic, but it was helpful to learn a bit more about Nav Mesh in general for Unity. The extra information about NavMeshPath was good to learn about, as well as giving me more options on useful aspects to give my own pathfinding systems.

UnityLearn – AI For Beginners – Crowd Simulations – Flocking

May 22, 2020

AI For Beginners

Crowd Simulations

Part 3


Beginner Programming: Unity Game Dev Courses

Unity Learn Course – AI For Beginners

Intro

This was by far the most interesting crowd simulation tutorial covered in the basic AI tutorials. This one really got into an actual rule based logic system for pathing of agents within a large group to move them in an interesting way with emergent behavior that is still controlled and possible to direct.

Flocking

Part 1

Flocking: simple rules to generate movement for groups of individuals to move towards common goals (i.e. birds or fish)

They create a FlockManager because flock movement requires the individual agents to know about and understand they movement and positioning of all the other agents around them. This will be at a higher level providing data for an entire flock as a whole. This starts with logic to instantiate the flock by creating many fish prefabs in a randomized starting position bound around the FlockManager’s position. They also created a class named Flock to go directly on the the individual fish agents themselves.

    Flocking Rules:

  1. Move towards average position of the group
  2. Align with the average heading of the group
  3. Avoid crowding other group members

Flock Rule 1: Move Towards Average Position of Group

This is done by summing all the positions of the agents within the group and dividing by the number of group members, so it directly is the average position of the agents within the group. The agent’s can then find where they are in relation to this average position, and turn towards it.

Flock Rule 2: Align with the Average Heading of the Group

Similar to rule 1, this is also directly an average within the entire group, but this time it is done using the heading vectors of all the agents within the group. The heading vectors are summed and divided by the total number of agents within a group to determine the group’s overall average heading. The agents then attempt to align their heading with this average heading.

Flock Rule 3: Avoid Crowding Other Group Members

The agents must be aware of the positions of their nearest neighbors and turn away from them, as not to collide with them.

Finally, these three rules produce three vectors which are summed to generate the actual new heading of each individual agent.

new heading = group heading + avoid heading + group position

Back in the Flock class, they start applying some of these rules. Here is a list of some of the variables within their ApplyRules() method and what they represent:

Vector3 vcenter = Vector3.zero; // Average center position of a group
Vector3 vavoid = Vector3.zero; // Average avoidance vector (since avoiding all members in group)
float gSpeed = 0.01f; // Global speed of the entire group (Average speed of the group)
float nDistance; // Neighbor distance to check if other agents are close enough to be considered within the same group
int groupSize = 0; // Count how many agents are within a group (smaller part of the group an individual agent considers neighbors)

When setting up their Flock class and applying these rules, they decided to only apply these rules to neighbor agents. This means that the agents are not directly tied to the entire flock at all times, they simply check for agents within a certain distance around them and they only determine their behavior based on all the agents within that certain radius. I just wanted to clarify since it was unclear if some or all of the rules applied to neighbors or the entire flock (here they just apply all rules to only neighbors).

The summary of the Flock class ending here, specifically within the ApplyRules() method, is that each agent finds all the other agents within the given neighbor distance to determine which agents to momentarily flock with. It sums all the positions of these agents together to eventually get the average position. It then checks if these agents are extraordinarily close to determine if it should avoid them, and if so, calculates the avoidance vector (just the vector directly away from that agent) and sums that into a total avoidance vector (which is NOT averaged later on). It then sums all the speeds of the neighbors, again to average later on.

Finally, it checks if the agent is within a group (so is groupSize > 0), and performs the averaging mentioned earlier here. The new heading is calculated here by summing the average center position of a group with the avoidance vector (and subtracting the agent’s position itself to get a proper vector relative to its current position) and the agent performs a slerp to move towards this new heading.

This created a swirling ball of fish that did not particularly seem to deviate from this large mass with a large number of fish (50) and average values for all the sliders (speeds of 0.25 to 2.5; neighbor distance of ~5; rotation speed ~3.5). While moving, significantly reducing the neighbor distance ( < 1.0) did have them separate into smaller groups and swim off infinitely.

Part 2

Adding General Goal Position for Flock

To help provide the group of agents with a general direction, they added a general goal position to the FlockManager class. The Flock class then uses this position within its average center position calculation to help influence the direction of the agents towards this goal position. Initially they tied this to the position of the FlockManager object itself, and moving this around in the editor moves all the agents tied to it in the general direction towards this object (their goal position).

To automate this process a bit, they have the goal position move randomly every now and then within the given instantiation limits (these are the position ranges which the initial agents spawn in around the FlockManager object). This allows for the agents to move around with some more guidance on their own.

They then extend this random “every now and then” process to the Flock class as well. Here they apply it to randomize the agent’s speed and only run the ApplyRules() method occasionally, so they are not constantly following the flocking rules every single frame. This has the added benefit of reducing the processing intensity as well as the agents will not perform the entire logic of flocking every single frame now.

Returning Stray Agents Back to Flock

They finally add logic to deal with rogue agents that leave the flock and travel outward forever. They use the same bounds which determines the general area to spawn all the agents to determine the greater bounds to contain the agents. The Bounds class within Unity is used to check if the agent is contained within these bounds or not. If not, the agent changes its heading towards the FlockManager’s location instead, which remains intact until it encounters other agents to flock with.

Part 3

Obstacle Detection/Avoidance

The major addition in this final flocking tutorial is the addition of obstacle detection. To accomplish this, they have the individual agents cast a physics ray forward, along their direction of travel, and if it detects an obstacle, it will start to turn they away from it.

To have the agents turn away from an obstacle, they choose to use Unity’s reflect method. Using the hit information of the raycast and the normal information from the object hit, Unity can determiner the reflection vector based on the incoming ray. This produces a vector away from an object at the same angle relative to the normal of the surface as the incoming vector.

Video of the Flocking Result In Action

My Flocking Example

Summary

The implementation and fine tuning of Reynold’s Flocking Rules here was by far the most interesting part of the crowd simulation tutorials in this overall section. The idea of using a set of fairly simple rules on many, many agents in a large group to provide interesting yet realistic motion with controllable direction and emergent behaviors is exactly what I hoped for when looking into crowd behavior, and AI in general.

It was interesting to learn that Reynold’s rules are applied to motion by simply converting each of the three rules into their own vector, and then just summing those vectors for the most part. It is also very cool to see just how much you can change up the behavior and general motion of the agents by altering just a few values, like neighbor distance, speed, and rotation speed.

The additional features they covered after the bare minimum of flocking were also very helpful and practical. Showing ways to control stray agents and move them in a unified general direction towards a common goal are very good additional beahviors to add to flocking, and they were implemented in a very easy to understand way. Obstacle detection is also extremely nice, but its implementation was very straight forward and basic so it wasn’t quite as exciting (although the use of the Unity Reflection method is something I hadn’t used before, so that was helpful to learn).

UnityLearn – AI For Beginners – Crowd Simulations – Moving As One & Creating A City Crowd

May 20, 2020

AI For Beginners

Crowd Simulations

Part 1


Beginner Programming: Unity Game Dev Courses

Unity Learn Course – AI For Beginners

Intro

This is the first part of the Crowd Simulations section of the AI course that I covered. This was the first two major tutorials of four, Moving As One & Creating a City Crowd. These introduce the basic concepts of crowd simulations, and at least cover ways to start moving groups of agents with Nav Mesh Agents in Unity to help visualize these concepts (more so than particularly creating agent crowd AI behaviors yourself).

1: Moving As One

Crowd Behavior: agents move enmasse, as opposed to solely as individual units; their movements are usually also dependent on each other’s movements

Reynold’s Flocking Algorithm:

    Common flocking logic based on 3 simple rules:

  1. Turn towards average heading of group
  2. Turn towards average center of the group
  3. Avoid those around you

They start with a really basic Nav Mesh setup with a bunch of blue capsule agents on one side of a tight corridor, and a bunch of red capsule agents on the other side, and they each need to navigate to a goal on the opposite side, running through/past each group of capsules. The standard Nav Mesh Agent setups with colliders gives interesting group interactions by themselves already to start. This simulation was mostly to help visualize the idea of lines of flow in crowds, as well as instances of turbulence within crowd simulations.

2: Creating A City Crowd

Part 1

Starting setup is adding Street Crowd Simulation package to a Unity project. They included a starting scene of a street with several different characters with basic idle, walk, and run animations. This setup just helps visualize crowd behavior in a more interesting and realistic setting. Initially the agents select a random object from all the objects tagged “goal” as their destination and move there.

The additions done in the tutorial were having the agents continue finding new destinations after reaching the first one and adding more static meshes as obstacles for the agents to move around. The first goal used a distance check for once the agents were close enough to their destination, and then they would select another goal randomly from the initialized goal array. To accomplish the second part, they just added large cubes to simulate buildings to make a more realistic street walking setup with the characters.

Part 2

They added a bunch of buildings to the center of the street scene so agents would walk around the outter edge as normal street traffic.

Alternating Character Animations:

All the characters are using the same animations, so they look strange because they are all doing the exact same animations on the exact same time cycles. To rectify this, they looked into the “Cycle Offset” parameter within the standard walking animation for all the characters in the Animator.

They suggest setting this value with the SetFloat method within Unity’s Animator class. I tried doing this to set the value for the float parameter they added and tied to Cycle Offset, but it was not working for me. The string I entered matches the parameter name, and I connected the value to the parameter as they showed, but it was having no effect for me.

FIXED:

I was able to rectify this issue by explicitly stating within the Random.Range method setting the values to use floats for 0 and 1 (with 0.0f, and 1.0f). Without this explicit declaration, it must’ve been using ints and it was only setting everything to 0 every time (so initializing it as it was originally). Making them floats fixed the issue and they were being put on different cycles as expected.

They also set varied starting speeds for the agents. This included changing the speed of their animations along with their actual Nav Mesh Agent travel speed. To keep these working together well, they just randomly selected a float value and applied this same value to both of these parameters.

Dynamic Nav Mesh Obstacle (with First Person Controller):

They then move on to adding dynamic Nav Mesh obstacles by adding a First Person controller and making the player an obstacle on the Nav Mesh. This is done simply by adding a Nav Mesh Obstacle to the First Person controller. It creates a wireframe similar to a collider that can be shaped and controlled to control the area it removes from the Nav Mesh itself.

Summary

Overall the tutorials have been extremely basic so far and have not really delved into the actual AI behaviours of groups yet really. I am hoping they explore implementing Reynold’s Flocking theorem at some point so I can get some experience with that. If not I may take a detour into the world of “boids” to expose myself to more crowd behavior AIs.