Search Unity

AI Behaviour [Discuss]

Discussion in 'Scripting' started by marraboy, Sep 18, 2008.

  1. marraboy

    marraboy

    Joined:
    Mar 25, 2008
    Posts:
    113
    Hi

    Following on from a different thread about AI I decided to have a little think about creating something that would be easy to implement and easy to manage regarding game characters.

    I came up with this, I would very much appreciate comments/tips on this (apologies - this is fairly lengthy):

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. ///<summary>
    5. /// Enum of the possible creature actions.
    6. ///</summary>
    7. public enum CreatureAction { DoNothing, Sleeping, Eating, Sitting, Standing }
    8.  
    9. ///<sumamry>
    10. /// Interface which all creature behaviour scripts must implement.
    11. ///</summary>
    12. public interface ICreatureBehaviour {
    13.     CreatureAction ActionThisScriptImplements { get; } 
    14. }
    15.  
    16. ///<summary>
    17. /// Sealed class to manage a creatures actions.
    18. ///</summary>
    19. public sealed class Creature : MonoBehaviour {
    20.  
    21.     ///<summary>
    22.     /// Unity exposed creature behaviours - upto 10
    23.     ///</summary>
    24.     public ICreatureBehaviour[] BehaviourScripts = new ICreatureBehaviour[10];
    25.  
    26.     private CreatureAction _currentAction = CreatureAction.DoNothing;
    27.  
    28.     ///<summary>
    29.     /// Gets or Sets the current creature behaviour.
    30.     ///</summary>
    31.     public CreatureAction CurrentAction {
    32.         set {
    33.             _currentAction = value;
    34.             ActivateScripts();
    35.         }  
    36.         get {
    37.             return _currentAction; 
    38.         }
    39.     }
    40.    
    41.     // activate/deactivate a script based upon its creature action.
    42.     private void ActivateScripts(){
    43.        
    44.         for(int i = 0; i < BehaviourScripts.Length; i++)
    45.         {
    46.             if(BehaviourScripts[i] != null)
    47.             {
    48.                 if(BehaviourScripts[i].ActionThisScriptImplements == _currentAction)
    49.                     ((GameObject)BehaviourScripts[i]).active = true;
    50.                 else
    51.                     ((GameObject)BehaviourScripts[i]).active = false;  
    52.             }
    53.         }
    54.     }
    55.    
    56.     // activate scripts on awake
    57.     private void Awake() {
    58.         ActivateScripts(); 
    59.     }
    60. }
    61.  
    62.  
    The idea is that the above script would be attached to the game object (the creature/character), and a number of behaviour scripts would also be added to the game object - but would also be added in the editor to the ICreatureBehaviour array. When you wanted to change the current 'behaviour' of the creature you would simple change the value in the public property CurrentAction.

    Here is the Behaviour scripts:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. ///<summary>
    5. /// Sealed class to implement an example sleeping behaviour of a creature.
    6. ///</summary>
    7. public sealed class SleepingBehaviour : MonoBehaviour, ICreatureBehaviour {
    8.  
    9.     ///<summary>
    10.     /// Gets the Action that this script implements.
    11.     /// </sleeping>
    12.     public CreatureAction ActionThisScriptImplements
    13.     {
    14.         get {
    15.             return CreatureAction.Sleeping;
    16.         }  
    17.     }
    18.    
    19.     // TODO: Implement the behaviours in here...
    20. }
    21.  
    22. ///<summary>
    23. /// Sealed class to implement an example eating behaviour of a creature.
    24. ///</summary>
    25. public sealed class EatingBehaviour : MonoBehaviour, ICreatureBehaviour {
    26.  
    27.     ///<summary>
    28.     /// Gets the Action that this script implements.
    29.     /// </sleeping>
    30.     public CreatureAction ActionThisScriptImplements
    31.     {
    32.         get {
    33.             return CreatureAction.Eating;  
    34.         }  
    35.     }
    36.    
    37.     // TODO: Implement the behaviours in here...
    38. }
    39.  
    40. // you get the idea...
    41.  
    I know there are many ways to implement this sort of stuff. Does anybody see any pitfalls/problems with this?

    I haven't actually tested this yet, it's just a thought!

    Ta

    JT
     
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    The main problem I can see is that you are hard-coding the possible states in the CreatureAction enum. You would therefore have to edit the code to add in new states like "laughing", "fleeing", etc, which seems to defeat the object of changing the settings in the editor. Also, the enum will either be specific to each type of creature you need or else it will have to contain all the states of every creature.

    There shouldn't be any problem if you use strings instead of enumerated values to represent the states.

    Also, it is common for state machines to need some set up code to be called each time a new state is entered and some kind of callback mechanism. For example, you might want to time how long a creature has been eating for animation purposes and then inform the control object when it has finished. You could extend ICreatureBehaviour to contain an OnEnterState method and an accessor to get/set the control object. The control object could then have a callback method to let the behaviour object choose the next state or whatever.

    As you can imagine, the sky's the limit with state machines but your scheme should be fairly easy to extend as you need.
     
  3. marraboy

    marraboy

    Joined:
    Mar 25, 2008
    Posts:
    113
    Yes I can see where you are coming from with enum limitations. I need to weigh up the options between making the code easier to implement (i.e. not remembering the strings) and scalability.

    Yeah, I should have made it clear that this was only a starter and did actually implement any of the behaviours and how the character made decisions to change between them. I would probably use delegated events to indicate when a particular behaviour was complete.

    Thanks for your response.