Lesson 7: Combat System & AI Enemies

Welcome to the most exciting part of your AI-Powered RPG Game! In this lesson, you'll learn how to create an engaging combat system with intelligent AI enemies that adapt to player behavior, making every battle unique and challenging.

What You'll Build

By the end of this lesson, you'll have:

  • Dynamic Combat System with health, damage, and status effects
  • AI-Powered Enemies that learn and adapt to player strategies
  • Behavior Trees for complex enemy decision-making
  • Combat UI with health bars, damage numbers, and status indicators
  • Balanced Difficulty that scales with player progression

Why AI-Powered Combat Matters

The Problem: Traditional RPG combat is predictable and repetitive. Players quickly learn enemy patterns and exploit them.

The Solution: AI-driven enemies that:

  • Adapt to player strategies in real-time
  • Learn from previous encounters
  • Evolve their tactics based on player behavior
  • Create unique challenges every time

Prerequisites

Before starting this lesson, make sure you have:

  • ✅ Completed Lesson 6: Procedural Quest Generation
  • ✅ Working Unity project with character controller
  • ✅ Basic C# scripting knowledge
  • ✅ Understanding of Unity's animation system

Step 1: Design Your Combat System Architecture

Combat Data Structures

First, let's design the core combat system:

[System.Serializable]
public class CombatStats
{
    public int maxHealth;
    public int currentHealth;
    public int attack;
    public int defense;
    public int speed;
    public int level;
    public float experience;
}

[System.Serializable]
public class CombatAction
{
    public string actionName;
    public int damage;
    public float cooldown;
    public float range;
    public ActionType type;
    public StatusEffect[] effects;
}

public enum ActionType
{
    Attack,
    Defend,
    Heal,
    Buff,
    Debuff,
    Special
}

[System.Serializable]
public class StatusEffect
{
    public string effectName;
    public float duration;
    public int value;
    public EffectType type;
}

public enum EffectType
{
    Damage,
    Heal,
    Buff,
    Debuff,
    Stun,
    Poison
}

Combat Manager Class

Create a new script called CombatManager.cs:

using System.Collections.Generic;
using UnityEngine;

public class CombatManager : MonoBehaviour
{
    [Header("Combat Settings")]
    public float combatRange = 5f;
    public float turnTime = 3f;
    public bool isInCombat = false;

    [Header("Combatants")]
    public GameObject player;
    public List<GameObject> enemies = new List<GameObject>();

    private CombatStats playerStats;
    private List<CombatStats> enemyStats = new List<CombatStats>();
    private int currentTurn = 0;

    private void Start()
    {
        InitializeCombat();
    }

    private void InitializeCombat()
    {
        // Get player stats
        playerStats = player.GetComponent<CombatStats>();

        // Get enemy stats
        foreach (GameObject enemy in enemies)
        {
            CombatStats stats = enemy.GetComponent<CombatStats>();
            if (stats != null)
            {
                enemyStats.Add(stats);
            }
        }
    }

    public void StartCombat()
    {
        isInCombat = true;
        Debug.Log("Combat Started!");

        // Initialize combat UI
        UpdateCombatUI();

        // Start first turn
        StartCoroutine(CombatTurn());
    }

    private System.Collections.IEnumerator CombatTurn()
    {
        while (isInCombat)
        {
            if (currentTurn == 0) // Player turn
            {
                yield return new WaitForSeconds(turnTime);
                ProcessPlayerTurn();
            }
            else // Enemy turn
            {
                yield return new WaitForSeconds(turnTime);
                ProcessEnemyTurn();
            }

            currentTurn = (currentTurn + 1) % (enemies.Count + 1);

            // Check for combat end
            if (CheckCombatEnd())
            {
                EndCombat();
                break;
            }
        }
    }
}

Step 2: Create AI-Powered Enemy System

Enemy AI Controller

Create an EnemyAI.cs script:

using System.Collections.Generic;
using UnityEngine;

public class EnemyAI : MonoBehaviour
{
    [Header("AI Settings")]
    public float detectionRange = 10f;
    public float attackRange = 2f;
    public float moveSpeed = 3f;
    public float rotationSpeed = 5f;

