Introduction: The Core of Engaging Turn-Based Combat Systems

In turn-based combat systems, every move matters. Whether in a strategy RPG, tactical combat simulator, or even a card game, turn-based systems rely heavily on well-designed mechanics and thoughtful implementation. A robust and flexible combat system can significantly enhance your game, keeping players engaged and challenging their strategic thinking. However, building a complete system requires a deep understanding of game loops, state management, and event handling.

In this post, we’ll dive into an advanced, modular implementation of a turn-based combat system in Unity. We’ll not only cover turn-based mechanics but also advanced features such as character states, turn queues, enemy AI, action execution, and battle flow control. This system can be easily adapted to various genres, whether you’re making an RPG, tactical game, or any other project that requires turn-based combat.


Why a Turn-Based Combat System Is Crucial

Turn-based combat systems are an essential mechanic in many games. They allow players to strategize, take their time, and make thoughtful decisions. The combat is typically divided into turns where each character (player or enemy) has the opportunity to act. This system is more deliberate and calculated compared to real-time combat, offering players control over their actions, positioning, and resources.

Key elements of a solid turn-based combat system include:

  • Turn Order Management: Who goes next and in what order? This can depend on initiative, speed, or other attributes.
  • Character Actions: Each character can perform actions like attacking, using skills, healing, etc.
  • Enemy AI: AI needs to decide what action to take based on the state of the game.
  • Battle Flow Control: Managing transitions between phases, such as player turns, enemy turns, and action resolution.

Key Concepts and Design Patterns for Unity Turn-Based Combat

  1. Turn Queue System: You need a system to manage and store the order of actions for all characters involved in the combat. This can be based on initiative or other factors like speed.
  2. Action System: Every character can perform an action (e.g., attack, heal, defend). This system needs to be flexible to allow for complex abilities.
  3. Character State Management: Each character can have different states such as “Idle”, “Attacking”, “Defending”, and “Stunned”. These states affect how they can interact with the system.
  4. AI Decision Making: For enemy characters, AI must select actions based on the current game state, like attacking the player, healing, or defending.
  5. Event Handling: Turn-based combat often requires various events to trigger during combat, such as visual effects, status changes, and animations.

Advanced Code Implementation: Complete Turn-Based Combat System

Now, let’s implement a comprehensive turn-based combat system with all the necessary features, including a turn queue, character actions, AI behavior, and event handling.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

// CombatManager handles the flow of the battle, turn order, and action execution
public class CombatManager : MonoBehaviour
{
    public List<Character> characters; // Players and enemies involved in the battle
    private Queue<Character> turnQueue = new Queue<Character>(); // Turn queue to manage the order
    private bool isCombatActive = true;

    void Start()
    {
        InitializeCombat();
    }

    void InitializeCombat()
    {
        // Sort characters by initiative or speed, descending order
        characters.Sort((x, y) => y.initiative.CompareTo(x.initiative));
        foreach (var character in characters)
        {
            turnQueue.Enqueue(character); // Add characters to the turn queue
        }

        StartCoroutine(CombatLoop());
    }

    // Main battle loop that controls the turn flow
    IEnumerator CombatLoop()
    {
        while (isCombatActive)
        {
            // Get the next character from the queue and perform their action
            Character currentCharacter = turnQueue.Dequeue();
            if (currentCharacter.isAlive)
            {
                yield return StartCoroutine(currentCharacter.PerformAction());
            }

            // Re-enqueue the character at the end of the queue after their turn
            if (currentCharacter.isAlive)
            {
                turnQueue.Enqueue(currentCharacter);
            }

            yield return new WaitForSeconds(1f); // Add delay between turns
        }
    }
}

// Character class represents each participant in combat (player or enemy)
public class Character : MonoBehaviour
{
    public string name;
    public int health;
    public int attackPower;
    public int defense;
    public int initiative;
    public bool isAlive = true;
    public CharacterState currentState = CharacterState.Idle;
    
    public enum CharacterState { Idle, Attacking, Defending, Healing, Stunned }
    
    private CombatManager combatManager;

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

