Enhanced AI with better chase logic

- AI now keeps track of last waypoint he has seen player at and heads there in an attempt to chase him down
- AI can be made to reverse his chase/patrol path by running around him
- The scene with the AI fix is called "MainGameWithAIFixed"
This commit is contained in:
mushgunAX 2022-11-25 20:16:31 +08:00
parent 7499011ea2
commit 5b41e832c6
7 changed files with 219 additions and 57 deletions

View File

@ -8599,6 +8599,7 @@
Arm Length: 1 Arm Length: 1
Look At Camera Origin: true Look At Camera Origin: true
Target Offset: {x: 0, y: 0, z: 0} Target Offset: {x: 0, y: 0, z: 0}
Camera Collision: false
IsActive: true IsActive: true
Scripts: Scripts:
- Type: SHADE_Scripting.ThirdPersonCamera - Type: SHADE_Scripting.ThirdPersonCamera
@ -8640,7 +8641,7 @@
Components: Components:
Transform Component: Transform Component:
Translate: {x: 2.70000005, y: 0.100000001, z: -2} 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} Scale: {x: 1, y: 1, z: 1}
IsActive: true IsActive: true
Renderable Component: Renderable Component:
@ -8665,7 +8666,7 @@
Colliders: Colliders:
- Is Trigger: false - Is Trigger: false
Type: Box Type: Box
Half Extents: {x: 0.200000003, y: 0.899999976, z: 0.200000003} Half Extents: {x: 0.400000006, y: 1.79999995, z: 0.400000006}
Friction: 0.400000006 Friction: 0.400000006
Bounciness: 0 Bounciness: 0
Density: 1 Density: 1

View File

@ -74,6 +74,7 @@ namespace SHADE_Scripting.AIBehaviour.BehaviourTree
} }
else else
{ {
//Debug.LogError("Cannot retrieve data " + key);
return outData; return outData;
} }
} }

View File

@ -104,15 +104,14 @@ public partial class Homeowner1 : BehaviourTree
//Called every tick //Called every tick
protected override void Tick() protected override void Tick()
{ {
Debug.Log("Ticking"); //Debug.Log("Ticking");
//Update data //Update data
if (GetData("waypoints") == null) if (GetData("waypoints") == null)
{ {
if (waypointsPool) if (waypointsPool != GameObject.Null)
SetData("waypoints", (List<GameObject>)waypointsPool.GetChildren()); SetData("waypoints", (List<GameObject>)waypointsPool.GetChildren());
else
List<GameObject> wpTemp = (List<GameObject>)GetData("waypoints"); Debug.LogError("No waypoints, no AI");
Debug.Log(wpTemp.Count.ToString());
} }
if (GetData("transform") == null) if (GetData("transform") == null)
SetData("transform", GetComponent<Transform>()); SetData("transform", GetComponent<Transform>());
@ -145,7 +144,7 @@ public partial class Homeowner1 : BehaviourTree
Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_footsteps"); Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_footsteps");
footstepTimeRemaining = footstepSFXIntervalMultiplier; footstepTimeRemaining = footstepSFXIntervalMultiplier;
} }
Debug.Log("Ticked"); //Debug.Log("Ticked");
} }
//Define the behaviour tree here //Define the behaviour tree here
@ -153,7 +152,7 @@ public partial class Homeowner1 : BehaviourTree
//The tree is called from the root every tick //The tree is called from the root every tick
protected override BehaviourTreeNode CreateTree() protected override BehaviourTreeNode CreateTree()
{ {
Debug.Log("Creating Tree"); //Debug.Log("Creating Tree");
//Start from the root, structure it like this to make it look like a tree //Start from the root, structure it like this to make it look like a tree
BehaviourTreeNode root = new BehaviourTreeSelector("Root", new List<BehaviourTreeNode> BehaviourTreeNode root = new BehaviourTreeSelector("Root", new List<BehaviourTreeNode>
{ {
@ -168,7 +167,7 @@ public partial class Homeowner1 : BehaviourTree
}), }),
new LeafPatrol("Patrol") new LeafPatrol("Patrol")
}); });
Debug.Log("Tree Created"); //Debug.Log("Tree Created");
return root; return root;
} }
} }