    [Header("Combat Stats")]
    public CombatStats stats;
    public List<CombatAction> availableActions = new List<CombatAction>();

    [Header("AI Behavior")]
    public AIBehaviorType behaviorType = AIBehaviorType.Aggressive;
    public float learningRate = 0.1f;
    public float adaptationThreshold = 0.7f;

    private Transform player;
    private Vector3 lastPlayerPosition;
    private List<PlayerAction> playerActionHistory = new List<PlayerAction>();
    private Dictionary<string, float> actionEffectiveness = new Dictionary<string, float>();

    public enum AIBehaviorType
    {
        Aggressive,
        Defensive,
        Balanced,
        Adaptive
    }

    private void Start()
    {
        player = GameObject.FindGameObjectWithTag("Player").transform;
        InitializeAI();
    }

    private void InitializeAI()
    {
        // Initialize action effectiveness tracking
        foreach (CombatAction action in availableActions)
        {
            actionEffectiveness[action.actionName] = 0.5f; // Start with neutral effectiveness
        }
    }

    public void UpdateAI()
    {
        if (player == null) return;

        float distanceToPlayer = Vector3.Distance(transform.position, player.position);

        if (distanceToPlayer <= detectionRange)
        {
            if (distanceToPlayer <= attackRange)
            {
                // In attack range - choose best action
                CombatAction bestAction = ChooseBestAction();
                ExecuteAction(bestAction);
            }
            else
            {
                // Move towards player
                MoveTowardsPlayer();
            }
        }
        else
        {
            // Player not detected - patrol or idle
            Patrol();
        }
    }

    private CombatAction ChooseBestAction()
    {
        CombatAction bestAction = availableActions[0];
        float bestScore = 0f;

        foreach (CombatAction action in availableActions)
        {
            float score = CalculateActionScore(action);
            if (score > bestScore)
            {
                bestScore = score;
                bestAction = action;
            }
        }

        return bestAction;
    }

    private float CalculateActionScore(CombatAction action)
    {
        float baseScore = action.damage;

        // Factor in action effectiveness history
        if (actionEffectiveness.ContainsKey(action.actionName))
        {
            baseScore *= actionEffectiveness[action.actionName];
        }

        // Factor in current situation
        if (stats.currentHealth < stats.maxHealth * 0.3f && action.type == ActionType.Heal)
        {
            baseScore *= 2f; // Prioritize healing when low on health
        }

        // Factor in player behavior
        if (HasPlayerUsedDefensiveAction() && action.type == ActionType.Attack)
        {
            baseScore *= 1.5f; // Be more aggressive if player is defensive
        }

        return baseScore;
    }

    private bool HasPlayerUsedDefensiveAction()
    {
        // Check recent player actions for defensive patterns
        int recentActions = Mathf.Min(3, playerActionHistory.Count);
        int defensiveActions = 0;

        for (int i = playerActionHistory.Count - recentActions; i < playerActionHistory.Count; i++)
        {
            if (playerActionHistory[i].actionType == ActionType.Defend)
            {
                defensiveActions++;
            }
        }

        return defensiveActions >= 2; // Player has been defensive recently
    }

    private void ExecuteAction(CombatAction action)
    {
        Debug.Log($"Enemy {gameObject.name} uses {action.actionName}");

        // Execute the action
        if (action.type == ActionType.Attack)
        {
            AttackPlayer(action);
        }
        else if (action.type == ActionType.Heal)
        {
            HealSelf(action);
        }
        else if (action.type == ActionType.Buff)
        {
            ApplyBuff(action);
        }

        // Record action for learning
        RecordAction(action);
    }

    private void AttackPlayer(CombatAction action)
    {
        // Calculate damage
        int damage = Mathf.Max(1, action.damage + stats.attack - player.GetComponent<CombatStats>().defense);

        // Apply damage to player
        player.GetComponent<CombatStats>().TakeDamage(damage);

        // Show damage effect
        ShowDamageEffect(player.position, damage);
    }

