2022-11-23 21:02:33 +08:00
|
|
|
|
/*********************************************************************
|
|
|
|
|
* \file LeafChase.cs
|
|
|
|
|
* \author Ryan Wang Nian Jing
|
|
|
|
|
* \brief Leaf node implementation for AI chasing the player
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* \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.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
//VARIABLES
|
|
|
|
|
public partial class LeafChase : BehaviourTreeNode
|
|
|
|
|
{
|
|
|
|
|
//Used to move entity around
|
|
|
|
|
private Transform transform;
|
|
|
|
|
private RigidBody rb;
|
|
|
|
|
private float chaseSpeed;
|
2022-11-25 16:12:58 +08:00
|
|
|
|
private float turningSpeed;
|
2022-11-23 21:02:33 +08:00
|
|
|
|
private float captureDistance;
|
2022-11-25 16:12:58 +08:00
|
|
|
|
private float baseCaptureTime;
|
2022-11-23 21:02:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//FUNCTIONS
|
|
|
|
|
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
|
2022-11-25 16:12:58 +08:00
|
|
|
|
public LeafChase(string name) : base (name)
|
2022-11-23 21:02:33 +08:00
|
|
|
|
{
|
2022-11-25 20:16:31 +08:00
|
|
|
|
//Debug.Log("LeafChase ctor");
|
2022-11-25 16:12:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-11-25 20:16:31 +08:00
|
|
|
|
//Helper, find which waypoint player is closest to
|
|
|
|
|
private void determinePlayerWaypoint()
|
|
|
|
|
{
|
|
|
|
|
List<GameObject> waypoints = (List<GameObject>)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<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);
|
|
|
|
|
}
|
2022-11-23 21:02:33 +08:00
|
|
|
|
|
|
|
|
|
public override BehaviourTreeNodeStatus Evaluate()
|
|
|
|
|
{
|
2022-11-25 20:16:31 +08:00
|
|
|
|
//Debug.LogWarning("LeafChase");
|
2022-11-25 16:12:58 +08:00
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
|
}
|
2022-11-23 21:02:33 +08:00
|
|
|
|
|
|
|
|
|
//Fail if no target in blackboard
|
|
|
|
|
if (GetNodeData("target") == null)
|
|
|
|
|
{
|
2022-11-25 20:16:31 +08:00
|
|
|
|
//Debug.Log("Failure: No target in blackboard");
|
2022-11-23 21:02:33 +08:00
|
|
|
|
return BehaviourTreeNodeStatus.FAILURE;
|
|
|
|
|
}
|
|
|
|
|
Transform target = (Transform)GetNodeData("target");
|
|
|
|
|
|
|
|
|
|
Vector3 normalisedDifference = target.GlobalPosition - transform.GlobalPosition;
|
|
|
|
|
normalisedDifference.y = 0.0f; //Do not consider Y
|
|
|
|
|
normalisedDifference /= normalisedDifference.GetMagnitude();
|
|
|
|
|
|
|
|
|
|
//Over maximum distance, stop chase
|
|
|
|
|
if ((transform.GlobalPosition - target.GlobalPosition).GetMagnitude() > 1000.0f)
|
|
|
|
|
{
|
2022-11-25 20:16:31 +08:00
|
|
|
|
//Debug.Log("Failure: Over maximum distance");
|
2022-11-23 21:02:33 +08:00
|
|
|
|
ClearNodeData("target");
|
|
|
|
|
|
|
|
|
|
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true)
|
|
|
|
|
{
|
2022-11-25 00:56:40 +08:00
|
|
|
|
Audio.PlaySFXOnce2D("event:/Homeowner/humming");
|
2022-11-23 21:02:33 +08:00
|
|
|
|
}
|
|
|
|
|
SetNodeData("isAlert", false);
|
|
|
|
|
|
|
|
|
|
status = BehaviourTreeNodeStatus.FAILURE;
|
|
|
|
|
onExit(BehaviourTreeNodeStatus.FAILURE);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
else if (false) //TODO If collided against a wall
|
|
|
|
|
{
|
2022-11-25 20:16:31 +08:00
|
|
|
|
//Debug.Log("Running: Collided against wall");
|
2022-11-23 21:02:33 +08:00
|
|
|
|
SetNodeData("isPathfinding", true);
|
|
|
|
|
|
|
|
|
|
status = BehaviourTreeNodeStatus.RUNNING;
|
|
|
|
|
onExit(BehaviourTreeNodeStatus.RUNNING);
|
|
|
|
|
return BehaviourTreeNodeStatus.RUNNING;
|
|
|
|
|
}
|
|
|
|
|
//Keep chasing
|
|
|
|
|
else if ((transform.GlobalPosition - target.GlobalPosition).GetMagnitude() > captureDistance)
|
|
|
|
|
{
|
2022-11-25 20:16:31 +08:00
|
|
|
|
//Debug.Log("Running: Chasing");
|
2022-11-23 21:02:33 +08:00
|
|
|
|
Quaternion targetRotation = Quaternion.LookRotation(normalisedDifference, new Vector3(0.0f, 1.0f, 0.0f));
|
2022-11-25 16:12:58 +08:00
|
|
|
|
transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turningSpeed * Time.DeltaTimeF);
|
2022-11-23 21:02:33 +08:00
|
|
|
|
|
2022-11-25 20:16:31 +08:00
|
|
|
|
|
|
|
|
|
//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();
|
|
|
|
|
|
2022-11-23 21:02:33 +08:00
|
|
|
|
//TODO delete this when original intendd code above works with velocity being limited correctly
|
2022-11-25 20:16:31 +08:00
|
|
|
|
//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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-23 21:02:33 +08:00
|
|
|
|
|
|
|
|
|
//Reset capture timing to base
|
2022-11-25 16:12:58 +08:00
|
|
|
|
SetNodeData("captureTimeLeft", baseCaptureTime);
|
2022-11-23 21:02:33 +08:00
|
|
|
|
|
|
|
|
|
//Not capturing, don't play SFX
|
|
|
|
|
SetNodeData("isCapturing", false);
|
|
|
|
|
|
|
|
|
|
status = BehaviourTreeNodeStatus.RUNNING;
|
|
|
|
|
onExit(BehaviourTreeNodeStatus.RUNNING);
|
|
|
|
|
return BehaviourTreeNodeStatus.RUNNING;
|
|
|
|
|
}
|
|
|
|
|
//Once player is close enough, perform attack
|
|
|
|
|
else
|
|
|
|
|
{
|
2022-11-25 20:16:31 +08:00
|
|
|
|
//Debug.Log("Success: Near enough. Begin attack");
|
2022-11-23 21:02:33 +08:00
|
|
|
|
//Look at the correct direction
|
|
|
|
|
Quaternion targetRotation = Quaternion.LookRotation(normalisedDifference, new Vector3(0.0f, 1.0f, 0.0f));
|
2022-11-25 16:12:58 +08:00
|
|
|
|
transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turningSpeed * Time.DeltaTimeF);
|
2022-11-23 21:02:33 +08:00
|
|
|
|
|
|
|
|
|
//Play SFX
|
|
|
|
|
if (GetNodeData("isCapturing") != null && (bool)GetNodeData("isCapturing") == false)
|
|
|
|
|
{
|
2022-11-25 11:44:58 +08:00
|
|
|
|
//Debug.Log("AI Play capturing SFX");
|
2022-11-23 21:02:33 +08:00
|
|
|
|
}
|
|
|
|
|
SetNodeData("isCapturing", true);
|
|
|
|
|
|
|
|
|
|
//TODO resetting the capture time once it's less than 0 doesn't work as
|
|
|
|
|
//there is quite some time (about .1 seconds) after the timer falls below 0
|
|
|
|
|
//that the capture actually happens
|
|
|
|
|
|
|
|
|
|
status = BehaviourTreeNodeStatus.SUCCESS;
|
|
|
|
|
onExit(BehaviourTreeNodeStatus.SUCCESS);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|