diff --git a/Assets/Scenes/MainGameWithAIFixed.shade b/Assets/Scenes/MainGameWithAIFixed.shade index 2ec3155e..d30799bc 100644 --- a/Assets/Scenes/MainGameWithAIFixed.shade +++ b/Assets/Scenes/MainGameWithAIFixed.shade @@ -8599,6 +8599,7 @@ Arm Length: 1 Look At Camera Origin: true Target Offset: {x: 0, y: 0, z: 0} + Camera Collision: false IsActive: true Scripts: - Type: SHADE_Scripting.ThirdPersonCamera @@ -8640,7 +8641,7 @@ Components: Transform Component: Translate: {x: 2.70000005, y: 0.100000001, z: -2} - Rotate: {x: -0, y: 0, z: -0} + Rotate: {x: -0, y: -2.09439516, z: -0} Scale: {x: 1, y: 1, z: 1} IsActive: true Renderable Component: @@ -8665,7 +8666,7 @@ Colliders: - Is Trigger: false Type: Box - Half Extents: {x: 1, y: 1.79999995, z: 0.400000006} + Half Extents: {x: 0.400000006, y: 1.79999995, z: 0.400000006} Friction: 0.400000006 Bounciness: 0 Density: 1 diff --git a/Assets/Scripts/AIBehaviour/BehaviourTree/Core/BehaviourTree.cs b/Assets/Scripts/AIBehaviour/BehaviourTree/Core/BehaviourTree.cs index 404e3df8..092c4087 100644 --- a/Assets/Scripts/AIBehaviour/BehaviourTree/Core/BehaviourTree.cs +++ b/Assets/Scripts/AIBehaviour/BehaviourTree/Core/BehaviourTree.cs @@ -66,9 +66,17 @@ namespace SHADE_Scripting.AIBehaviour.BehaviourTree //Getters and setters for the blackboard public object GetData(string key) { + //Debug.Log("Getting Data " + key); object outData = null; - if (blackboard.TryGetValue(key, out outData)) return outData; - else return outData; + if (blackboard.TryGetValue(key, out outData)) + { + return outData; + } + else + { + //Debug.LogError("Cannot retrieve data " + key); + return outData; + } } public void SetData(string key, object data) { diff --git a/Assets/Scripts/AIBehaviour/Implemented/Homeowner1.cs b/Assets/Scripts/AIBehaviour/Implemented/Homeowner1.cs index a90a3157..ff315df2 100644 --- a/Assets/Scripts/AIBehaviour/Implemented/Homeowner1.cs +++ b/Assets/Scripts/AIBehaviour/Implemented/Homeowner1.cs @@ -84,17 +84,55 @@ public partial class Homeowner1 : BehaviourTree _events = new Homeowner1Events(this); events.Initialise(); - //Initialise the waypoints here - if (waypointsPool) + //(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 @@ -103,9 +141,10 @@ public partial class Homeowner1 : BehaviourTree footstepTimeRemaining -= velocity * Time.DeltaTimeF; if (footstepTimeRemaining < 0.0f) { - Debug.Log("AI Play Footstep SFX"); + Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_footsteps"); footstepTimeRemaining = footstepSFXIntervalMultiplier; } + //Debug.Log("Ticked"); } //Define the behaviour tree here @@ -113,20 +152,22 @@ public partial class Homeowner1 : BehaviourTree //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", GetComponent(), eyeOffset, sightDistance), + new LeafSearch("SearchFOV"), new BehaviourTreeSequence("CatchPlayer", new List { - new LeafChase("Chasing", GetComponent(), GetComponent(), chaseSpeed, turningSpeed, distanceToCapture, captureTime), - new LeafAttack("Attacking", GameObject.Find("Player").GetValueOrDefault()) + new LeafChase("Chasing"), + new LeafAttack("Attacking") }) }), - new LeafPatrol("Patrol", GetComponent(), patrolSpeed, turningSpeed, GetComponent()) + new LeafPatrol("Patrol") }); + //Debug.Log("Tree Created"); return root; } } \ No newline at end of file diff --git a/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafAttack.cs b/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafAttack.cs index 15c0ed67..71a23115 100644 --- a/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafAttack.cs +++ b/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafAttack.cs @@ -21,16 +21,40 @@ using System.Threading.Tasks; //VARIABLES public partial class LeafAttack : BehaviourTreeNode { - //Holds the player game object + //Holds the player game object that is to be targeted private GameObject player; } //FUNCTIONS public partial class LeafAttack : BehaviourTreeNode { - public LeafAttack(string name, GameObject p) : base (name) + public LeafAttack(string name) : base (name) { - player = p; + //Debug.Log("LeafAttack ctor"); + } + + //Helper, find the nearest unobstructed waypoint to return to when chase is over + public void reevaluateWaypoint() + { + List waypoints = (List)GetNodeData("waypoints"); + Transform transform = (Transform)GetNodeData("transform"); + + if (waypoints == null || transform == null) + { + SetNodeData("currentWaypointIndex", 0); + return; + } + + int nearestWaypointIndex = 0; + for (int i = 0; i < waypoints.Count; ++i) + { + if ((transform.GlobalPosition - waypoints[i].GetComponent().GlobalPosition).GetSqrMagnitude() < + (transform.GlobalPosition - waypoints[nearestWaypointIndex].GetComponent().GlobalPosition).GetSqrMagnitude()) + { + nearestWaypointIndex = i; + } + } + SetNodeData("currentWaypointIndex", nearestWaypointIndex); } public override BehaviourTreeNodeStatus Evaluate() @@ -40,20 +64,36 @@ public partial class LeafAttack : BehaviourTreeNode onEnter(BehaviourTreeNodeStatus.RUNNING); - //Succeed when stand in hurt box for long enough - object timeObj = GetNodeData("captureTimeLeft"); - if (timeObj == null) + //Get Data + float? captureTime; + if (GetNodeData("captureTimeLeft") == null) { - return BehaviourTreeNodeStatus.FAILURE; + status = BehaviourTreeNodeStatus.FAILURE; + onExit(BehaviourTreeNodeStatus.FAILURE); + return status; } + else + captureTime = (float)GetNodeData("captureTimeLeft"); - float captureTime = (float)GetNodeData("captureTimeLeft"); + if (GameObject.Find("Player") == null) + { + status = BehaviourTreeNodeStatus.FAILURE; + onExit(BehaviourTreeNodeStatus.FAILURE); + return status; + } + else + player = GameObject.Find("Player").GetValueOrDefault(); + + //Succeed when stand in hurt box for long enough + //Debug.Log("Attempting to get blackboard data"); + //Debug.Log("Got blackboard data"); captureTime -= Time.DeltaTimeF; SetNodeData("captureTimeLeft", captureTime); //Debug.Log(captureTime.ToString()); if (captureTime <= 0.0f) { //Catch player when in range for long enough + //Debug.Log("Success: Caught"); player.GetScript().currentState = PlayerController.RaccoonStates.CAUGHT; status = BehaviourTreeNodeStatus.SUCCESS; onExit(BehaviourTreeNodeStatus.SUCCESS); @@ -61,8 +101,7 @@ public partial class LeafAttack : BehaviourTreeNode } //Return running if not success - - //Debug.Log("Success: Caught"); + //Debug.Log("Running: About to capture in " + captureTimeLeft); status = BehaviourTreeNodeStatus.RUNNING; onExit(BehaviourTreeNodeStatus.RUNNING); return status; diff --git a/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafChase.cs b/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafChase.cs index 87e8ae1e..de3352d6 100644 --- a/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafChase.cs +++ b/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafChase.cs @@ -24,9 +24,9 @@ public partial class LeafChase : BehaviourTreeNode private Transform transform; private RigidBody rb; private float chaseSpeed; - private float turnSpeed; + private float turningSpeed; private float captureDistance; - private float captureTime; + private float baseCaptureTime; } //FUNCTIONS @@ -34,29 +34,69 @@ public partial class LeafChase : BehaviourTreeNode { //Despite inheriting from BehaviourTreeNode, we don't have children to this node, //and hence we don't need to inherit its constructors - public LeafChase(string name, Transform t, RigidBody rb, float cSpd, float tSpd, float capDist, float capTime) : base (name) + public LeafChase(string name) : base (name) { - transform = t; - this.rb = rb; - chaseSpeed = cSpd; - turnSpeed = tSpd; - captureDistance = capDist; - captureTime = capTime; + //Debug.Log("LeafChase ctor"); + } + + //Helper, find which waypoint player is closest to + private void determinePlayerWaypoint() + { + List waypoints = (List)GetNodeData("waypoints"); + Transform target = (Transform)GetNodeData("target"); + if (waypoints == null || target == null) + { + return; + } + + int nearestWaypointIndex = 0; + for (int i = 0; i < waypoints.Count; ++i) + { + if ((target.GlobalPosition - waypoints[i].GetComponent().GlobalPosition).GetSqrMagnitude() < + (target.GlobalPosition - waypoints[nearestWaypointIndex].GetComponent().GlobalPosition).GetSqrMagnitude()) + { + nearestWaypointIndex = i; + } + } + //Debug.Log("Player is nearest " + nearestWaypointIndex); + //Debug.Log("I'm at " + (int)GetNodeData("currentWaypointIndex")); + SetNodeData("playerLastSightedWaypointIndex", nearestWaypointIndex); } public override BehaviourTreeNodeStatus Evaluate() { //Debug.LogWarning("LeafChase"); + onEnter(BehaviourTreeNodeStatus.RUNNING); + + //Get Data + if (GetNodeData("transform") == null || + GetNodeData("rigidBody") == null || + GetNodeData("turningSpeed") == null || + GetNodeData("chaseSpeed") == null || + GetNodeData("distanceToCapture") == null || + GetNodeData("baseCaptureTime") == null) + { + status = BehaviourTreeNodeStatus.FAILURE; + onExit(BehaviourTreeNodeStatus.FAILURE); + return status; + } + else + { + transform = (Transform)GetNodeData("transform"); + rb = (RigidBody)GetNodeData("rigidBody"); + chaseSpeed = (float)GetNodeData("chaseSpeed"); + turningSpeed = (float)GetNodeData("turningSpeed"); + captureDistance = (float)GetNodeData("distanceToCapture"); + baseCaptureTime = (float)GetNodeData("baseCaptureTime"); + } + //Fail if no target in blackboard if (GetNodeData("target") == null) { //Debug.Log("Failure: No target in blackboard"); return BehaviourTreeNodeStatus.FAILURE; } - - onEnter(BehaviourTreeNodeStatus.RUNNING); - Transform target = (Transform)GetNodeData("target"); Vector3 normalisedDifference = target.GlobalPosition - transform.GlobalPosition; @@ -71,7 +111,7 @@ public partial class LeafChase : BehaviourTreeNode if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true) { - Debug.Log("AI play unalert hmm"); + Audio.PlaySFXOnce2D("event:/Homeowner/humming"); } SetNodeData("isAlert", false); @@ -93,13 +133,32 @@ public partial class LeafChase : BehaviourTreeNode { //Debug.Log("Running: Chasing"); Quaternion targetRotation = Quaternion.LookRotation(normalisedDifference, new Vector3(0.0f, 1.0f, 0.0f)); - transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turnSpeed * Time.DeltaTimeF); + transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turningSpeed * Time.DeltaTimeF); + + + //Determine the player's nearest waypoint as long as the AI can see the player + //Head towards that waypoint in an attempt to chase the player + determinePlayerWaypoint(); //TODO delete this when original intendd code above works with velocity being limited correctly - rb.LinearVelocity = normalisedDifference * chaseSpeed; + //Only chase the player directly if the player's waypoint matches the AI's own + if (GetNodeData("currentWaypointIndex") != null && GetNodeData("playerLastSightedWaypointIndex") != null) + { + if ((int)GetNodeData("currentWaypointIndex") == (int)GetNodeData("playerLastSightedWaypointIndex")) + { + //Debug.Log("Waypoint indicees matching. Chasing directly"); + rb.LinearVelocity = normalisedDifference * chaseSpeed; + } + else + { + status = BehaviourTreeNodeStatus.FAILURE; + onExit(BehaviourTreeNodeStatus.FAILURE); + return BehaviourTreeNodeStatus.FAILURE; + } + } //Reset capture timing to base - SetNodeData("captureTimeLeft", captureTime); + SetNodeData("captureTimeLeft", baseCaptureTime); //Not capturing, don't play SFX SetNodeData("isCapturing", false); @@ -114,12 +173,12 @@ public partial class LeafChase : BehaviourTreeNode //Debug.Log("Success: Near enough. Begin attack"); //Look at the correct direction Quaternion targetRotation = Quaternion.LookRotation(normalisedDifference, new Vector3(0.0f, 1.0f, 0.0f)); - transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turnSpeed * Time.DeltaTimeF); + transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turningSpeed * Time.DeltaTimeF); //Play SFX if (GetNodeData("isCapturing") != null && (bool)GetNodeData("isCapturing") == false) { - Debug.Log("AI Play capturing SFX"); + //Debug.Log("AI Play capturing SFX"); } SetNodeData("isCapturing", true); diff --git a/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafPatrol.cs b/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafPatrol.cs index 802157cf..2f9c8e1a 100644 --- a/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafPatrol.cs +++ b/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafPatrol.cs @@ -22,13 +22,15 @@ public partial class LeafPatrol : BehaviourTreeNode { //Waypoints and movement private Transform transform; - private List waypoints; + private List? waypoints; private RigidBody rb; private float patrolSpeed; + private float chaseSpeed; private float turningSpeed; private float retreatTimer = 0.0f; private int currentWaypointIndex = 0; private bool retreatState = false; + private bool goingForwards = true; //Small delays between waypoints private bool isWaiting = false; @@ -42,13 +44,8 @@ public partial class LeafPatrol : BehaviourTreeNode //Constructor, establish values here //Despite inheriting from BehaviourTreeNode, we don't have children to this //node, and hence we do not need to inherit its constructors - public LeafPatrol(string name, Transform t, float patrolSpeed, float turnSpeed, RigidBody rb) : base(name) + public LeafPatrol(string name) : base(name) { - transform = t; - this.patrolSpeed = patrolSpeed; - turningSpeed = turnSpeed; - this.rb = rb; - currentWaypointIndex = 0; } @@ -58,7 +55,28 @@ public partial class LeafPatrol : BehaviourTreeNode { //Debug.LogWarning("LeafPatrol"); onEnter(BehaviourTreeNodeStatus.RUNNING); - if(GetNodeData("currentWaypointIndex") == null) + + //Get data + if (GetNodeData("transform") == null || + GetNodeData("patrolSpeed") == null || + GetNodeData("chaseSpeed") == null || + GetNodeData("turningSpeed") == null || + GetNodeData("rigidBody") == null) + { + status = BehaviourTreeNodeStatus.FAILURE; + onExit(BehaviourTreeNodeStatus.FAILURE); + return status; + } + else + { + transform = (Transform)GetNodeData("transform"); + patrolSpeed = (float)GetNodeData("patrolSpeed"); + chaseSpeed = (float)GetNodeData("chaseSpeed"); + turningSpeed = (float)GetNodeData("turningSpeed"); + rb = (RigidBody)GetNodeData("rigidBody"); + } + + if (GetNodeData("currentWaypointIndex") == null) { SetNodeData("currentWaypointIndex", 0); } @@ -77,38 +95,90 @@ public partial class LeafPatrol : BehaviourTreeNode //Waiting, do not move if (GetNodeData("isWaiting") != null) { - waitCounter = 0.0f; + //Only wait to change waypoints if not alert + if (GetNodeData("isAlert") != null && !(bool)GetNodeData("isAlert")) + waitCounter = 0.0f; + isWaiting = true; ClearNodeData("isWaiting"); return; } - - object waypoint = GetNodeData("waypoints"); - if (waypoint == null) + waypoints = (List)GetNodeData("waypoints"); + if (waypoints == null) { return; } - - waypoints = (List)waypoint; Vector3 targetPosition = waypoints[currentWaypointIndex].GetComponent().GlobalPosition; - //Reach waypoint by X and Z being near enough //Do not consider Y of waypoints yet Vector3 remainingDistance = targetPosition - transform.GlobalPosition; remainingDistance.y = 0.0f; - //Reached waypoint, cycle if (remainingDistance.GetSqrMagnitude() < 0.1f) { + //If alert, may reverse + if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert")) + { + //If alert, may reverse if it's closer to the player + if (GetNodeData("playerLastSightedWaypointIndex") != null) + { + int playerWaypoint = (int)GetNodeData("playerLastSightedWaypointIndex"); + int forwardDistance = 0; + int backDistance = 0; + if (playerWaypoint < currentWaypointIndex) + { + //Player waypoint is behind current waypoint + forwardDistance = playerWaypoint + waypoints.Count() - currentWaypointIndex; + backDistance = currentWaypointIndex - playerWaypoint; + } + else + { + //Player waypoint is ahead of current waypoint (or same) + forwardDistance = playerWaypoint - currentWaypointIndex; + backDistance = currentWaypointIndex + waypoints.Count() - playerWaypoint; + } + + if (backDistance < forwardDistance) + { + //Go backwards + goingForwards = false; + + } + else + { + //Go forward + goingForwards = true; + } + } + else + { + //Fallback if no player waypoint data, go forward + goingForwards = true; + } + } + //Cycle waypoints - ++currentWaypointIndex; - if (currentWaypointIndex >= waypoints.Count()) - currentWaypointIndex = 0; + if (goingForwards) + { + ++currentWaypointIndex; + if (currentWaypointIndex >= waypoints.Count()) + currentWaypointIndex = 0; + } + else + { + --currentWaypointIndex; + if (currentWaypointIndex < 0) + currentWaypointIndex = waypoints.Count() - 1; + } + //Write to blackboard SetNodeData("currentWaypointIndex", currentWaypointIndex); - waitCounter = 0.0f; + //Only wait to change waypoints if not alert + if (GetNodeData("isAlert") != null && !(bool)GetNodeData("isAlert")) + waitCounter = 0.0f; + isWaiting = true; } else if (false /*Physics.OverlapSphere(_selfTransform.position, 0.3f, 1 << 8).Length > 0 && retreatState == false*/) @@ -150,8 +220,30 @@ public partial class LeafPatrol : BehaviourTreeNode //TODO delete this when original intended code above works with velocity being limited correctly if (rb != null) { - //Debug.Log("Null check passed?"); - rb.LinearVelocity = normalisedDifference * patrolSpeed; + //Move quickly if alert + if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert")) + { + //Debug.Log("Fast Patrol"); + rb.LinearVelocity = normalisedDifference * chaseSpeed; + } + else + { + rb.LinearVelocity = normalisedDifference * patrolSpeed; + } + + //Unalert if AI reaches player nearest + if (GetNodeData("currentWaypointIndex") != null && GetNodeData("playerLastSightedWaypointIndex") != null) + { + if ((int)GetNodeData("currentWaypointIndex") == (int)GetNodeData("playerLastSightedWaypointIndex")) + { + if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert")) + { + //Debug.Log("Unalert"); + Audio.PlaySFXOnce2D("event:/Homeowner/humming"); + } + SetNodeData("isAlert", false); + } + } } if (retreatState) { @@ -167,7 +259,6 @@ public partial class LeafPatrol : BehaviourTreeNode private void DelayAtWaypoint() { - //Debug.Log("DelayAtWaypoint"); waitCounter += Time.DeltaTimeF; if (waitCounter >= waitDuration) isWaiting = false; diff --git a/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs b/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs index 056b5a4a..4fa5e376 100644 --- a/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs +++ b/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs @@ -30,18 +30,14 @@ public partial class LeafSearch : BehaviourTreeNode //FUNCTIONS HERE public partial class LeafSearch : BehaviourTreeNode { - public LeafSearch(string name, Transform t, Vector3 eo, float sDist) : base(name) + public LeafSearch(string name) : base(name) { - transform = t; - eyeOffset = eo; - sightDistance = sDist; - player = null; + //Debug.Log("LeafSearch ctor"); } //Helper, find the nearest unobstructed waypoint to return to when chase is over - private void reevaluateWaypoint() + public void reevaluateWaypoint() { - Debug.Log("Reevaluating Waypoints"); List waypoints = (List)GetNodeData("waypoints"); if (waypoints == null) @@ -62,11 +58,40 @@ public partial class LeafSearch : BehaviourTreeNode SetNodeData("currentWaypointIndex", nearestWaypointIndex); } + //Helper for handling being alert + + //Helper for handling stopping of chases + private void handleChaseStop() + { + if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true) + { + Audio.PlaySFXOnce2D("event:/Homeowner/humming"); + reevaluateWaypoint(); + } + SetNodeData("isAlert", false); + } + public override BehaviourTreeNodeStatus Evaluate() { //Debug.LogWarning("LeafSearch"); onEnter(BehaviourTreeNodeStatus.RUNNING); + //Get data + if (GetNodeData("transform") == null || + GetNodeData("eyeOffset") == null || + GetNodeData("sightDistance") == null) + { + status = BehaviourTreeNodeStatus.FAILURE; + onExit(BehaviourTreeNodeStatus.FAILURE); + return status; + } + else + { + transform = (Transform)GetNodeData("transform"); + eyeOffset = (Vector3)GetNodeData("eyeOffset"); + sightDistance = (float)GetNodeData("sightDistance"); + } + //Search for player player = GameObject.Find("Player"); @@ -94,12 +119,7 @@ public partial class LeafSearch : BehaviourTreeNode if ((plrT.GlobalPosition - transform.GlobalPosition).GetMagnitude() > sightDistance) { //Debug.Log("Failure: Too far"); - if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true) - { - Debug.Log("AI play unalert hmm"); - reevaluateWaypoint(); - } - SetNodeData("isAlert", false); + //handleChaseStop(); status = BehaviourTreeNodeStatus.FAILURE; onExit(BehaviourTreeNodeStatus.FAILURE); return status; @@ -114,12 +134,7 @@ public partial class LeafSearch : BehaviourTreeNode if (Vector3.Dot(difference, lookDirection) < 0.0f) { //Debug.Log("Failure: Out of FOV"); - if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true) - { - Debug.Log("AI play unalert hmm"); - reevaluateWaypoint(); - } - SetNodeData("isAlert", false); + //handleChaseStop(); status = BehaviourTreeNodeStatus.FAILURE; onExit(BehaviourTreeNodeStatus.FAILURE); return status; @@ -132,20 +147,27 @@ public partial class LeafSearch : BehaviourTreeNode //Draw a ray, succeed if ray is unobstructed Vector3 eyePosition = transform.GlobalPosition + eyeOffset; - Ray sightRay = new Ray(eyePosition, plrT.GlobalPosition - eyePosition); + BoxCollider playerCollider = player.GetValueOrDefault().GetComponent().GetCollisionShape(0); + if (playerCollider == null) + { + //Debug.Log("Failure: Player has no collider"); + status = BehaviourTreeNodeStatus.FAILURE; + onExit(BehaviourTreeNodeStatus.FAILURE); + return status; + } + //Ray destination to target the centre of the player's collider instead of transform position + //Since transform position is often the raccoon's base and the ray needs to hit somewhere higher to be more reliable + Vector3 rayDestination = plrT.GlobalPosition + plrT.GlobalScale * playerCollider.PositionOffset; + Ray sightRay = new Ray(eyePosition, rayDestination - eyePosition); RaycastHit sightRayHit = Physics.Raycast(sightRay); //As of November 2022, RaycastHit contains only the FIRST object hit by //the ray in the Other GameObject data member //Diren may likely add ALL objects hit by the ray over December if (sightRayHit.Hit && sightRayHit.Other != player) { + //TODO sometimes the ray doesn't hit the player even if he's in plain sight because the ray hits the floor the player is on instead??? //Debug.Log("Failure: Ray hit obstacle named " + sightRayHit.Other.GetValueOrDefault().Name + " ID" + sightRayHit.Other.GetValueOrDefault().EntityId); - if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true) - { - Debug.Log("AI play unalert hmm"); - reevaluateWaypoint(); - } - SetNodeData("isAlert", false); + //handleChaseStop(); status = BehaviourTreeNodeStatus.FAILURE; onExit(BehaviourTreeNodeStatus.FAILURE); return status; @@ -160,11 +182,19 @@ public partial class LeafSearch : BehaviourTreeNode //Write player's transform into the blackboard SetNodeData("target", plrT); - if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == false) + if (GetNodeData("isAlert") == null) { - Debug.Log("AI Play Alerted Yell here"); + SetNodeData("isAlert", true); + Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_detect_raccoon"); + } + else + { + if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == false) + { + Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_detect_raccoon"); + } + SetNodeData("isAlert", true); } - SetNodeData("isAlert", true); status = BehaviourTreeNodeStatus.SUCCESS; onExit(BehaviourTreeNodeStatus.SUCCESS);