    private void HealSelf(CombatAction action)
    {
        int healAmount = action.damage; // For heal actions, damage value represents heal amount
        stats.currentHealth = Mathf.Min(stats.maxHealth, stats.currentHealth + healAmount);

        // Show heal effect
        ShowHealEffect(transform.position, healAmount);
    }

    private void ApplyBuff(CombatAction action)
    {
        // Apply status effect to self
        foreach (StatusEffect effect in action.effects)
        {
            ApplyStatusEffect(effect);
        }
    }

    private void RecordAction(CombatAction action)
    {
        // Record action for learning
        PlayerAction enemyAction = new PlayerAction
        {
            actionName = action.actionName,
            actionType = action.type,
            timestamp = Time.time
        };

        // Store for effectiveness calculation
        StartCoroutine(EvaluateActionEffectiveness(enemyAction));
    }

    private System.Collections.IEnumerator EvaluateActionEffectiveness(PlayerAction action)
    {
        yield return new WaitForSeconds(2f); // Wait to see results

        // Evaluate how effective the action was
        float effectiveness = CalculateActionEffectiveness(action);

        // Update effectiveness tracking
        if (actionEffectiveness.ContainsKey(action.actionName))
        {
            actionEffectiveness[action.actionName] = Mathf.Lerp(
                actionEffectiveness[action.actionName], 
                effectiveness, 
                learningRate
            );
        }
    }

    private float CalculateActionEffectiveness(PlayerAction action)
    {
        // Simple effectiveness calculation based on damage dealt vs received
        float damageDealt = action.damageDealt;
        float damageReceived = action.damageReceived;

        if (damageReceived == 0) return 1f; // No damage received, action was effective

        return Mathf.Clamp01(damageDealt / damageReceived);
    }
}

Step 3: Implement Adaptive AI Learning

AI Learning System

Create an AILearningSystem.cs script:

using System.Collections.Generic;
using UnityEngine;

public class AILearningSystem : MonoBehaviour
{
    [Header("Learning Settings")]
    public float learningRate = 0.1f;
    public int memorySize = 100;
    public float adaptationThreshold = 0.7f;

    private Dictionary<string, float> actionEffectiveness = new Dictionary<string, float>();
    private List<CombatScenario> scenarioHistory = new List<CombatScenario>();
    private Dictionary<string, float> playerPatterns = new Dictionary<string, float>();

    [System.Serializable]
    public class CombatScenario
    {
        public string scenarioId;
        public List<PlayerAction> playerActions;
        public List<EnemyAction> enemyActions;
        public float outcome; // 1 = enemy won, 0 = player won
        public float timestamp;
    }

    [System.Serializable]
    public class PlayerAction
    {
        public string actionName;
        public ActionType actionType;
        public float timestamp;
        public int damageDealt;
        public int damageReceived;
    }

    [System.Serializable]
    public class EnemyAction
    {
        public string actionName;
        public ActionType actionType;
        public float timestamp;
        public int damageDealt;
        public int damageReceived;
    }

    public void RecordCombatScenario(CombatScenario scenario)
    {
        scenarioHistory.Add(scenario);

        // Maintain memory size
        if (scenarioHistory.Count > memorySize)
        {
            scenarioHistory.RemoveAt(0);
        }

        // Analyze scenario for learning
        AnalyzeScenario(scenario);
    }

    private void AnalyzeScenario(CombatScenario scenario)
    {
        // Analyze player patterns
        AnalyzePlayerPatterns(scenario);

        // Analyze action effectiveness
        AnalyzeActionEffectiveness(scenario);

        // Update AI behavior based on findings
        UpdateAIBehavior();
    }

    private void AnalyzePlayerPatterns(CombatScenario scenario)
    {
        foreach (PlayerAction action in scenario.playerActions)
        {
            string patternKey = $"{action.actionType}_{GetContextKey(scenario)}";

            if (playerPatterns.ContainsKey(patternKey))
            {
                playerPatterns[patternKey] = Mathf.Lerp(
                    playerPatterns[patternKey], 
                    scenario.outcome, 
                    learningRate
                );
            }
            else
            {
                playerPatterns[patternKey] = scenario.outcome;
            }
        }
    }

