/********************************************************************* * \file Homeowner1.cs * \author Ryan Wang Nian Jing * \brief The implemented behaviour tree for the homeowner * A prototype to prove that behaviour trees can be worked and expanded * on in the custom engine for GAM300 Milestone 3 and expanded over * GAM350 * * * \copyright Copyright (c) 2022 DigiPen Institute of Technology. Reproduction or disclosure of this file or its contents without the prior written consent of DigiPen Institute of Technology is prohibited. *********************************************************************/ using SHADE; using SHADE_Scripting.AIBehaviour.BehaviourTree; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; //Variables required for the AI to function //To be attached to the game object via the inspector public partial class Homeowner1 : BehaviourTree { private BehaviourTreeEvents _events { get; set; } public override BehaviourTreeEvents events { get => _events; } //PATROL FIELDS/////////////////////////////////////////////////////////////// [SerializeField] [Tooltip("The list of waypoints for the AI to cycle around")] private GameObject waypointsPool; private List waypoints; [SerializeField] [Tooltip("The AI will patrol at this speed")] private float patrolSpeed; [SerializeField] [Tooltip("The speed at which the AI will chase the player if sighted")] private float chaseSpeed; [SerializeField] [Tooltip("Turning speed multiplier of the AI. 10 is good")] private float turningSpeed; //FIELD OF VISION///////////////////////////////////////////////////////////// [SerializeField] [Tooltip("How far the AI can see up to")] private float sightDistance; [SerializeField] [Tooltip("How far the eyes are offset from the AI's actual position")] private Vector3 eyeOffset; //ATTACKING/////////////////////////////////////////////////////////////////// [SerializeField] [Tooltip("How near the player mut be to the AI for capture")] private float distanceToCapture; [SerializeField] [Tooltip("How long the player should be in the attack range for successful capture")] private float captureTime; //There's definitely a better way to do this [SerializeField] [Tooltip("TO BE REMOVED IN 350. Interval multiplier between footsteps")] private float footstepSFXIntervalMultiplier; private float footstepTimeRemaining; } //AI tree public partial class Homeowner1 : BehaviourTree { //Called at the start protected override void Initialise() { _events = new Homeowner1Events(this); events.Initialise(); //(25 Nov) DO NOT Initialise the data here /*if (waypointsPool) { waypoints = (List)waypointsPool.GetChildren(); SetData("waypoints", waypoints); } SetData("transform", GetComponent()); SetData("rigidBody", GetComponent()); SetData("eyeOffset", eyeOffset); SetData("sightDistance", sightDistance); SetData("patrolSpeed", patrolSpeed); SetData("chaseSpeed", chaseSpeed); SetData("turningSpeed", turningSpeed); SetData("distanceToCapture", distanceToCapture); SetData("baseCaptureTime", captureTime);*/ } //Called every tick protected override void Tick() { //Debug.Log("Ticking"); //Update data if (GetData("waypoints") == null) { if (waypointsPool != GameObject.Null) SetData("waypoints", (List)waypointsPool.GetChildren()); else Debug.LogError("No waypoints, no AI"); } if (GetData("transform") == null) SetData("transform", GetComponent()); if (GetData("rigidBody") == null) SetData("rigidBody", GetComponent()); if (GetData("eyeOffset") == null || (Vector3)GetData("eyeOffset") != eyeOffset) SetData("eyeOffset", eyeOffset); if (GetData("sightDistance") == null || (float)GetData("sightDistance") != sightDistance) SetData("sightDistance", sightDistance); if (GetData("patrolSpeed") == null || (float)GetData("patrolSpeed") != patrolSpeed) SetData("patrolSpeed", patrolSpeed); if (GetData("chaseSpeed") == null || (float)GetData("chaseSpeed") != chaseSpeed) SetData("chaseSpeed", chaseSpeed); if (GetData("turningSpeed") == null || (float)GetData("turningSpeed") != turningSpeed) SetData("turningSpeed", turningSpeed); if (GetData("distanceToCapture") == null || (float)GetData("distanceToCapture") != distanceToCapture) SetData("distanceToCapture", distanceToCapture); if (GetData("baseCaptureTime") == null || (float)GetData("baseCaptureTime") != captureTime) SetData("baseCaptureTime", captureTime); events.Tick(); //Footsteps SFX, move them somewhere else soon float velocity = GetComponent().LinearVelocity.GetMagnitude(); footstepTimeRemaining -= velocity * Time.DeltaTimeF; if (footstepTimeRemaining < 0.0f) { Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_footsteps"); footstepTimeRemaining = footstepSFXIntervalMultiplier; } //Debug.Log("Ticked"); } //Define the behaviour tree here //Order of which nodes are created affects order of execution //The tree is called from the root every tick protected override BehaviourTreeNode CreateTree() { //Debug.Log("Creating Tree"); //Start from the root, structure it like this to make it look like a tree BehaviourTreeNode root = new BehaviourTreeSelector("Root", new List { new BehaviourTreeSequence("Alerted", new List { new LeafSearch("SearchFOV"), new BehaviourTreeSequence("CatchPlayer", new List { new LeafChase("Chasing"), new LeafAttack("Attacking") }) }), new LeafPatrol("Patrol") }); //Debug.Log("Tree Created"); return root; } }