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

Best Pattern for Player Behaviour?

Discussion in 'Scripting' started by Terraya, Oct 6, 2020.

  1. Terraya

    Terraya

    Joined:
    Mar 8, 2018
    Posts:
    646
    Hey there,

    im Refactoring my Code ... ,
    and after Creating an AI Tree and an ActionScheduler for my A.I and Player i need also to rework my Player Behaviour,

    i have following Scripts:

    - Inventory
    - Mover
    - PlayerController
    - Interaction

    (Lets just stick to those 4 for now)

    there are a few things to consider:
    - whenever i move i shouldnt be able to open my inventory or interact with any Entity
    - whenever inventory is open, i shouldnt be able to interact or move
    - whenever i interact, i shouldnt be able to move or open the inventory

    so if i do one, the others shouldnt be able to happen until im finished,
    i have my ActionScheduler which lets me track the Action im doing but the main Question i have here is,
    what would be the best way to "CHECK" if im ready to do the other action?

    I know that having an ENUM with a few States is not a good way but i cant think of another way actualy .. ,
    i would finish my action and set the ENUM to "default" state ..
    the problem here would be to check if the ENUM state is inventory or interaction etc.. so i can do X action .. but with many states this gets messy ..

    EDIT: Here is may action scheduler:

    Code (CSharp):
    1.     public class ActionScheduler : MonoBehaviour
    2.     {
    3.         IAction currentAction;
    4.  
    5.         public void StartAction(IAction action)
    6.         {
    7.             if (currentAction == action) return;
    8.             if (currentAction != null)
    9.             {
    10.                 currentAction.Cancel();
    11.             }
    12.  
    13.             currentAction = action;
    14.         }
    15.  
    16.         public void CancelCurrentAction()
    17.         {
    18.             StartAction(null);
    19.         }
    20.  
    21.         public string GetCurrentAction() => currentAction.ToString();
    22.     }
    Another thing i could do would be , set always whenever im finisht doing anything my currentAction to "Null" so if the ActionScheduler is "Null" i can do another action... problem here would be, in case i want todo another action , the currentaction needs to be Null or something else ..
     
  2. David42142

    David42142

    Joined:
    Jul 15, 2015
    Posts:
    13
    Hello there, My approach would be to create seperate objects. Eg. create a GameObject called Inventory that holds all the nessecary UI Elements and attach a InventoryController Script, then enable and disable the Inventory from your PlayerController Script and before you handle your movement simply check if its active or not.

    If you really want to use enums you can use a switch statement:

    Code (CSharp):
    1. enum ActionType{inventory,interacting...}
    2.  
    3. switch(currentAction)
    4. {
    5.      case ActionType.inventory:
    6.         doInventoryControls();
    7.         break;
    8.      case ActionType.interacting:
    9.         interact();
    10.         break;
    11.      default:
    12.         doMovement();
    13.         break;
    14. }
     
    Terraya likes this.
  3. Sphinks

    Sphinks

    Joined:
    Apr 6, 2019
    Posts:
    267
    Would events a possibiliy for your case ? So each time if one action is done, send an event to the next action.
     
    Terraya likes this.
  4. Terraya

    Terraya

    Joined:
    Mar 8, 2018
    Posts:
    646
    Hey there!

    So well "ENUMS" are a very bad approach for a large scale game so i dont realy want this to use,

    basically i have figured out now a pattern based on my actionScheduler,
    My Monobehaviour Scripts have attached my Interface "IAction" , based on that interface
    i know that those scripts are an "Action" or at least i know that from there i can fire an action,

    so whenever i do an action i just call for example something like this:

    Code (CSharp):
    1.         private void InteractWithTarget()
    2.         {
    3.             actionScheduler.StartAction(this);
    4.             target = Casting.target != null ? Casting.target?.GetComponent<Interactable>() : null;
    5.             if (target != null)
    6.             {
    7.                 InteractWithTarget(true, () => target.Interact(gameObject));
    8.             }
    9.         }
    so based on that i know that the script is running which i called the function from + the function,


    @Sphinks Events would also be a good choice but i dont know the flexibility of that approach in my case,
    note: i do an "RPG like Gothic/Risen",

    so with my approach i do know what i am doing but i still need to change something so i can say "IF USER IS IN INVENTORY" then i need to ABORT that bymyself which means : "I shouldnt be able to run/interact/open inventory" and so on ..
     
  5. Terraya

    Terraya

    Joined:
    Mar 8, 2018
    Posts:
    646
    The problem here is, i want my Scripts to be flexible as possible and not rely on another scripts which means:

    - Inventory
    - Movement
    - Combat
    - UI
    - EquipmentHandler
    - EntityController
    - DailyBehvaiour
    - JobBehaviour

    etc... shouldnt necessarly stick together since also my NPCs are using them and so on,
    if i want an NPC only to have Inventory and "be" an NPC, then i just give him those 2 Scripts,
    if i want the NPC to do more, for example having a DailyRoutine, i also add this script for that and so on