    private string GetContextKey(CombatScenario scenario)
    {
        // Create a context key based on scenario conditions
        return $"health_{scenario.enemyActions.Count}_actions_{scenario.playerActions.Count}_player_actions";
    }

    private void AnalyzeActionEffectiveness(CombatScenario scenario)
    {
        foreach (EnemyAction action in scenario.enemyActions)
        {
            if (actionEffectiveness.ContainsKey(action.actionName))
            {
                float effectiveness = CalculateEffectiveness(action, scenario);
                actionEffectiveness[action.actionName] = Mathf.Lerp(
                    actionEffectiveness[action.actionName], 
                    effectiveness, 
                    learningRate
                );
            }
            else
            {
                actionEffectiveness[action.actionName] = CalculateEffectiveness(action, scenario);
            }
        }
    }

    private float CalculateEffectiveness(EnemyAction action, CombatScenario scenario)
    {
        // Calculate effectiveness based on damage dealt vs received
        float damageRatio = action.damageDealt / Mathf.Max(1f, action.damageReceived);
        float outcomeBonus = scenario.outcome > 0.5f ? 1.2f : 0.8f;

        return Mathf.Clamp01(damageRatio * outcomeBonus);
    }

    private void UpdateAIBehavior()
    {
        // Update AI behavior based on learned patterns
        foreach (var pattern in playerPatterns)
        {
            if (pattern.Value > adaptationThreshold)
            {
                // Player is using this pattern effectively
                // AI should counter this pattern
                CounterPlayerPattern(pattern.Key);
            }
        }
    }

    private void CounterPlayerPattern(string patternKey)
    {
        // Implement counter-strategies based on player patterns
        Debug.Log($"AI learned to counter player pattern: {patternKey}");

        // This would trigger specific AI behaviors to counter the pattern
        // For example, if player uses defensive actions, AI becomes more aggressive
    }

    public float GetActionEffectiveness(string actionName)
    {
        if (actionEffectiveness.ContainsKey(actionName))
        {
            return actionEffectiveness[actionName];
        }
        return 0.5f; // Default neutral effectiveness
    }

    public string GetRecommendedAction(List<CombatAction> availableActions)
    {
        string bestAction = availableActions[0].actionName;
        float bestScore = 0f;

        foreach (CombatAction action in availableActions)
        {
            float effectiveness = GetActionEffectiveness(action.actionName);
            float score = action.damage * effectiveness;

            if (score > bestScore)
            {
                bestScore = score;
                bestAction = action.actionName;
            }
        }

        return bestAction;
    }
}

Step 4: Create Combat UI System

Combat UI Manager

Create a CombatUI.cs script:

using UnityEngine;
using UnityEngine.UI;
using TMPro;

public class CombatUI : MonoBehaviour
{
    [Header("UI References")]
    public GameObject combatPanel;
    public Slider playerHealthBar;
    public Slider enemyHealthBar;
    public TextMeshProUGUI playerHealthText;
    public TextMeshProUGUI enemyHealthText;
    public TextMeshProUGUI combatLog;
    public Button attackButton;
    public Button defendButton;
    public Button healButton;
    public Button specialButton;

    [Header("Damage Effects")]
    public GameObject damageNumberPrefab;
    public Transform damageNumberParent;

    private CombatManager combatManager;
    private CombatStats playerStats;
    private CombatStats enemyStats;

    private void Start()
    {
        combatManager = FindObjectOfType<CombatManager>();
        playerStats = combatManager.player.GetComponent<CombatStats>();
        enemyStats = combatManager.enemies[0].GetComponent<CombatStats>();

        SetupUI();
        SetupEventListeners();
    }

    private void SetupUI()
    {
        // Initialize health bars
        UpdateHealthBars();

        // Setup combat log
        combatLog.text = "Combat Started!";
    }

