Drawing Board: Idea #1 - Skewed Randoms
Originally I had thought of using skewed random chance to determine if a unit was aggressive enough to attack--meaning that when an enemy entered a unit's sight, a number between 1 and 100 would be randomly generated and then be compared to the unit's aggressiveness trait (also a number between 1 and 100). If the number was less than the unit's aggressiveness trait, then the unit would be aggressive enough to attack the enemy.
The problem with this method is that the AI behavior is a little too random--too inconsistent. The player would have trouble figuring out how exactly the aggressiveness trait affected a unit's behavior. So I decided to do some research.
Drawing Board: Idea #2 - Interpersonal Space Multiplier
The most applicable (and interesting) thing that I found while researching was the concept of Proxemics, pioneered by Edward T. Hall.
Take a look at the following diagram regarding interpersonal space:
Edward T. Hall's personal reaction bubbles, showing radius in feet and meters.
This is what Wikipedia has to say about interpersonal space:
Interpersonal space is the psychological "bubble" that exists when one person stands too close to another. Research has revealed that there are four different zones of interpersonal space:
How is this useful?
How can I relate the concept of interpersonal space to my game? My AI units have a limited sight range (each unit can only see a certain distance around itself) that essentially creates a sight "bubble" around each unit. See where I'm going with this? What if I utilized the different levels of interpersonal space to help determine whether or not a unit is aggressive enough to attack an enemy? Taking the most literal translation of the diagram, I made each section of interpersonal space correlate to a certain distance from the unit. Each section would be relative to a certain percentage of a unit's sight range.
If I were to equate the outer radius (25ft) of the diagram to the outer radius of a unit's sight bubble, I would get the following ratios:
- Intimate distance ranges from touching to about 18 inches (46 cm) apart, and is reserved for lovers, children, close family members, friends, and pet animals.
- Personal distance begins about an arm's length away; starting around 18 inches (46 cm) from the person and ending about 4 feet (122 cm) away. This space is used in conversations with friends, to chat with associates, and in group discussions.
- Social distance ranges from 4 to 8 feet (1.2 m - 2.4 m) away from the person and is reserved for strangers, newly formed groups, and new acquaintances.
- Public distance includes anything more than 8 feet (2.4 m) away, and is used for speeches, lectures, and theater. Public distance is essentially that range reserved for larger audiences.
- Intimate space <= 1.5 ft
- Personal Space <= 4 ft
- Social Space <= 8 ft
- Public Space <= 25 ft
How is this useful?
How can I relate the concept of interpersonal space to my game? My AI units have a limited sight range (each unit can only see a certain distance around itself) that essentially creates a sight "bubble" around each unit. See where I'm going with this? What if I utilized the different levels of interpersonal space to help determine whether or not a unit is aggressive enough to attack an enemy? Taking the most literal translation of the diagram, I made each section of interpersonal space correlate to a certain distance from the unit. Each section would be relative to a certain percentage of a unit's sight range.
If I were to equate the outer radius (25ft) of the diagram to the outer radius of a unit's sight bubble, I would get the following ratios:
- Intimate space:
1.5 ft / 25 ft -> 0.06
At or closer than 6% of a unit's sight range
- Personal Space:
4 ft / 25 ft -> 0.16
At or closer than 16% of a unit's sight range
- Social Space:
8 ft / 25 ft -> 0.32
At or closer than 32% of a unit's sight range
- Public Space:
25 ft / 25 ft -> 1
At or closer than 100% of a unit's sight range
- Intimate Space <= 6
- Personal Space <= 16
- Social Space <= 32
- Public Space <= 100
The idea was to add a multiplier (dependent on which bubble an enemy was located in) to how likely a unit was to be aggressive. I tried to translate each bubble into a value based on the premise of how someone might react towards a stranger within that bubble.
Here are my interpretations of aggressiveness in each bubble:
- Intimate Space:
The hug zone. This space starts at about elbow's length away. This is a space where someone would be very uncomfortable if a stranger were to get within. This space represents an area where physical damage can easily be inflicted and an attack would be hard to dodge.
Multiplier: 2
- Personal Space:
This is about arm's length away. This space represents an area where physical damage can easily be inflicted, but an attack would be fairly easy to dodge.
Multiplier: 1.5
- Social Space:
This is an acceptable space for strangers to be located in, but this space also implies that there is likely some form of interaction between everyone within. This is the space where someone might start to get defensive.
Multiplier: 1.25
- Public Space:
This is an acceptable space for strangers to be in and does not imply any sort of direct interaction.
There is no multiplier for this space.
Drawing Board: Idea #3 - Territory Multiplier
Animals have been known to be more aggressive in areas that they consider to be their territory. This concept is fairly simple. What if I used a multiplier (dependent on where, in regards to the unit's territory, the unit and enemy are located) in determining whether or not a unit is aggressive enough to attack?
Scenarios and interpretations translated into multipliers:
- The unit is in the unit's territory while the enemy is not:
This could be equated to being in your house, or on your lawn, and watching someone ride a bike down the middle of the street. This might prompt a unit to be slightly more aggressive because it is in its own territory, but not too aggressive because the enemy is not in the unit's territory.
Multiplier: 1.25
- Both the unit and the enemy are in the unit's territory: This could be equated to having a stranger enter your property while you are on the premises. You aren't too concerned about the stranger because you can keep your eye on them and can potentially stop any form of property damage/theft they might intend to do. However, there is still a stranger on your property so you will be more aggressive than normal.
Multiplier: 1.5
- The enemy is in the unit's territory while the unit is not:
This could be equated to being at your neighbor's house and watching someone walk up to your down. There is an unattended stranger on your property. If the stranger were to attempt any property damage or theft, it would be very difficult for you to stop them. You might be very aggressive in this situation.
Multiplier: 2
- Neither the unit nor the enemy is in the unit's territory:
This would be like seeing a stranger in public.
There is no multiplier for this scenario.
I wanted something inherently simple for implementation so I settled with a form of proximity based aggressiveness. The aggressiveness trait would correlate with a certain percentage of a unit's sight range. So a unit with a value of 50 for aggressiveness would be aggressive enough to attack any enemies that are at or closer than 50% of the unit's sight range. This idea utilizes a linear progression between the aggressiveness trait value and how aggressive a unit actually is. However, this idea still retains dynamism due to varying sight ranges and aggressiveness trait values. If it wasn't apparent, this idea is a modified version of the Interpersonal Space Multiplier.
Here is the function:
float percentOfSightEnemyIsAt = Vector2.Distance(Position, enemy.Position) / Sight;
if (percentOfSightEnemyIsAt <= Personality.Aggressiveness / 100f)
{
return (true);
}
else
{
return (false);
}
This function is designed so that an aggressiveness trait value of 100 will always result in a unit being aggressive enough to attack an enemy within the unit's sight range. While this is an elegant solution to defining aggressiveness, this function seems to be a little too simple. The aggressiveness behavior would greatly benefit from some additional logic. I'm going to try and work the Territory Multiplier concept into this function.
Here is the final function:
float territoryMultiplier = 1;
if (isUnitInTerritory)
{
territoryMultiplier = 2f;
if (isEnemyInTerritory)
{
territoryMultiplier = 3f;
}
}
float percentOfSightEnemyIsAt = Vector2.Distance(Position, enemy.Position) / Sight;
if (percentOfSightEnemyIsAt <= (territoryMultiplier * Personality.Aggressiveness) / 100f)
{
return (true);
}
else
{
return (false);
}
As you can see, the territory multiplier increases the range at which a unit will be aggressive. This leads to some interesting behavior.
That's all I have for today! I know that there are other ways this could have been done, so feel free to share any of your thoughts!
Here's a video demoing this behavior:
That's all I have for today! I know that there are other ways this could have been done, so feel free to share any of your thoughts!