Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Help structuring scripts for game with many autonomous agents

Discussion in 'Scripting' started by ujz, Nov 25, 2020.

  1. ujz

    ujz

    Joined:
    Feb 17, 2020
    Posts:
    28
    Hey guys, my game has about 100 autonomous agents spread throughout the world. The core logic revolves around:
    • STATS: Every agent has same stats including strength, speed, intelligence, dexterity, health, etc.
    • STATES: Every agent is either (1) a member of player's party, (2) friendly or (3) unfriendly. It is possible to transition between these three states
    • TYPE: Every agent is either (1) melee, (2) range or (3) magic
    • ACTIONS:
      • Agents in player's party have only two actions: (1) follow player, (2) use class ability on player's target
      • Friendly or unfriendly agents have four actions: (1) move to waypoint, (2) scan for enemies, (3) chase target, (4) use class ability on target
    So far my design is only using Monobehavior classes:
    • AgentProfile.cs = Sits on every agent and holds updates their STATS + STATE + TYPE
    • AgentActions.cs = Class for friendly or unfriendly agents that carries out actions through Update
    • PartyMemberActions.cs = Class for party members that carries out actions through Update
    I guess AgentProfile.cs is OK, but maybe it doesn't need to use Monobehavior? Maybe I can break it into structs or scriptableObjects to save performance? But in that case, how do I attach them to specific objects and track changes throughout the game? I know I cannot attach non-Monobehavior scripts to objects.

    My biggest problem is AgentActions.cs. It switches between actions (waypoint, scan, chase, class ability) using a bunch of if/else which is messy. I wish there was a way to break it into individual scripts or perhaps use a State Machine? But I'm not sure how to get started. I saw this video but it doesn't seem to apply to me because that video introduces a State Machine for an entire game, whereas I need State Machines for multiple agents.

    Would appreciate any advice from you wise sages. Thank you.
     
  2. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    Just a couple of quick notes - but design decisions like this are more philosophical than a question of right/wrong.

    Your states don't appear to be states but more fixed factions: ally, neutral, enemy. That's because I'm assuming that your agents don't transition much between states, which is usually what states are used for

    Your types should also bear closer examination: melee, ranged, and magic runs into problems: is a magic attack ranged? can a melee attack be magic? It appears to be more efficent if 'magic' is an attribute of the attack, and that can be ranged or melee.

    If you differentiate what to do based on attributes like friendly, magic, etc, you may want to re-think your approach here, and revisit some Object-Oriented documentation. You'd probably get more out of your scripts if you first designed a general Actions script, and then subclassed that for each type (melee, ranged).
     
    ujz likes this.
  3. ujz

    ujz

    Joined:
    Feb 17, 2020
    Posts:
    28
    Thanks for your reply. You're right, I should design along object-oriented rules. This is C# after all. I think I will make do as you said and make a general actions script with subclasses for each type.

    I will update this thread if I make something worth sharing. For anyone who stumbles on this, I'm finding this video by Sebastian Lague quite useful.
     
  4. Havyx

    Havyx

    Joined:
    Oct 20, 2020
    Posts:
    140

    This is kind of what scriptable objects were build for.

    https://docs.unity3d.com/Manual/class-ScriptableObject.html

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. [CreateAssetMenu(fileName = "Data", menuName = "SO/Agent", order = 1)]
    5. public class AgentSO : ScriptableObject
    6. {
    7.     public string strength;
    8.     public int speed;
    9.     public int intelligence;
    10. }
    11.  
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class Agent : MonoBehaviour
    5. {
    6.     public AgentSO agentData;
    7.  
    8.     void Start()
    9.     {
    10.         Debug.Log(agentData.strength);
    11.     }
    12. }
    13.