    private void SetupEventListeners()
    {
        attackButton.onClick.AddListener(() => PlayerAction(ActionType.Attack));
        defendButton.onClick.AddListener(() => PlayerAction(ActionType.Defend));
        healButton.onClick.AddListener(() => PlayerAction(ActionType.Heal));
        specialButton.onClick.AddListener(() => PlayerAction(ActionType.Special));
    }

    public void UpdateHealthBars()
    {
        // Update player health bar
        playerHealthBar.value = (float)playerStats.currentHealth / playerStats.maxHealth;
        playerHealthText.text = $"{playerStats.currentHealth}/{playerStats.maxHealth}";

        // Update enemy health bar
        enemyHealthBar.value = (float)enemyStats.currentHealth / enemyStats.maxHealth;
        enemyHealthText.text = $"{enemyStats.currentHealth}/{enemyStats.maxHealth}";
    }

    public void ShowDamageEffect(Vector3 position, int damage)
    {
        GameObject damageNumber = Instantiate(damageNumberPrefab, damageNumberParent);
        damageNumber.transform.position = position;

        TextMeshProUGUI damageText = damageNumber.GetComponent<TextMeshProUGUI>();
        damageText.text = damage.ToString();
        damageText.color = Color.red;

        // Animate damage number
        StartCoroutine(AnimateDamageNumber(damageNumber));
    }

    public void ShowHealEffect(Vector3 position, int healAmount)
    {
        GameObject healNumber = Instantiate(damageNumberPrefab, damageNumberParent);
        healNumber.transform.position = position;

        TextMeshProUGUI healText = healNumber.GetComponent<TextMeshProUGUI>();
        healText.text = $"+{healAmount}";
        healText.color = Color.green;

        // Animate heal number
        StartCoroutine(AnimateDamageNumber(healNumber));
    }

    private System.Collections.IEnumerator AnimateDamageNumber(GameObject damageNumber)
    {
        float duration = 1f;
        float elapsed = 0f;
        Vector3 startPos = damageNumber.transform.position;
        Vector3 endPos = startPos + Vector3.up * 2f;

        while (elapsed < duration)
        {
            elapsed += Time.deltaTime;
            float t = elapsed / duration;

            damageNumber.transform.position = Vector3.Lerp(startPos, endPos, t);
            damageNumber.GetComponent<TextMeshProUGUI>().alpha = 1f - t;

            yield return null;
        }

        Destroy(damageNumber);
    }

    public void AddCombatLog(string message)
    {
        combatLog.text += $"\n{message}";

        // Scroll to bottom
        Canvas.ForceUpdateCanvases();
        combatLog.GetComponent<ScrollRect>().verticalNormalizedPosition = 0f;
    }

    private void PlayerAction(ActionType actionType)
    {
        // Process player action
        combatManager.ProcessPlayerAction(actionType);

        // Update UI
        UpdateHealthBars();

        // Add to combat log
        string actionName = actionType.ToString();
        AddCombatLog($"Player uses {actionName}!");
    }
}

Step 5: Implement Status Effects System

Status Effect Manager

Create a StatusEffectManager.cs script:

using System.Collections.Generic;
using UnityEngine;

public class StatusEffectManager : MonoBehaviour
{
    private List<StatusEffect> activeEffects = new List<StatusEffect>();
    private CombatStats targetStats;

    private void Start()
    {
        targetStats = GetComponent<CombatStats>();
    }

    private void Update()
    {
        ProcessStatusEffects();
    }

    public void ApplyStatusEffect(StatusEffect effect)
    {
        // Check if effect already exists
        StatusEffect existingEffect = activeEffects.Find(e => e.effectName == effect.effectName);

        if (existingEffect != null)
        {
            // Refresh duration
            existingEffect.duration = effect.duration;
        }
        else
        {
            // Add new effect
            activeEffects.Add(new StatusEffect
            {
                effectName = effect.effectName,
                duration = effect.duration,
                value = effect.value,
                type = effect.type
            });
        }

        Debug.Log($"Applied {effect.effectName} for {effect.duration} seconds");
    }

