Chapter 3: NPC Personality System
Giving Your NPCs Character and Uniqueness
In Chapter 2: NPC Controller, we learned how to connect AI decisions to actions in the game world. But so far, all our NPCs would behave exactly the same way in similar situations. Real characters in games should have unique personalities - some might be aggressive while others are cautious, some might be intelligent while others act more randomly.
Imagine a game with two guard NPCs. If they both spot the player, should they both react exactly the same way? What if one guard is a seasoned veteran who carefully approaches, while the other is an aggressive hothead who charges in immediately? Creating these differences is where the NPC Personality System comes in!
What is the NPC Personality System?
The NPC Personality System is like creating a psychological profile for each AI character. Just as people have different personalities in real life, this system gives NPCs their own unique traits and tendencies that influence their decision-making.
Think of it like adjusting sliders on a character’s personality traits:
- How aggressive are they? (Will they attack on sight or only when threatened?)
- How intelligent are they? (Do they make smart decisions or simple ones?)
- How random are they? (Do they behave predictably or surprise the player?)
- How quickly do they learn? (Do they adapt to the player’s tactics?)
By setting these personality traits, you can create a wide variety of characters that behave uniquely, making your game world feel more alive and realistic.
Key Personality Traits
Let’s look at the core personality traits available in the system:
1. Aggressiveness
This trait determines how likely an NPC is to choose aggressive actions like attacking:
// Setting a guard to be highly aggressive (80% aggressive)
npcSettings.baseAggresiveness.Data.f = 80f;
// Setting a friendly villager to be barely aggressive (10% aggressive)
npcSettings.baseAggresiveness.Data.f = 10f;
Higher aggressiveness means the NPC is more likely to:
- Choose attack behaviors over other options
- Engage enemies from further away
- Be less likely to flee when damaged
2. Intelligence
This trait affects how “smart” an NPC appears to be:
// Setting a wizard NPC to be highly intelligent (90% intelligence)
npcSettings.baseIntelligence.Data.f = 90f;
// Setting a zombie to have low intelligence (20% intelligence)
npcSettings.baseIntelligence.Data.f = 20f;
Intelligence affects:
- The complexity of tasks the NPC can remember and execute
- How well they navigate around obstacles
- Whether they can recognize patterns in player behavior
- How many options they consider before making decisions
3. Randomness
This determines how predictable or chaotic an NPC’s behavior will be:
// Setting a disciplined soldier to be very predictable (20% randomness)
npcSettings.baseRandomness.Data.f = 20f;
// Setting a wild animal to be highly unpredictable (85% randomness)
npcSettings.baseRandomness.Data.f = 85f;
Higher randomness means:
- The NPC will sometimes make unexpected choices
- The same situation might result in different reactions
- Players find it harder to predict what the NPC will do next
4. Learning Skills
This represents how well an NPC adapts to new situations:
// Setting an adaptive AI boss to learn quickly (75% learning)
npcSettings.baseLearningSkills.Data.f = 75f;
// Setting a simple enemy to barely learn (15% learning)
npcSettings.baseLearningSkills.Data.f = 15f;
Learning affects:
- How quickly the NPC adapts to player strategies
- Whether they remember past encounters
- If they change tactics when previous approaches fail
Behavior Permissions
Beyond personality traits, we can also set specific behavior permissions - actions the NPC is allowed to take:
// Set a companion NPC's permissions
npcSettings.follow.Data.b = true; // Can follow the player
npcSettings.attack.Data.b = true; // Can attack enemies
npcSettings.protect.Data.b = true; // Will defend allies
npcSettings.useWeapon.Data.b = true; // Can use weapons
npcSettings.selfDefend.Data.b = true; // Will defend itself
These boolean (true/false) settings act like “on/off switches” for specific behaviors. You can use them to create NPCs with specialized roles by enabling or disabling certain actions.
NPC Types and Moods
The system also includes pre-defined NPC types and moods to make creating common character archetypes easier:
// Create a hostile enemy NPC
npcSettings.npcType = NPCType.Enemy;
npcSettings.mood = Mood.Aggressive;
// Create a helpful companion NPC
npcSettings.npcType = NPCType.Companion;
npcSettings.mood = Mood.Friendly;
// Create a neutral townsperson
npcSettings.npcType = NPCType.UnBiased;
npcSettings.mood = Mood.Natural;
These presets help you quickly define common NPC types without having to manually set all the individual personality traits.
Practical Example: Creating Different Guard Types
Let’s create two different guard NPCs with distinct personalities:
void CreateVeteranGuard()
{
// Create the NPC GameObject and components
GameObject guardObject = new GameObject("Veteran Guard");
NpcController controller = guardObject.AddComponent<NpcController>();
// Get the settings component
NpcSettings settings = controller.settings;
// Configure veteran guard personality
settings.baseAggresiveness.Data.f = 50f; // Moderate aggression
settings.baseIntelligence.Data.f = 85f; // Very intelligent
settings.baseRandomness.Data.f = 30f; // Fairly predictable
settings.baseLearningSkills.Data.f = 70f; // Learns from experience
// Allow tactical behaviors
settings.follow.Data.b = true;
settings.attack.Data.b = true;
settings.selfDefend.Data.b = true;
settings.targetInSight.Data.b = true;
controller.ResetSettings();
}
This code creates a veteran guard who is intelligent, tactically predictable (not random), and learns from experience. Now let’s create a rookie guard:
void CreateRookieGuard()
{
// Create the NPC GameObject and components
GameObject guardObject = new GameObject("Rookie Guard");
NpcController controller = guardObject.AddComponent<NpcController>();
// Get the settings component
NpcSettings settings = controller.settings;
// Configure rookie guard personality
settings.baseAggresiveness.Data.f = 70f; // More aggressive
settings.baseIntelligence.Data.f = 40f; // Less intelligent
settings.baseRandomness.Data.f = 75f; // More unpredictable
settings.baseLearningSkills.Data.f = 35f; // Learns slowly
controller.ResetSettings();
}
This rookie guard is more aggressive (eager to prove themselves), less intelligent (inexperienced), more random (panicky), and slower to learn new tactics.
How Personality Affects Behavior Decisions
The personality traits don’t just define static values - they actively influence how the Behaviour System makes decisions. Let’s see how this works under the hood:
sequenceDiagram
participant NPC as NPC
participant BS as Behaviour System
participant PS as Personality System
participant DB as Decision Behavior
participant BM as Behaviour Manager
NPC->>BS: Need to make a decision
BS->>PS: Get personality influence
PS-->>BS: Return traits (aggression, etc.)
BS->>DB: Evaluate possible behaviors
DB->>DB: Apply personality weights
DB-->>BS: Return weighted behavior choices
BS->>BM: Execute chosen behavior
This diagram shows how personality traits filter into the decision-making process. When an NPC needs to decide what to do next, its personality traits influence which behaviors are more likely to be chosen.
The Influence of Aggressiveness
Let’s look at a specific example of how the aggressiveness trait affects behavior choice:
private void Database_NewTrigger(BehaviourType type)
{
// Only trigger behaviors based on randomness trait
if (Random.Range(0, 100) > settings.GetCurrentRandomness())
{
return; // Skip behavior if randomness check fails
}
switch (type)
{
case BehaviourType.Attack:
// Only proceed if not already attacking
if (manager.task?.behaviour?.type == type)
{
return;
}
// Higher priority task (5) means it overrides other behaviors
Task task = manager.AddTask(5);
UniObjectData target = GetRandomTarget();
if (target != null)
{
// If aggressive, directly attack target
// If not aggressive, approach first then decide
if (settings.GetCurrentAggresiveness() > 70)
{
// Aggressive: Skip approach, directly attack
task.AddBehaviour(new Behaviour(
BehaviourType.Attack,
Random.Range(1, 3),
TargetType.Character,
target));
}
else
{
// Less aggressive: Approach first
task.AddBehaviour(new Behaviour(
BehaviourType.Go,
Random.Range(2, 6),
TargetType.Character,
target));
task.AddBehaviour(new Behaviour(
BehaviourType.Attack,
Random.Range(1, 2),
TargetType.Character,
target));
}
}
break;
}
}
In this example:
- The randomness trait determines if the NPC even considers this behavior
- The aggressiveness trait then determines HOW the NPC attacks:
- Highly aggressive NPCs (>70) directly attack
- Less aggressive NPCs approach cautiously first, then attack
The Influence of Intelligence
Intelligence affects how many tasks an NPC can remember and prioritize:
// Limit task memory based on intelligence
int maxMemory = Mathf.FloorToInt(settings.GetCurrentIntelligence() / 20);
while (manager.tasks.Count > maxMemory)
{
// Remove least important tasks if we exceed memory capacity
manager.tasks.RemoveAt(manager.tasks.Count - 1);
}
Higher intelligence means the NPC can:
- Remember more tasks (higher
maxMemory) - Prioritize between more options
- Make more complex decisions
A low-intelligence NPC might forget what it was doing if something new catches its attention, while a high-intelligence NPC can balance multiple goals effectively.
How to Modify Personality at Runtime
NPCs don’t have to keep the same personality throughout the game. You can modify their traits in response to events:
// Make an NPC more aggressive when injured
public void OnTakeDamage(float damageAmount)
{
// Increase aggressiveness when hurt (cornered animal becomes dangerous)
float currentHealth = GetHealth();
if (currentHealth < 0.5f) // Below half health
{
// Temporarily boost aggression
npcSettings.aggresiveness += 20f;
// Schedule a return to normal after some time
StartCoroutine(RestoreNormalAggression(10f)); // After 10 seconds
}
}
private IEnumerator RestoreNormalAggression(float delay)
{
yield return new WaitForSeconds(delay);
// Return to base aggression level
npcSettings.aggresiveness = 0f;
}
This code makes an NPC more aggressive when injured, creating a “cornered animal” effect, then returns to normal after some time.
Connecting Personality with Other Systems
The NPC Personality System interacts with several other systems:
Connection to the Behaviour System
Personality traits directly influence which behaviors are chosen and how they’re executed:
// When creating behaviors, check personality traits
if (settings.GetCurrentAggresiveness() > 50 && settings.attack.Data.b)
{
// High aggression + allowed to attack = create attack behavior
manager.AddTask(2).AddBehaviour(new Behaviour(
BehaviourType.Attack,
3,
TargetType.Character,
target
));
}
else if (settings.follow.Data.b)
{
// Lower aggression = follow behavior instead
manager.AddTask(1).AddBehaviour(new Behaviour(
BehaviourType.Follow,
5,
TargetType.Character,
target
));
}
Connection to the Target System
Personality affects how NPCs choose and prioritize targets:
// Choosing which target to focus on
public UniObjectData SelectBestTarget(List<UniObjectData> possibleTargets)
{
if (possibleTargets.Count == 0) return null;
// More aggressive NPCs prioritize closer targets they can attack
if (settings.GetCurrentAggresiveness() > 70)
{
// Find closest target
return FindClosestTarget(possibleTargets);
}
// More intelligent NPCs might prioritize weakest targets
else if (settings.GetCurrentIntelligence() > 70)
{
// Find most vulnerable target
return FindWeakestTarget(possibleTargets);
}
// More random NPCs might choose unpredictably
else if (settings.GetCurrentRandomness() > 70)
{
// Pick a random target
int randomIndex = Random.Range(0, possibleTargets.Count);
return possibleTargets[randomIndex];
}
// Default to closest target
return FindClosestTarget(possibleTargets);
}
Creating Mood Presets
To make NPC creation easier, you can create preset personalities for common character types:
// Apply a preset mood to an NPC
public void ApplyMoodPreset(NpcSettings settings, Mood mood)
{
switch (mood)
{
case Mood.Friendly:
settings.baseAggresiveness.Data.f = 20f;
settings.baseRandomness.Data.f = 40f;
settings.follow.Data.b = true;
settings.attack.Data.b = false;
break;
case Mood.Aggressive:
settings.baseAggresiveness.Data.f = 85f;
settings.baseRandomness.Data.f = 50f;
settings.attack.Data.b = true;
settings.selfDefend.Data.b = true;
break;
case Mood.Coward:
settings.baseAggresiveness.Data.f = 10f;
settings.baseRandomness.Data.f = 70f;
settings.attack.Data.b = false;
settings.selfDefend.Data.b = false;
break;
// Other moods...
}
}
This function lets you quickly apply common personality types to NPCs without setting each trait individually.
Best Practices for Using the NPC Personality System
-
Start with Presets: Use the built-in NPC types and moods as starting points, then customize as needed.
-
Test Extreme Values: Try setting traits to very high or low values to see how they affect behavior.
-
Combination Effects: Remember that traits interact with each other - high aggression but low intelligence creates a different character than high aggression with high intelligence.
-
Dynamic Adjustments: Consider changing personality traits during gameplay based on events for more realistic character development.
-
Subtle Differences: Even small variations in personality traits can make NPCs feel different - you don’t need extreme differences for NPCs to feel unique.
Conclusion
The NPC Personality System transforms your AI characters from predictable robots into entities with unique behaviors and reactions. By adjusting traits like aggressiveness, intelligence, and randomness, you can create a wide range of character types that make your game world feel more alive and dynamic.
This system works hand-in-hand with the Behaviour System and NPC Controller we’ve already learned about, adding an extra layer of depth to your AI. Rather than explicitly programming every reaction, you can define personality traits and let the AI system naturally generate appropriate behaviors based on those traits.
In the next chapter, Factor Monitoring System, we’ll learn how to track and respond to important factors in the game world, allowing our NPCs to react appropriately to changes in their environment and situation.
Generated by AI Codebase Knowledge Builder