SHADE_Y3/Assets/Scripts/AIBehaviour/Implemented/LeafNodes/LeafSearch.cs

174 lines
6.4 KiB
C#

/*********************************************************************
* \file LeafSearch.cs
* \author Ryan Wang Nian Jing
* \brief Leaf node implementation for AI searching for 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.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
//VARIABLES HERE
public partial class LeafSearch : BehaviourTreeNode
{
private Transform transform;
private Vector3 eyeOffset;
private float sightDistance;
private GameObject? player; //To be searched for and marked
}
//FUNCTIONS HERE
public partial class LeafSearch : BehaviourTreeNode
{
public LeafSearch(string name, Transform t, Vector3 eo, float sDist) : base(name)
{
transform = t;
eyeOffset = eo;
sightDistance = sDist;
player = null;
}
//Helper, find the nearest unobstructed waypoint to return to when chase is over
private void reevaluateWaypoint()
{
Debug.Log("Reevaluating Waypoints");
List<GameObject> waypoints = (List<GameObject>)GetNodeData("waypoints");
if (waypoints == 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()
{
//Debug.LogWarning("LeafSearch");
onEnter(BehaviourTreeNodeStatus.RUNNING);
//Search for player
player = GameObject.Find("Player");
//Automatically fail if no player is found
if (player == null)
{
SetNodeData("isAlert", false);
status = BehaviourTreeNodeStatus.FAILURE;
onExit(BehaviourTreeNodeStatus.FAILURE);
return status;
}
else
{
//Fail if unable to find a player
//Get player's transform
Transform plrT = player.GetValueOrDefault().GetComponent<Transform>();
//DELETE THIS
//Debug.Log("X " + MathF.Sin(transform.LocalEulerAngles.y).ToString() + " Z " + MathF.Cos(transform.LocalEulerAngles.y).ToString());
//Debug.Log("Looking at: " + transform.LocalRotation.y.ToString() + " To player is: " + temporary.ToString());
//Debug.Log("Look difference is: " + (transform.LocalRotation.y - differenceDirection.y).ToString());
//Debug.Log("Dot: " + Quaternion.Dot(differenceDirection, transform.GlobalRotation));
//Fail if too far from vision range
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);
status = BehaviourTreeNodeStatus.FAILURE;
onExit(BehaviourTreeNodeStatus.FAILURE);
return status;
}
//Fail if player is out of FOV
//TODO currently a simple dot product against negative is done, this makes it essentially be a semicircle in front at which AI can see
Vector3 difference = plrT.GlobalPosition - transform.GlobalPosition;
difference.y = 0.0f; //Disregard Y axis
Vector3 lookDirection = new Vector3(MathF.Sin(transform.LocalEulerAngles.y), 0.0f, MathF.Cos(transform.LocalEulerAngles.y));
//Debug.Log("Dot: " + Vector3.Dot(difference, lookDirection));
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);
status = BehaviourTreeNodeStatus.FAILURE;
onExit(BehaviourTreeNodeStatus.FAILURE);
return status;
}
//LocalRotation is between -1 and 1, which are essentially the same.
//0 and -1/1 are 180 deg apart
//Quaternion differenceDirection = Quaternion.FromToRotation(Vector3.Forward, plrT.GlobalPosition - transform.GlobalPosition);
//Debug.Log("Looking at: " + transform.LocalRotation.y.ToString() + " To player is: " + differenceDirection.y.ToString());
//Draw a ray, succeed if ray is unobstructed
Vector3 eyePosition = transform.GlobalPosition + eyeOffset;
Ray sightRay = new Ray(eyePosition, plrT.GlobalPosition - 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)
{
//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);
status = BehaviourTreeNodeStatus.FAILURE;
onExit(BehaviourTreeNodeStatus.FAILURE);
return status;
}
else if (sightRayHit.Hit && sightRayHit.Other == player)
{
//Debug.Log("Ray hit player");
}
//All checks for now succeeded
//Debug.Log("Success: Homeowner has sighted player");
//Write player's transform into the blackboard
SetNodeData("target", plrT);
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == false)
{
Debug.Log("AI Play Alerted Yell here");
}
SetNodeData("isAlert", true);
status = BehaviourTreeNodeStatus.SUCCESS;
onExit(BehaviourTreeNodeStatus.SUCCESS);
return status;
}
}
}