    private void ProcessStatusEffects()
    {
        for (int i = activeEffects.Count - 1; i >= 0; i--)
        {
            StatusEffect effect = activeEffects[i];
            effect.duration -= Time.deltaTime;

            // Apply effect
            ApplyEffect(effect);

            // Remove expired effects
            if (effect.duration <= 0)
            {
                RemoveStatusEffect(effect);
            }
        }
    }

    private void ApplyEffect(StatusEffect effect)
    {
        switch (effect.type)
        {
            case EffectType.Damage:
                targetStats.TakeDamage(effect.value);
                break;
            case EffectType.Heal:
                targetStats.Heal(effect.value);
                break;
            case EffectType.Buff:
                ApplyBuff(effect);
                break;
            case EffectType.Debuff:
                ApplyDebuff(effect);
                break;
            case EffectType.Stun:
                // Implement stun logic
                break;
            case EffectType.Poison:
                targetStats.TakeDamage(effect.value);
                break;
        }
    }

    private void ApplyBuff(StatusEffect effect)
    {
        // Apply temporary stat buffs
        // This would modify the target's stats temporarily
    }

    private void ApplyDebuff(StatusEffect effect)
    {
        // Apply temporary stat debuffs
        // This would reduce the target's stats temporarily
    }

    private void RemoveStatusEffect(StatusEffect effect)
    {
        activeEffects.Remove(effect);
        Debug.Log($"Removed {effect.effectName}");
    }

    public bool HasStatusEffect(string effectName)
    {
        return activeEffects.Exists(e => e.effectName == effectName);
    }

    public List<StatusEffect> GetActiveEffects()
    {
        return new List<StatusEffect>(activeEffects);
    }
}

Step 6: Advanced AI Behaviors

Behavior Tree Implementation

Create a BehaviorTree.cs script:

using System.Collections.Generic;
using UnityEngine;

public class BehaviorTree : MonoBehaviour
{
    [Header("Behavior Tree Settings")]
    public float updateInterval = 0.1f;
    public float maxDecisionTime = 1f;

    private BehaviorNode rootNode;
    private float lastUpdateTime;

    private void Start()
    {
        BuildBehaviorTree();
    }

    private void Update()
    {
        if (Time.time - lastUpdateTime >= updateInterval)
        {
            ExecuteBehaviorTree();
            lastUpdateTime = Time.time;
        }
    }

    private void BuildBehaviorTree()
    {
        // Create behavior tree structure
        rootNode = new SequenceNode("Root");

        // Health check branch
        SequenceNode healthCheck = new SequenceNode("Health Check");
        healthCheck.AddChild(new HealthCheckNode());
        healthCheck.AddChild(new HealActionNode());

        // Combat branch
        SequenceNode combatBranch = new SequenceNode("Combat");
        combatBranch.AddChild(new PlayerInRangeNode());
        combatBranch.AddChild(new AttackActionNode());

        // Movement branch
        SequenceNode movementBranch = new SequenceNode("Movement");
        movementBranch.AddChild(new PlayerDetectedNode());
        movementBranch.AddChild(new MoveToPlayerNode());

        // Add branches to root
        rootNode.AddChild(healthCheck);
        rootNode.AddChild(combatBranch);
        rootNode.AddChild(movementBranch);
    }

    private void ExecuteBehaviorTree()
    {
        if (rootNode != null)
        {
            rootNode.Execute();
        }
    }
}

// Base behavior node class
public abstract class BehaviorNode
{
    protected string name;
    protected List<BehaviorNode> children = new List<BehaviorNode>();

    public BehaviorNode(string nodeName)
    {
        name = nodeName;
    }

    public abstract bool Execute();

    public void AddChild(BehaviorNode child)
    {
        children.Add(child);
    }
}

// Sequence node - executes children in order
public class SequenceNode : BehaviorNode
{
    public SequenceNode(string name) : base(name) { }

    public override bool Execute()
    {
        foreach (BehaviorNode child in children)
        {
            if (!child.Execute())
            {
                return false;
            }
        }
        return true;
    }
}