View File

@ -21,7 +21,7 @@ using System.Threading.Tasks;
//VARIABLES //VARIABLES
public partial class LeafAttack : BehaviourTreeNode public partial class LeafAttack : BehaviourTreeNode
{ {
//Holds the player game object //Holds the player game object that is to be targeted
private GameObject player; private GameObject player;
} }
@ -30,12 +30,36 @@ public partial class LeafAttack : BehaviourTreeNode
{ {
public LeafAttack(string name) : base (name) public LeafAttack(string name) : base (name)
{ {
Debug.Log("LeafAttack ctor"); //Debug.Log("LeafAttack ctor");
}
//Helper, find the nearest unobstructed waypoint to return to when chase is over
public void reevaluateWaypoint()
{
List<GameObject> waypoints = (List<GameObject>)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<Transform>().GlobalPosition).GetSqrMagnitude() <
(transform.GlobalPosition - waypoints[nearestWaypointIndex].GetComponent<Transform>().GlobalPosition).GetSqrMagnitude())
{
nearestWaypointIndex = i;
}
}
SetNodeData("currentWaypointIndex", nearestWaypointIndex);
} }
public override BehaviourTreeNodeStatus Evaluate() public override BehaviourTreeNodeStatus Evaluate()
{ {
Debug.LogWarning("LeafAttack"); //Debug.LogWarning("LeafAttack");
//Fail if no target in blackboard? //Fail if no target in blackboard?
onEnter(BehaviourTreeNodeStatus.RUNNING); onEnter(BehaviourTreeNodeStatus.RUNNING);
@ -49,7 +73,7 @@ public partial class LeafAttack : BehaviourTreeNode
return status; return status;
} }
else else
captureTime = (float)GetNodeData("captureTime"); captureTime = (float)GetNodeData("captureTimeLeft");
if (GameObject.Find("Player") == null) if (GameObject.Find("Player") == null)
{ {
@ -69,6 +93,7 @@ public partial class LeafAttack : BehaviourTreeNode
if (captureTime <= 0.0f) if (captureTime <= 0.0f)
{ {
//Catch player when in range for long enough //Catch player when in range for long enough
//Debug.Log("Success: Caught");
player.GetScript<PlayerController>().currentState = PlayerController.RaccoonStates.CAUGHT; player.GetScript<PlayerController>().currentState = PlayerController.RaccoonStates.CAUGHT;
status = BehaviourTreeNodeStatus.SUCCESS; status = BehaviourTreeNodeStatus.SUCCESS;
onExit(BehaviourTreeNodeStatus.SUCCESS); onExit(BehaviourTreeNodeStatus.SUCCESS);
@ -76,8 +101,7 @@ public partial class LeafAttack : BehaviourTreeNode
} }
//Return running if not success //Return running if not success
//Debug.Log("Running: About to capture in " + captureTimeLeft);
Debug.Log("Success: Caught");
status = BehaviourTreeNodeStatus.RUNNING; status = BehaviourTreeNodeStatus.RUNNING;
onExit(BehaviourTreeNodeStatus.RUNNING); onExit(BehaviourTreeNodeStatus.RUNNING);
return status; return status;

View File

@ -36,21 +36,36 @@ public partial class LeafChase : BehaviourTreeNode
//and hence we don't need to inherit its constructors //and hence we don't need to inherit its constructors
public LeafChase(string name) : base (name) public LeafChase(string name) : base (name)
{ {
Debug.Log("LeafChase ctor"); //Debug.Log("LeafChase ctor");
} }
/* //Helper, find which waypoint player is closest to
* transform = t; private void determinePlayerWaypoint()
this.rb = rb; {
chaseSpeed = cSpd; List<GameObject> waypoints = (List<GameObject>)GetNodeData("waypoints");
turnSpeed = tSpd; Transform target = (Transform)GetNodeData("target");
captureDistance = capDist; if (waypoints == null || target == null)
captureTime = capTime; {
*/ return;
}
int nearestWaypointIndex = 0;
for (int i = 0; i < waypoints.Count; ++i)
{
if ((target.GlobalPosition - waypoints[i].GetComponent<Transform>().GlobalPosition).GetSqrMagnitude() <
(target.GlobalPosition - waypoints[nearestWaypointIndex].GetComponent<Transform>().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() public override BehaviourTreeNodeStatus Evaluate()
{ {
Debug.LogWarning("LeafChase"); //Debug.LogWarning("LeafChase");
onEnter(BehaviourTreeNodeStatus.RUNNING); onEnter(BehaviourTreeNodeStatus.RUNNING);
@ -79,7 +94,7 @@ public partial class LeafChase : BehaviourTreeNode
//Fail if no target in blackboard //Fail if no target in blackboard
if (GetNodeData("target") == null) if (GetNodeData("target") == null)
{ {
Debug.Log("Failure: No target in blackboard"); //Debug.Log("Failure: No target in blackboard");
return BehaviourTreeNodeStatus.FAILURE; return BehaviourTreeNodeStatus.FAILURE;
} }
Transform target = (Transform)GetNodeData("target"); Transform target = (Transform)GetNodeData("target");
@ -91,7 +106,7 @@ public partial class LeafChase : BehaviourTreeNode
//Over maximum distance, stop chase //Over maximum distance, stop chase
if ((transform.GlobalPosition - target.GlobalPosition).GetMagnitude() > 1000.0f) if ((transform.GlobalPosition - target.GlobalPosition).GetMagnitude() > 1000.0f)
{ {
Debug.Log("Failure: Over maximum distance"); //Debug.Log("Failure: Over maximum distance");
ClearNodeData("target"); ClearNodeData("target");
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true) if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true)
@ -106,7 +121,7 @@ public partial class LeafChase : BehaviourTreeNode
} }
else if (false) //TODO If collided against a wall else if (false) //TODO If collided against a wall
{ {
Debug.Log("Running: Collided against wall"); //Debug.Log("Running: Collided against wall");
SetNodeData("isPathfinding", true); SetNodeData("isPathfinding", true);
status = BehaviourTreeNodeStatus.RUNNING; status = BehaviourTreeNodeStatus.RUNNING;
@ -116,12 +131,31 @@ public partial class LeafChase : BehaviourTreeNode
//Keep chasing //Keep chasing
else if ((transform.GlobalPosition - target.GlobalPosition).GetMagnitude() > captureDistance) else if ((transform.GlobalPosition - target.GlobalPosition).GetMagnitude() > captureDistance)
{ {
Debug.Log("Running: Chasing"); //Debug.Log("Running: Chasing");
Quaternion targetRotation = Quaternion.LookRotation(normalisedDifference, new Vector3(0.0f, 1.0f, 0.0f)); Quaternion targetRotation = Quaternion.LookRotation(normalisedDifference, new Vector3(0.0f, 1.0f, 0.0f));
transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turningSpeed * 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 //TODO delete this when original intendd code above works with velocity being limited correctly
//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; rb.LinearVelocity = normalisedDifference * chaseSpeed;
}
else
{
status = BehaviourTreeNodeStatus.FAILURE;
onExit(BehaviourTreeNodeStatus.FAILURE);
return BehaviourTreeNodeStatus.FAILURE;
}
}
//Reset capture timing to base //Reset capture timing to base
SetNodeData("captureTimeLeft", baseCaptureTime); SetNodeData("captureTimeLeft", baseCaptureTime);
@ -136,7 +170,7 @@ public partial class LeafChase : BehaviourTreeNode
//Once player is close enough, perform attack //Once player is close enough, perform attack
else else
{ {
Debug.Log("Success: Near enough. Begin attack"); //Debug.Log("Success: Near enough. Begin attack");
//Look at the correct direction //Look at the correct direction
Quaternion targetRotation = Quaternion.LookRotation(normalisedDifference, new Vector3(0.0f, 1.0f, 0.0f)); Quaternion targetRotation = Quaternion.LookRotation(normalisedDifference, new Vector3(0.0f, 1.0f, 0.0f));
transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turningSpeed * Time.DeltaTimeF); transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turningSpeed * Time.DeltaTimeF);

View File

@ -25,10 +25,12 @@ public partial class LeafPatrol : BehaviourTreeNode
private List<GameObject>? waypoints; private List<GameObject>? waypoints;
private RigidBody rb; private RigidBody rb;
private float patrolSpeed; private float patrolSpeed;
private float chaseSpeed;
private float turningSpeed; private float turningSpeed;
private float retreatTimer = 0.0f; private float retreatTimer = 0.0f;
private int currentWaypointIndex = 0; private int currentWaypointIndex = 0;
private bool retreatState = false; private bool retreatState = false;
private bool goingForwards = true;
//Small delays between waypoints //Small delays between waypoints
private bool isWaiting = false; private bool isWaiting = false;
@ -51,12 +53,13 @@ public partial class LeafPatrol : BehaviourTreeNode
//le this node keep returning RUNNING as it is the last fallback node on tree //le this node keep returning RUNNING as it is the last fallback node on tree
public override BehaviourTreeNodeStatus Evaluate() public override BehaviourTreeNodeStatus Evaluate()
{ {
Debug.LogWarning("LeafPatrol"); //Debug.LogWarning("LeafPatrol");
onEnter(BehaviourTreeNodeStatus.RUNNING); onEnter(BehaviourTreeNodeStatus.RUNNING);
//Get data //Get data
if (GetNodeData("transform") == null || if (GetNodeData("transform") == null ||
GetNodeData("patrolSpeed") == null || GetNodeData("patrolSpeed") == null ||
GetNodeData("chaseSpeed") == null ||
GetNodeData("turningSpeed") == null || GetNodeData("turningSpeed") == null ||
GetNodeData("rigidBody") == null) GetNodeData("rigidBody") == null)
{ {
@ -68,6 +71,7 @@ public partial class LeafPatrol : BehaviourTreeNode
{ {
transform = (Transform)GetNodeData("transform"); transform = (Transform)GetNodeData("transform");
patrolSpeed = (float)GetNodeData("patrolSpeed"); patrolSpeed = (float)GetNodeData("patrolSpeed");
chaseSpeed = (float)GetNodeData("chaseSpeed");
turningSpeed = (float)GetNodeData("turningSpeed"); turningSpeed = (float)GetNodeData("turningSpeed");
rb = (RigidBody)GetNodeData("rigidBody"); rb = (RigidBody)GetNodeData("rigidBody");
} }
@ -87,11 +91,14 @@ public partial class LeafPatrol : BehaviourTreeNode
//Move and cycle between waypoints //Move and cycle between waypoints
private void MoveToWaypoint() private void MoveToWaypoint()
{ {
Debug.Log("MoveToWaypoint"); //Debug.Log("MoveToWaypoint");
//Waiting, do not move //Waiting, do not move
if (GetNodeData("isWaiting") != null) if (GetNodeData("isWaiting") != null)
{ {
//Only wait to change waypoints if not alert
if (GetNodeData("isAlert") != null && !(bool)GetNodeData("isAlert"))
waitCounter = 0.0f; waitCounter = 0.0f;
isWaiting = true; isWaiting = true;
ClearNodeData("isWaiting"); ClearNodeData("isWaiting");
return; return;
@ -109,15 +116,69 @@ public partial class LeafPatrol : BehaviourTreeNode
//Reached waypoint, cycle //Reached waypoint, cycle
if (remainingDistance.GetSqrMagnitude() < 0.1f) 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 //Cycle waypoints
if (goingForwards)
{
++currentWaypointIndex; ++currentWaypointIndex;
if (currentWaypointIndex >= waypoints.Count()) if (currentWaypointIndex >= waypoints.Count())
currentWaypointIndex = 0; currentWaypointIndex = 0;
}
else
{
--currentWaypointIndex;
if (currentWaypointIndex < 0)
currentWaypointIndex = waypoints.Count() - 1;
}
//Write to blackboard //Write to blackboard
SetNodeData("currentWaypointIndex", currentWaypointIndex); SetNodeData("currentWaypointIndex", currentWaypointIndex);
//Only wait to change waypoints if not alert
if (GetNodeData("isAlert") != null && !(bool)GetNodeData("isAlert"))
waitCounter = 0.0f; waitCounter = 0.0f;
isWaiting = true; isWaiting = true;
} }
else if (false /*Physics.OverlapSphere(_selfTransform.position, 0.3f, 1 << 8).Length > 0 && retreatState == false*/) else if (false /*Physics.OverlapSphere(_selfTransform.position, 0.3f, 1 << 8).Length > 0 && retreatState == false*/)
@ -159,9 +220,31 @@ public partial class LeafPatrol : BehaviourTreeNode
//TODO delete this when original intended code above works with velocity being limited correctly //TODO delete this when original intended code above works with velocity being limited correctly
if (rb != null) if (rb != null)
{ {
//Debug.Log("Null check passed?"); //Move quickly if alert
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert"))
{
//Debug.Log("Fast Patrol");
rb.LinearVelocity = normalisedDifference * chaseSpeed;
}
else
{
rb.LinearVelocity = normalisedDifference * patrolSpeed; 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) if (retreatState)
{ {
if (retreatTimer < 1.0f) retreatTimer += Time.DeltaTimeF; if (retreatTimer < 1.0f) retreatTimer += Time.DeltaTimeF;
@ -176,7 +259,6 @@ public partial class LeafPatrol : BehaviourTreeNode
private void DelayAtWaypoint() private void DelayAtWaypoint()
{ {
Debug.Log("DelayAtWaypoint");
waitCounter += Time.DeltaTimeF; waitCounter += Time.DeltaTimeF;
if (waitCounter >= waitDuration) if (waitCounter >= waitDuration)
isWaiting = false; isWaiting = false;

View File

@ -32,11 +32,11 @@ public partial class LeafSearch : BehaviourTreeNode
{ {
public LeafSearch(string name) : base(name) public LeafSearch(string name) : base(name)
{ {
Debug.Log("LeafSearch ctor"); //Debug.Log("LeafSearch ctor");
} }
//Helper, find the nearest unobstructed waypoint to return to when chase is over //Helper, find the nearest unobstructed waypoint to return to when chase is over
private void reevaluateWaypoint() public void reevaluateWaypoint()
{ {
List<GameObject> waypoints = (List<GameObject>)GetNodeData("waypoints"); List<GameObject> waypoints = (List<GameObject>)GetNodeData("waypoints");
@ -58,6 +58,8 @@ public partial class LeafSearch : BehaviourTreeNode
SetNodeData("currentWaypointIndex", nearestWaypointIndex); SetNodeData("currentWaypointIndex", nearestWaypointIndex);
} }
//Helper for handling being alert
//Helper for handling stopping of chases //Helper for handling stopping of chases
private void handleChaseStop() private void handleChaseStop()
{ {
@ -71,7 +73,7 @@ public partial class LeafSearch : BehaviourTreeNode
public override BehaviourTreeNodeStatus Evaluate() public override BehaviourTreeNodeStatus Evaluate()
{ {
Debug.LogWarning("LeafSearch"); //Debug.LogWarning("LeafSearch");
onEnter(BehaviourTreeNodeStatus.RUNNING); onEnter(BehaviourTreeNodeStatus.RUNNING);
//Get data //Get data
@ -86,7 +88,6 @@ public partial class LeafSearch : BehaviourTreeNode
else else
{ {
transform = (Transform)GetNodeData("transform"); transform = (Transform)GetNodeData("transform");
Debug.Log("Transform position: " + transform.GlobalPosition.x + " " + transform.GlobalPosition.y + " " + transform.GlobalPosition.z);
eyeOffset = (Vector3)GetNodeData("eyeOffset"); eyeOffset = (Vector3)GetNodeData("eyeOffset");
sightDistance = (float)GetNodeData("sightDistance"); sightDistance = (float)GetNodeData("sightDistance");
} }
@ -117,8 +118,8 @@ public partial class LeafSearch : BehaviourTreeNode
//Fail if too far from vision range //Fail if too far from vision range
if ((plrT.GlobalPosition - transform.GlobalPosition).GetMagnitude() > sightDistance) if ((plrT.GlobalPosition - transform.GlobalPosition).GetMagnitude() > sightDistance)
{ {
Debug.Log("Failure: Too far"); //Debug.Log("Failure: Too far");
handleChaseStop(); //handleChaseStop();
status = BehaviourTreeNodeStatus.FAILURE; status = BehaviourTreeNodeStatus.FAILURE;
onExit(BehaviourTreeNodeStatus.FAILURE); onExit(BehaviourTreeNodeStatus.FAILURE);
return status; return status;
@ -132,8 +133,8 @@ public partial class LeafSearch : BehaviourTreeNode
//Debug.Log("Dot: " + Vector3.Dot(difference, lookDirection)); //Debug.Log("Dot: " + Vector3.Dot(difference, lookDirection));
if (Vector3.Dot(difference, lookDirection) < 0.0f) if (Vector3.Dot(difference, lookDirection) < 0.0f)
{ {
Debug.Log("Failure: Out of FOV"); //Debug.Log("Failure: Out of FOV");
handleChaseStop(); //handleChaseStop();
status = BehaviourTreeNodeStatus.FAILURE; status = BehaviourTreeNodeStatus.FAILURE;
onExit(BehaviourTreeNodeStatus.FAILURE); onExit(BehaviourTreeNodeStatus.FAILURE);
return status; return status;
@ -146,34 +147,54 @@ public partial class LeafSearch : BehaviourTreeNode
//Draw a ray, succeed if ray is unobstructed //Draw a ray, succeed if ray is unobstructed
Vector3 eyePosition = transform.GlobalPosition + eyeOffset; Vector3 eyePosition = transform.GlobalPosition + eyeOffset;
Ray sightRay = new Ray(eyePosition, plrT.GlobalPosition - eyePosition); BoxCollider playerCollider = player.GetValueOrDefault().GetComponent<Collider>().GetCollisionShape<BoxCollider>(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); RaycastHit sightRayHit = Physics.Raycast(sightRay);
//As of November 2022, RaycastHit contains only the FIRST object hit by //As of November 2022, RaycastHit contains only the FIRST object hit by
//the ray in the Other GameObject data member //the ray in the Other GameObject data member
//Diren may likely add ALL objects hit by the ray over December //Diren may likely add ALL objects hit by the ray over December
if (sightRayHit.Hit && sightRayHit.Other != player) if (sightRayHit.Hit && sightRayHit.Other != player)
{ {
Debug.Log("Failure: Ray hit obstacle named " + sightRayHit.Other.GetValueOrDefault().Name + " ID" + sightRayHit.Other.GetValueOrDefault().EntityId); //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???
handleChaseStop(); //Debug.Log("Failure: Ray hit obstacle named " + sightRayHit.Other.GetValueOrDefault().Name + " ID" + sightRayHit.Other.GetValueOrDefault().EntityId);
//handleChaseStop();
status = BehaviourTreeNodeStatus.FAILURE; status = BehaviourTreeNodeStatus.FAILURE;
onExit(BehaviourTreeNodeStatus.FAILURE); onExit(BehaviourTreeNodeStatus.FAILURE);
return status; return status;
} }
else if (sightRayHit.Hit && sightRayHit.Other == player) else if (sightRayHit.Hit && sightRayHit.Other == player)
{ {
Debug.Log("Ray hit player"); //Debug.Log("Ray hit player");
} }
//All checks for now succeeded //All checks for now succeeded
Debug.Log("Success: Homeowner has sighted player"); //Debug.Log("Success: Homeowner has sighted player");
//Write player's transform into the blackboard //Write player's transform into the blackboard
SetNodeData("target", plrT); SetNodeData("target", plrT);
if (GetNodeData("isAlert") == null)
{
SetNodeData("isAlert", true);
Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_detect_raccoon");
}
else
{
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == false) if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == false)
{ {
Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_detect_raccoon"); Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_detect_raccoon");
} }
SetNodeData("isAlert", true); SetNodeData("isAlert", true);
}
status = BehaviourTreeNodeStatus.SUCCESS; status = BehaviourTreeNodeStatus.SUCCESS;
onExit(BehaviourTreeNodeStatus.SUCCESS); onExit(BehaviourTreeNodeStatus.SUCCESS);