Fixed AI C# Script for final submission #283
|
@ -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: 1, y: 1.79999995, z: 0.400000006}
|
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
|
||||||
|
|
|
@ -66,9 +66,17 @@ namespace SHADE_Scripting.AIBehaviour.BehaviourTree
|
||||||
//Getters and setters for the blackboard
|
//Getters and setters for the blackboard
|
||||||
public object GetData(string key)
|
public object GetData(string key)
|
||||||
{
|
{
|
||||||
|
//Debug.Log("Getting Data " + key);
|
||||||
object outData = null;
|
object outData = null;
|
||||||
if (blackboard.TryGetValue(key, out outData)) return outData;
|
if (blackboard.TryGetValue(key, out outData))
|
||||||
else return outData;
|
{
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Debug.LogError("Cannot retrieve data " + key);
|
||||||
|
return outData;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public void SetData(string key, object data)
|
public void SetData(string key, object data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -84,17 +84,55 @@ public partial class Homeowner1 : BehaviourTree
|
||||||
_events = new Homeowner1Events(this);
|
_events = new Homeowner1Events(this);
|
||||||
events.Initialise();
|
events.Initialise();
|
||||||
|
|
||||||
//Initialise the waypoints here
|
//(25 Nov) DO NOT Initialise the data here
|
||||||
if (waypointsPool)
|
/*if (waypointsPool)
|
||||||
{
|
{
|
||||||
waypoints = (List<GameObject>)waypointsPool.GetChildren();
|
waypoints = (List<GameObject>)waypointsPool.GetChildren();
|
||||||
SetData("waypoints", waypoints);
|
SetData("waypoints", waypoints);
|
||||||
}
|
}
|
||||||
|
SetData("transform", GetComponent<Transform>());
|
||||||
|
SetData("rigidBody", GetComponent<RigidBody>());
|
||||||
|
SetData("eyeOffset", eyeOffset);
|
||||||
|
SetData("sightDistance", sightDistance);
|
||||||
|
SetData("patrolSpeed", patrolSpeed);
|
||||||
|
SetData("chaseSpeed", chaseSpeed);
|
||||||
|
SetData("turningSpeed", turningSpeed);
|
||||||
|
SetData("distanceToCapture", distanceToCapture);
|
||||||
|
SetData("baseCaptureTime", captureTime);*/
|
||||||
}
|
}
|
||||||
|
|
||||||
//Called every tick
|
//Called every tick
|
||||||
protected override void Tick()
|
protected override void Tick()
|
||||||
{
|
{
|
||||||
|
//Debug.Log("Ticking");
|
||||||
|
//Update data
|
||||||
|
if (GetData("waypoints") == null)
|
||||||
|
{
|
||||||
|
if (waypointsPool != GameObject.Null)
|
||||||
|
SetData("waypoints", (List<GameObject>)waypointsPool.GetChildren());
|
||||||
|
else
|
||||||
|
Debug.LogError("No waypoints, no AI");
|
||||||
|
}
|
||||||
|
if (GetData("transform") == null)
|
||||||
|
SetData("transform", GetComponent<Transform>());
|
||||||
|
if (GetData("rigidBody") == null)
|
||||||
|
SetData("rigidBody", GetComponent<RigidBody>());
|
||||||
|
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();
|
events.Tick();
|
||||||
|
|
||||||
//Footsteps SFX, move them somewhere else soon
|
//Footsteps SFX, move them somewhere else soon
|
||||||
|
@ -103,9 +141,10 @@ public partial class Homeowner1 : BehaviourTree
|
||||||
footstepTimeRemaining -= velocity * Time.DeltaTimeF;
|
footstepTimeRemaining -= velocity * Time.DeltaTimeF;
|
||||||
if (footstepTimeRemaining < 0.0f)
|
if (footstepTimeRemaining < 0.0f)
|
||||||
{
|
{
|
||||||
Debug.Log("AI Play Footstep SFX");
|
Audio.PlaySFXOnce2D("event:/Homeowner/homeowner_footsteps");
|
||||||
footstepTimeRemaining = footstepSFXIntervalMultiplier;
|
footstepTimeRemaining = footstepSFXIntervalMultiplier;
|
||||||
}
|
}
|
||||||
|
//Debug.Log("Ticked");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Define the behaviour tree here
|
//Define the behaviour tree here
|
||||||
|
@ -113,20 +152,22 @@ 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");
|
||||||
//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>
|
||||||
{
|
{
|
||||||
new BehaviourTreeSequence("Alerted", new List<BehaviourTreeNode>
|
new BehaviourTreeSequence("Alerted", new List<BehaviourTreeNode>
|
||||||
{
|
{
|
||||||
new LeafSearch("SearchFOV", GetComponent<Transform>(), eyeOffset, sightDistance),
|
new LeafSearch("SearchFOV"),
|
||||||
new BehaviourTreeSequence("CatchPlayer", new List<BehaviourTreeNode>
|
new BehaviourTreeSequence("CatchPlayer", new List<BehaviourTreeNode>
|
||||||
{
|
{
|
||||||
new LeafChase("Chasing", GetComponent<Transform>(), GetComponent<RigidBody>(), chaseSpeed, turningSpeed, distanceToCapture, captureTime),
|
new LeafChase("Chasing"),
|
||||||
new LeafAttack("Attacking", GameObject.Find("Player").GetValueOrDefault())
|
new LeafAttack("Attacking")
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
new LeafPatrol("Patrol", GetComponent<Transform>(), patrolSpeed, turningSpeed, GetComponent<RigidBody>())
|
new LeafPatrol("Patrol")
|
||||||
});
|
});
|
||||||
|
//Debug.Log("Tree Created");
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,16 +21,40 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FUNCTIONS
|
//FUNCTIONS
|
||||||
public partial class LeafAttack : BehaviourTreeNode
|
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<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()
|
||||||
|
@ -40,20 +64,36 @@ public partial class LeafAttack : BehaviourTreeNode
|
||||||
|
|
||||||
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
|
||||||
//Succeed when stand in hurt box for long enough
|
//Get Data
|
||||||
object timeObj = GetNodeData("captureTimeLeft");
|
float? captureTime;
|
||||||
if (timeObj == null)
|
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;
|
captureTime -= Time.DeltaTimeF;
|
||||||
SetNodeData("captureTimeLeft", captureTime);
|
SetNodeData("captureTimeLeft", captureTime);
|
||||||
//Debug.Log(captureTime.ToString());
|
//Debug.Log(captureTime.ToString());
|
||||||
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);
|
||||||
|
@ -61,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;
|
||||||
|
|
|
@ -24,9 +24,9 @@ public partial class LeafChase : BehaviourTreeNode
|
||||||
private Transform transform;
|
private Transform transform;
|
||||||
private RigidBody rb;
|
private RigidBody rb;
|
||||||
private float chaseSpeed;
|
private float chaseSpeed;
|
||||||
private float turnSpeed;
|
private float turningSpeed;
|
||||||
private float captureDistance;
|
private float captureDistance;
|
||||||
private float captureTime;
|
private float baseCaptureTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
//FUNCTIONS
|
//FUNCTIONS
|
||||||
|
@ -34,29 +34,69 @@ public partial class LeafChase : BehaviourTreeNode
|
||||||
{
|
{
|
||||||
//Despite inheriting from BehaviourTreeNode, we don't have children to this node,
|
//Despite inheriting from BehaviourTreeNode, we don't have children to this node,
|
||||||
//and hence we don't need to inherit its constructors
|
//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;
|
//Debug.Log("LeafChase ctor");
|
||||||
this.rb = rb;
|
}
|
||||||
chaseSpeed = cSpd;
|
|
||||||
turnSpeed = tSpd;
|
//Helper, find which waypoint player is closest to
|
||||||
captureDistance = capDist;
|
private void determinePlayerWaypoint()
|
||||||
captureTime = capTime;
|
{
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override BehaviourTreeNodeStatus Evaluate()
|
public override BehaviourTreeNodeStatus Evaluate()
|
||||||
{
|
{
|
||||||
//Debug.LogWarning("LeafChase");
|
//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
|
//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;
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
|
||||||
|
|
||||||
Transform target = (Transform)GetNodeData("target");
|
Transform target = (Transform)GetNodeData("target");
|
||||||
|
|
||||||
Vector3 normalisedDifference = target.GlobalPosition - transform.GlobalPosition;
|
Vector3 normalisedDifference = target.GlobalPosition - transform.GlobalPosition;
|
||||||
|
@ -71,7 +111,7 @@ public partial class LeafChase : BehaviourTreeNode
|
||||||
|
|
||||||
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true)
|
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true)
|
||||||
{
|
{
|
||||||
Debug.Log("AI play unalert hmm");
|
Audio.PlaySFXOnce2D("event:/Homeowner/humming");
|
||||||
}
|
}
|
||||||
SetNodeData("isAlert", false);
|
SetNodeData("isAlert", false);
|
||||||
|
|
||||||
|
@ -93,13 +133,32 @@ public partial class LeafChase : BehaviourTreeNode
|
||||||
{
|
{
|
||||||
//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, 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
|
//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
|
//Reset capture timing to base
|
||||||
SetNodeData("captureTimeLeft", captureTime);
|
SetNodeData("captureTimeLeft", baseCaptureTime);
|
||||||
|
|
||||||
//Not capturing, don't play SFX
|
//Not capturing, don't play SFX
|
||||||
SetNodeData("isCapturing", false);
|
SetNodeData("isCapturing", false);
|
||||||
|
@ -114,12 +173,12 @@ public partial class LeafChase : BehaviourTreeNode
|
||||||
//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, turnSpeed * Time.DeltaTimeF);
|
transform.LocalRotation = Quaternion.Slerp(transform.LocalRotation, targetRotation, turningSpeed * Time.DeltaTimeF);
|
||||||
|
|
||||||
//Play SFX
|
//Play SFX
|
||||||
if (GetNodeData("isCapturing") != null && (bool)GetNodeData("isCapturing") == false)
|
if (GetNodeData("isCapturing") != null && (bool)GetNodeData("isCapturing") == false)
|
||||||
{
|
{
|
||||||
Debug.Log("AI Play capturing SFX");
|
//Debug.Log("AI Play capturing SFX");
|
||||||
}
|
}
|
||||||
SetNodeData("isCapturing", true);
|
SetNodeData("isCapturing", true);
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,15 @@ public partial class LeafPatrol : BehaviourTreeNode
|
||||||
{
|
{
|
||||||
//Waypoints and movement
|
//Waypoints and movement
|
||||||
private Transform transform;
|
private Transform transform;
|
||||||
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;
|
||||||
|
@ -42,13 +44,8 @@ public partial class LeafPatrol : BehaviourTreeNode
|
||||||
//Constructor, establish values here
|
//Constructor, establish values here
|
||||||
//Despite inheriting from BehaviourTreeNode, we don't have children to this
|
//Despite inheriting from BehaviourTreeNode, we don't have children to this
|
||||||
//node, and hence we do not need to inherit its constructors
|
//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;
|
currentWaypointIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +55,28 @@ public partial class LeafPatrol : BehaviourTreeNode
|
||||||
{
|
{
|
||||||
//Debug.LogWarning("LeafPatrol");
|
//Debug.LogWarning("LeafPatrol");
|
||||||
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
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);
|
SetNodeData("currentWaypointIndex", 0);
|
||||||
}
|
}
|
||||||
|
@ -77,38 +95,90 @@ public partial class LeafPatrol : BehaviourTreeNode
|
||||||
//Waiting, do not move
|
//Waiting, do not move
|
||||||
if (GetNodeData("isWaiting") != null)
|
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;
|
isWaiting = true;
|
||||||
ClearNodeData("isWaiting");
|
ClearNodeData("isWaiting");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
waypoints = (List<GameObject>)GetNodeData("waypoints");
|
||||||
object waypoint = GetNodeData("waypoints");
|
if (waypoints == null)
|
||||||
if (waypoint == null)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
waypoints = (List<GameObject>)waypoint;
|
|
||||||
Vector3 targetPosition = waypoints[currentWaypointIndex].GetComponent<Transform>().GlobalPosition;
|
Vector3 targetPosition = waypoints[currentWaypointIndex].GetComponent<Transform>().GlobalPosition;
|
||||||
|
|
||||||
//Reach waypoint by X and Z being near enough
|
//Reach waypoint by X and Z being near enough
|
||||||
//Do not consider Y of waypoints yet
|
//Do not consider Y of waypoints yet
|
||||||
Vector3 remainingDistance = targetPosition - transform.GlobalPosition;
|
Vector3 remainingDistance = targetPosition - transform.GlobalPosition;
|
||||||
remainingDistance.y = 0.0f;
|
remainingDistance.y = 0.0f;
|
||||||
|
|
||||||
//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
|
||||||
++currentWaypointIndex;
|
if (goingForwards)
|
||||||
if (currentWaypointIndex >= waypoints.Count())
|
{
|
||||||
currentWaypointIndex = 0;
|
++currentWaypointIndex;
|
||||||
|
if (currentWaypointIndex >= waypoints.Count())
|
||||||
|
currentWaypointIndex = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
--currentWaypointIndex;
|
||||||
|
if (currentWaypointIndex < 0)
|
||||||
|
currentWaypointIndex = waypoints.Count() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//Write to blackboard
|
//Write to blackboard
|
||||||
SetNodeData("currentWaypointIndex", currentWaypointIndex);
|
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;
|
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*/)
|
||||||
|
@ -150,8 +220,30 @@ 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
|
||||||
rb.LinearVelocity = normalisedDifference * patrolSpeed;
|
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)
|
if (retreatState)
|
||||||
{
|
{
|
||||||
|
@ -167,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;
|
||||||
|
|
|
@ -30,18 +30,14 @@ public partial class LeafSearch : BehaviourTreeNode
|
||||||
//FUNCTIONS HERE
|
//FUNCTIONS HERE
|
||||||
public partial class LeafSearch : BehaviourTreeNode
|
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;
|
//Debug.Log("LeafSearch ctor");
|
||||||
eyeOffset = eo;
|
|
||||||
sightDistance = sDist;
|
|
||||||
player = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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()
|
||||||
{
|
{
|
||||||
Debug.Log("Reevaluating Waypoints");
|
|
||||||
List<GameObject> waypoints = (List<GameObject>)GetNodeData("waypoints");
|
List<GameObject> waypoints = (List<GameObject>)GetNodeData("waypoints");
|
||||||
|
|
||||||
if (waypoints == null)
|
if (waypoints == null)
|
||||||
|
@ -62,11 +58,40 @@ public partial class LeafSearch : BehaviourTreeNode
|
||||||
SetNodeData("currentWaypointIndex", nearestWaypointIndex);
|
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()
|
public override BehaviourTreeNodeStatus Evaluate()
|
||||||
{
|
{
|
||||||
//Debug.LogWarning("LeafSearch");
|
//Debug.LogWarning("LeafSearch");
|
||||||
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
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
|
//Search for player
|
||||||
player = GameObject.Find("Player");
|
player = GameObject.Find("Player");
|
||||||
|
|
||||||
|
@ -94,12 +119,7 @@ public partial class LeafSearch : BehaviourTreeNode
|
||||||
if ((plrT.GlobalPosition - transform.GlobalPosition).GetMagnitude() > sightDistance)
|
if ((plrT.GlobalPosition - transform.GlobalPosition).GetMagnitude() > sightDistance)
|
||||||
{
|
{
|
||||||
//Debug.Log("Failure: Too far");
|
//Debug.Log("Failure: Too far");
|
||||||
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true)
|
//handleChaseStop();
|
||||||
{
|
|
||||||
Debug.Log("AI play unalert hmm");
|
|
||||||
reevaluateWaypoint();
|
|
||||||
}
|
|
||||||
SetNodeData("isAlert", false);
|
|
||||||
status = BehaviourTreeNodeStatus.FAILURE;
|
status = BehaviourTreeNodeStatus.FAILURE;
|
||||||
onExit(BehaviourTreeNodeStatus.FAILURE);
|
onExit(BehaviourTreeNodeStatus.FAILURE);
|
||||||
return status;
|
return status;
|
||||||
|
@ -114,12 +134,7 @@ public partial class LeafSearch : BehaviourTreeNode
|
||||||
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");
|
||||||
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true)
|
//handleChaseStop();
|
||||||
{
|
|
||||||
Debug.Log("AI play unalert hmm");
|
|
||||||
reevaluateWaypoint();
|
|
||||||
}
|
|
||||||
SetNodeData("isAlert", false);
|
|
||||||
status = BehaviourTreeNodeStatus.FAILURE;
|
status = BehaviourTreeNodeStatus.FAILURE;
|
||||||
onExit(BehaviourTreeNodeStatus.FAILURE);
|
onExit(BehaviourTreeNodeStatus.FAILURE);
|
||||||
return status;
|
return status;
|
||||||
|
@ -132,20 +147,27 @@ 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)
|
||||||
{
|
{
|
||||||
|
//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);
|
//Debug.Log("Failure: Ray hit obstacle named " + sightRayHit.Other.GetValueOrDefault().Name + " ID" + sightRayHit.Other.GetValueOrDefault().EntityId);
|
||||||
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true)
|
//handleChaseStop();
|
||||||
{
|
|
||||||
Debug.Log("AI play unalert hmm");
|
|
||||||
reevaluateWaypoint();
|
|
||||||
}
|
|
||||||
SetNodeData("isAlert", false);
|
|
||||||
status = BehaviourTreeNodeStatus.FAILURE;
|
status = BehaviourTreeNodeStatus.FAILURE;
|
||||||
onExit(BehaviourTreeNodeStatus.FAILURE);
|
onExit(BehaviourTreeNodeStatus.FAILURE);
|
||||||
return status;
|
return status;
|
||||||
|
@ -160,11 +182,19 @@ public partial class LeafSearch : BehaviourTreeNode
|
||||||
//Write player's transform into the blackboard
|
//Write player's transform into the blackboard
|
||||||
SetNodeData("target", plrT);
|
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;
|
status = BehaviourTreeNodeStatus.SUCCESS;
|
||||||
onExit(BehaviourTreeNodeStatus.SUCCESS);
|
onExit(BehaviourTreeNodeStatus.SUCCESS);
|
||||||
|
|
Loading…
Reference in New Issue