    // Perform the character's action based on the current state
    public IEnumerator PerformAction()
    {
        if (currentState == CharacterState.Idle)
        {
            // Decide the action for the current character (player or AI)
            if (name == "Player")
            {
                // Player takes action manually, for example, Attack
                currentState = CharacterState.Attacking;
                yield return StartCoroutine(AttackAction());
            }
            else
            {
                // AI decides to attack
                currentState = CharacterState.Attacking;
                yield return StartCoroutine(AttackAction());
            }
        }

        // Add more states such as healing, defending, etc.
    }

    // Perform the attack action, dealing damage to the target
    public IEnumerator AttackAction()
    {
        Debug.Log(name + " is attacking!");

        // Determine target (for simplicity, assume first enemy in the list is targeted)
        Character target = combatManager.characters.Find(c => c.name != name && c.isAlive);

        if (target != null)
        {
            int damage = Mathf.Max(0, attackPower - target.defense); // Calculate damage
            target.TakeDamage(damage);

            // Play attack animation or effects here
            yield return new WaitForSeconds(0.5f); // Simulate animation time
        }

        currentState = CharacterState.Idle;
    }

    // Apply damage to the character
    public void TakeDamage(int damage)
    {
        health -= damage;
        if (health <= 0)
        {
            health = 0;
            isAlive = false;
            Debug.Log(name + " has been defeated!");
        }
    }

    // Heal the character (example for future action types)
    public void Heal(int amount)
    {
        health += amount;
    }
}

// Example AI class for enemy behavior (can be extended)
public class EnemyAI : MonoBehaviour
{
    public void TakeTurn(Character character)
    {
        // Simple AI decision making: attack player if health is above a certain threshold
        if (character.health > 10)
        {
            character.currentState = CharacterState.Attacking;
        }
        else
        {
            character.currentState = CharacterState.Healing;
        }
    }
}

Key Features of the Code

  1. Combat Manager:
    • Turn Queue: This system processes the characters in order of their initiative. After each character completes their turn, they are re-enqueued at the end of the queue unless they are dead.
    • Turn Management: The CombatLoop coroutine ensures the game advances by calling the next character’s action. The loop continues until all characters are defeated.
  2. Character Actions:
    • Attack: The AttackAction method calculates damage based on the character’s attack power and the target’s defense.
    • States: The character’s state affects the action they can perform (idle, attacking, defending, healing).
  3. Enemy AI:
    • The AI selects an action based on the character’s health. This can be expanded to more complex behaviors like targeting the weakest player or healing itself when health is low.
  4. Modular Design: The system is modular and can be extended with new actions like healing, buffing, or special abilities. You can add more logic to handle turn transitions, status effects (like poison), or unique abilities.

Advantages and Disadvantages

Advantages:

  • Scalable: This system is designed to handle any number of characters and actions, making it suitable for RPGs or tactical games with large combat scenes.
  • Flexibility: Easily extendable to include additional states, AI behaviors, and new actions.
  • Clear Game Flow: The turn queue ensures a clear flow of combat, and the turn-based system gives players the time to plan their strategy.

Disadvantages:

  • Complexity: A system with many features (like AI, healing, buffs, etc.) can become complex to manage.
  • Performance: Handling large numbers of characters with complex actions may introduce performance issues, especially with many AI decisions and animations.

Conclusion

A well-designed turn-based combat system forms the heart of many RPGs and strategy games, providing a structured yet flexible combat experience. With Unity, you can build a system that is both scalable and adaptable, incorporating complex mechanics like AI, state management, and diverse actions.

By structuring the code in a modular way and following design patterns such as the state and strategy patterns, you create a system that is not only functional but also easy to extend and maintain. The advanced features provided in this post, including turn management, AI decision-making, and customizable actions, offer a strong foundation for your game’s combat system.

This system is designed to scale from small, tactical encounters to larger, more complex battles, so you can use it in a variety of genres. With these tools, you’ll be able to bring depth and excitement to your turn-based combat!

2 thoughts on “Building a Comprehensive Turn-Based Combat System in Unity: Advanced Features, Patterns, and Code Examples”
  1. Hello! I’m at work surfing around your blog from my new iphone 4! Just wanted to say I love reading through your blog and look forward to all your posts! Carry on the outstanding work!

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다