// Selector node - executes first successful child
public class SelectorNode : BehaviorNode
{
    public SelectorNode(string name) : base(name) { }

    public override bool Execute()
    {
        foreach (BehaviorNode child in children)
        {
            if (child.Execute())
            {
                return true;
            }
        }
        return false;
    }
}

// Health check node
public class HealthCheckNode : BehaviorNode
{
    public HealthCheckNode() : base("Health Check") { }

    public override bool Execute()
    {
        CombatStats stats = GetComponent<CombatStats>();
        return stats.currentHealth < stats.maxHealth * 0.3f;
    }
}

// Player in range node
public class PlayerInRangeNode : BehaviorNode
{
    public PlayerInRangeNode() : base("Player In Range") { }

    public override bool Execute()
    {
        Transform player = GameObject.FindGameObjectWithTag("Player").transform;
        float distance = Vector3.Distance(transform.position, player.position);
        return distance <= 2f; // Attack range
    }
}

// Attack action node
public class AttackActionNode : BehaviorNode
{
    public AttackActionNode() : base("Attack Action") { }

    public override bool Execute()
    {
        // Execute attack action
        GetComponent<EnemyAI>().ExecuteAction(GetComponent<EnemyAI>().availableActions[0]);
        return true;
    }
}

Step 7: Testing and Balancing

Combat Testing Script

Create a CombatTester.cs script:

using UnityEngine;

public class CombatTester : MonoBehaviour
{
    [Header("Test Settings")]
    public int testRounds = 100;
    public float testInterval = 1f;

    private CombatManager combatManager;
    private int currentRound = 0;

    private void Start()
    {
        combatManager = FindObjectOfType<CombatManager>();
        StartCoroutine(RunCombatTests());
    }

    private System.Collections.IEnumerator RunCombatTests()
    {
        while (currentRound < testRounds)
        {
            // Start combat
            combatManager.StartCombat();

            // Wait for combat to complete
            yield return new WaitUntil(() => !combatManager.isInCombat);

            // Record results
            RecordCombatResults();

            currentRound++;
            yield return new WaitForSeconds(testInterval);
        }

        AnalyzeTestResults();
    }

    private void RecordCombatResults()
    {
        // Record combat statistics
        Debug.Log($"Combat Round {currentRound} completed");
    }

    private void AnalyzeTestResults()
    {
        // Analyze AI learning and adaptation
        Debug.Log("Combat testing completed. Analyzing results...");
    }
}

Mini-Task: Create Your First AI Enemy

Your Mission: Create a simple AI enemy that learns from player behavior and adapts its strategy.

Steps:

  1. Set up the combat system with health and damage
  2. Create an AI enemy with basic behaviors
  3. Implement learning system that tracks player actions
  4. Test the enemy's adaptation over multiple encounters
  5. Verify the enemy becomes more challenging over time

Success Criteria:

  • ✅ Enemy responds to player actions
  • ✅ Learning system tracks player patterns
  • ✅ Enemy adapts strategy based on player behavior
  • ✅ Combat feels challenging and engaging

Common Issues and Solutions

Issue 1: AI Not Learning

Problem: Enemy AI doesn't seem to adapt to player behavior Solution: Check learning rate and memory size settings

Issue 2: Combat Too Easy/Hard

Problem: Difficulty not balanced properly Solution: Adjust damage values and AI decision weights

Issue 3: Performance Issues

Problem: AI calculations causing frame drops Solution: Implement AI update intervals and optimize calculations

Next Steps

Congratulations! You've built a sophisticated AI combat system. In the next lesson, you'll learn about:

  • Advanced AI Behaviors - More complex decision-making
  • Combat Balancing - Fine-tuning difficulty
  • Performance Optimization - Making your AI efficient

Resources

Community Challenge

Share Your AI Enemy: Post a video of your AI enemy in action and tag us on social media! Show off how your enemy adapts to different player strategies.

Pro Tip: Experiment with different learning rates and behavior patterns to create unique enemy personalities that feel alive and challenging.

Ready to create enemies that think, learn, and adapt? Let's build the AI combat system that will make your RPG unforgettable!