adding ai fixes in #268
|
@ -8633,3 +8633,62 @@
|
||||||
Scale: {x: 1, y: 1, z: 1}
|
Scale: {x: 1, y: 1, z: 1}
|
||||||
IsActive: true
|
IsActive: true
|
||||||
Scripts: ~
|
Scripts: ~
|
||||||
|
- EID: 196
|
||||||
|
Name: ====AI=====
|
||||||
|
IsActive: true
|
||||||
|
NumberOfChildren: 0
|
||||||
|
Components:
|
||||||
|
Transform Component:
|
||||||
|
Translate: {x: 2.70000005, y: 0.100000001, z: -2}
|
||||||
|
Rotate: {x: -0, y: 0, z: -0}
|
||||||
|
Scale: {x: 1, y: 1, z: 1}
|
||||||
|
IsActive: true
|
||||||
|
Renderable Component:
|
||||||
|
Mesh: 140697366
|
||||||
|
Material: 129495479
|
||||||
|
IsActive: true
|
||||||
|
RigidBody Component:
|
||||||
|
Type: Dynamic
|
||||||
|
Drag: 0.00999999978
|
||||||
|
Angular Drag: 0.00999999978
|
||||||
|
Use Gravity: true
|
||||||
|
Interpolate: false
|
||||||
|
Sleeping Enabled: true
|
||||||
|
Freeze Position X: false
|
||||||
|
Freeze Position Y: false
|
||||||
|
Freeze Position Z: false
|
||||||
|
Freeze Rotation X: true
|
||||||
|
Freeze Rotation Y: false
|
||||||
|
Freeze Rotation Z: true
|
||||||
|
IsActive: true
|
||||||
|
Collider Component:
|
||||||
|
Colliders:
|
||||||
|
- Is Trigger: false
|
||||||
|
Type: Box
|
||||||
|
Half Extents: {x: 1, y: 1.79999995, z: 0.400000006}
|
||||||
|
Friction: 0.400000006
|
||||||
|
Bounciness: 0
|
||||||
|
Density: 1
|
||||||
|
Position Offset: {x: 0, y: 0.899999976, z: 0}
|
||||||
|
Rotation Offset: {x: 0, y: 0, z: 0}
|
||||||
|
IsActive: true
|
||||||
|
Scripts:
|
||||||
|
- Type: Homeowner1
|
||||||
|
Enabled: true
|
||||||
|
player: 2
|
||||||
|
waypoints:
|
||||||
|
- [2.70000005, 0, -2]
|
||||||
|
- [-0.300000012, 0, -2.70000005]
|
||||||
|
- [-2, 0, -3.79999995]
|
||||||
|
- [-4, 0, -2.0999999]
|
||||||
|
- [-2.9000001, 0, 2.4000001]
|
||||||
|
- [-1, 0, 4]
|
||||||
|
- [2.70000005, 0, 4]
|
||||||
|
patrolSpeed: 1
|
||||||
|
chaseSpeed: 2
|
||||||
|
turningSpeed: 5
|
||||||
|
sightDistance: 8
|
||||||
|
eyeOffset: [0, 0, 0]
|
||||||
|
distanceToCapture: 0.5
|
||||||
|
captureTime: 0.5
|
||||||
|
footstepSFXIntervalMultiplier: 0.5
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,3 @@
|
||||||
|
Name: MainGameWithAI
|
||||||
|
ID: 96052853
|
||||||
|
Type: 5
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file BehaviourTree.cs
|
||||||
|
* \author Ryan Wang Nian Jing
|
||||||
|
* \brief Based off Kheng Ian's SC_BTTree.cs
|
||||||
|
* Abstract class to be inherited as the "core" of any entity's AI
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \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 System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Design;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SHADE_Scripting.AIBehaviour.BehaviourTree
|
||||||
|
{
|
||||||
|
public abstract partial class BehaviourTree : Script
|
||||||
|
{
|
||||||
|
//The root of the tree, it should not have any parent
|
||||||
|
private BehaviourTreeNode _root = null;
|
||||||
|
protected BehaviourTreeNode root { get => _root; set => _root = value; }
|
||||||
|
|
||||||
|
//Events of the behaviour tree
|
||||||
|
public abstract BehaviourTreeEvents events { get; }
|
||||||
|
|
||||||
|
//Dictionary containing every single node in the tree
|
||||||
|
//Key is the node's unique name
|
||||||
|
public Dictionary<string, BehaviourTreeNode> nodeDictionary = new Dictionary<string, BehaviourTreeNode>();
|
||||||
|
|
||||||
|
//When inheriting from the class, this is where you would define your tree structure
|
||||||
|
|
||||||
|
//Very important
|
||||||
|
//Override this to construct the behaviour tree of any AI
|
||||||
|
protected abstract BehaviourTreeNode CreateTree();
|
||||||
|
|
||||||
|
//awake and update functions
|
||||||
|
//the only segment in the entire AI that is dependent on the engine
|
||||||
|
|
||||||
|
private bool test = false;
|
||||||
|
|
||||||
|
protected override void awake()
|
||||||
|
{
|
||||||
|
AwakeCall();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void start()
|
||||||
|
{
|
||||||
|
_root = CreateTree();
|
||||||
|
_root.InitialiseNode(this);
|
||||||
|
Initialise();
|
||||||
|
}
|
||||||
|
protected override void update()
|
||||||
|
{
|
||||||
|
_root?.Evaluate();
|
||||||
|
Tick();
|
||||||
|
}
|
||||||
|
protected abstract void AwakeCall();
|
||||||
|
protected abstract void Initialise();
|
||||||
|
protected abstract void Tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
//BLACKBOARD SYSTEM///////////////////////////////////////////////////////////
|
||||||
|
//Shared data within the tree, implemented as a dictionary of objects
|
||||||
|
public abstract partial class BehaviourTree : Script
|
||||||
|
{
|
||||||
|
//Data to be shared among nodes
|
||||||
|
public Dictionary<string, object> blackboard = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
//Getters and setters for the blackboard
|
||||||
|
public object GetData(string key)
|
||||||
|
{
|
||||||
|
object outData = null;
|
||||||
|
if (blackboard.TryGetValue(key, out outData)) return outData;
|
||||||
|
else return outData;
|
||||||
|
}
|
||||||
|
public void SetData(string key, object data)
|
||||||
|
{
|
||||||
|
blackboard[key] = data;
|
||||||
|
}
|
||||||
|
public bool ClearData(string key)
|
||||||
|
{
|
||||||
|
if (blackboard.ContainsKey(key))
|
||||||
|
{
|
||||||
|
blackboard.Remove(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: BehaviourTree
|
||||||
|
ID: 156799455
|
||||||
|
Type: 9
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file BehaviourTreeEvents.cs
|
||||||
|
* \author Ryan Wang Nian Jing
|
||||||
|
* \brief Based off Kheng Ian's SC_BTEvents.cs
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \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 System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace SHADE_Scripting.AIBehaviour.BehaviourTree
|
||||||
|
{
|
||||||
|
public abstract class BehaviourTreeEvents
|
||||||
|
{
|
||||||
|
public BehaviourTree tree;
|
||||||
|
public BehaviourTreeEvents(BehaviourTree tree)
|
||||||
|
{
|
||||||
|
this.tree = tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Called at the start
|
||||||
|
public abstract void Initialise();
|
||||||
|
//Called at every tick
|
||||||
|
public abstract void Tick();
|
||||||
|
|
||||||
|
public void OnEnterAddListener(string name, Delegate action)
|
||||||
|
{
|
||||||
|
BehaviourTreeNode targetNode;
|
||||||
|
tree.nodeDictionary.TryGetValue(name, out targetNode);
|
||||||
|
targetNode.onEnterEvent += (EventHandler)action;
|
||||||
|
}
|
||||||
|
public void OnExitAddListener(string name, Delegate action)
|
||||||
|
{
|
||||||
|
BehaviourTreeNode targetNode;
|
||||||
|
tree.nodeDictionary.TryGetValue(name, out targetNode);
|
||||||
|
targetNode.onExitEvent += (EventHandler)action;
|
||||||
|
}
|
||||||
|
public void OnEnterRemoveListener(string name, Delegate action)
|
||||||
|
{
|
||||||
|
BehaviourTreeNode targetNode;
|
||||||
|
tree.nodeDictionary.TryGetValue(name, out targetNode);
|
||||||
|
targetNode.onEnterEvent -= (EventHandler)action;
|
||||||
|
}
|
||||||
|
public void OnExitRemoveListener(string name, Delegate action)
|
||||||
|
{
|
||||||
|
BehaviourTreeNode targetNode;
|
||||||
|
tree.nodeDictionary.TryGetValue(name, out targetNode);
|
||||||
|
targetNode.onExitEvent -= (EventHandler)action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: BehaviourTreeEvents
|
||||||
|
ID: 157306586
|
||||||
|
Type: 9
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file BehaviourTreeNode.cs
|
||||||
|
* \author Ryan Wang Nian Jing
|
||||||
|
* \brief Based off Kheng Ian's SC_BTNode.cs
|
||||||
|
* Abstract implementation of individual nodes of a behaviour tree
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \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 System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Mail;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SHADE_Scripting.AIBehaviour.BehaviourTree
|
||||||
|
{
|
||||||
|
//ENUMERATIONS FOR NODE STATUS////////////////////////////////////////////////
|
||||||
|
public enum BehaviourTreeNodeStatus
|
||||||
|
{
|
||||||
|
RUNNING, //Node has not finished evaluating, to be re-evaluated
|
||||||
|
SUCCESS, //Node has been evaluated to be a success
|
||||||
|
FAILURE //Node has been evaluated to be a failure
|
||||||
|
}
|
||||||
|
|
||||||
|
//CORE TRAVERSAL SYSTEM OF BEHAVIOUR TREE/////////////////////////////////////
|
||||||
|
public partial class BehaviourTreeNode
|
||||||
|
{
|
||||||
|
//The main tree structure that the node is in
|
||||||
|
//This needs to be specified by the root node so that it can permutate to its children
|
||||||
|
public BehaviourTree tree;
|
||||||
|
|
||||||
|
//This portion functions similar to a doubly-linked list,
|
||||||
|
//only having a list of children instead of a single reference
|
||||||
|
public BehaviourTreeNode parent;
|
||||||
|
protected List<BehaviourTreeNode> children = new List<BehaviourTreeNode>();
|
||||||
|
|
||||||
|
//Current status of the node
|
||||||
|
//Technically redundant as nodes already return their status via the
|
||||||
|
//Evaluate() function
|
||||||
|
protected BehaviourTreeNodeStatus status;
|
||||||
|
|
||||||
|
//Constructors, to be overriden by its children as needed
|
||||||
|
public BehaviourTreeNode(string name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
parent = null;
|
||||||
|
}
|
||||||
|
public BehaviourTreeNode(string name, List<BehaviourTreeNode> children)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
foreach (BehaviourTreeNode child in children)
|
||||||
|
Attach(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Attach a child node to a BT node
|
||||||
|
private void Attach(BehaviourTreeNode child)
|
||||||
|
{
|
||||||
|
child.parent = this;
|
||||||
|
children.Add(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Very important
|
||||||
|
//Must be overriden by its derived classes (control flow / leaf / decorators)
|
||||||
|
//Defines the traversal method of the node
|
||||||
|
//Called every frame via the root from the BT
|
||||||
|
public virtual BehaviourTreeNodeStatus Evaluate()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException("Missing implementation of Evaluate() function!");
|
||||||
|
}
|
||||||
|
|
||||||
|
//To attach the tree, called in the Start() tick AFTER creation of the tree
|
||||||
|
public void InitialiseNode(BehaviourTree tree)
|
||||||
|
{
|
||||||
|
this.tree = tree;
|
||||||
|
|
||||||
|
//Add itself to the tree's node dictionary
|
||||||
|
if (tree.nodeDictionary.ContainsKey(name))
|
||||||
|
throw new Exception("Node name: " + name + " is not unique! Please assign a unique name to each node!");
|
||||||
|
else
|
||||||
|
tree.nodeDictionary.Add(name, this);
|
||||||
|
|
||||||
|
//TODO initialise its events
|
||||||
|
//onEnterEvent = new
|
||||||
|
//onExitEvent = new
|
||||||
|
|
||||||
|
//Recurse InitialiseNode() in children
|
||||||
|
foreach (BehaviourTreeNode child in children)
|
||||||
|
child.InitialiseNode(tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//BLACKBOARD SYSTEM///////////////////////////////////////////////////////////
|
||||||
|
//To be able to access tree's data from any node in the tree
|
||||||
|
public partial class BehaviourTreeNode
|
||||||
|
{
|
||||||
|
//Getter and setter functions for blackboard data
|
||||||
|
public object GetNodeData(string key)
|
||||||
|
{
|
||||||
|
return tree.GetData(key);
|
||||||
|
}
|
||||||
|
public void SetNodeData(string key, object data)
|
||||||
|
{
|
||||||
|
tree.SetData(key, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Removes blackboard data of name key
|
||||||
|
public bool ClearNodeData(string key)
|
||||||
|
{
|
||||||
|
return tree.ClearData(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//EVENT/CALLBACK SYSTEM///////////////////////////////////////////////////////
|
||||||
|
public class BehaviourTreeEventArgs : System.EventArgs
|
||||||
|
{
|
||||||
|
public BehaviourTreeNodeStatus returnStatus { get; set; }
|
||||||
|
public BehaviourTreeEventArgs(BehaviourTreeNodeStatus status) { returnStatus = status; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public partial class BehaviourTreeNode
|
||||||
|
{
|
||||||
|
//Mainly used for the callback system
|
||||||
|
//"name" must be unique to each node instance
|
||||||
|
//Events must be replaced by custom engine counterpart
|
||||||
|
public string name;
|
||||||
|
public System.EventHandler onEnterEvent;
|
||||||
|
public System.EventHandler onExitEvent;
|
||||||
|
public void onEnter(BehaviourTreeNodeStatus status)
|
||||||
|
{
|
||||||
|
onEnterEvent?.Invoke(this, new BehaviourTreeEventArgs(status));
|
||||||
|
}
|
||||||
|
public void onExit(BehaviourTreeNodeStatus status)
|
||||||
|
{
|
||||||
|
onExitEvent?.Invoke(this, new BehaviourTreeEventArgs(status));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: BehaviourTreeNode
|
||||||
|
ID: 159032454
|
||||||
|
Type: 9
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file BehaviourTreeSelector.cs
|
||||||
|
* \author Ryan Wang Nian Jing
|
||||||
|
* \brief Based off Kheng Ian's SC_BTSelector.cs
|
||||||
|
* Selectors function like "OR" nodes, returning success on the
|
||||||
|
* first successful child and stopping operation
|
||||||
|
*
|
||||||
|
* \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 System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SHADE_Scripting.AIBehaviour.BehaviourTree
|
||||||
|
{
|
||||||
|
public class BehaviourTreeSelector : BehaviourTreeNode
|
||||||
|
{
|
||||||
|
public BehaviourTreeSelector(string name) : base(name) { }
|
||||||
|
public BehaviourTreeSelector(string name, List<BehaviourTreeNode> children) :
|
||||||
|
base(name, children)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public override BehaviourTreeNodeStatus Evaluate()
|
||||||
|
{
|
||||||
|
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
for (int i = 0; i < children.Count; ++i)
|
||||||
|
{
|
||||||
|
switch (children[i].Evaluate())
|
||||||
|
{
|
||||||
|
case BehaviourTreeNodeStatus.RUNNING:
|
||||||
|
status = BehaviourTreeNodeStatus.RUNNING;
|
||||||
|
onExit(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
return status;
|
||||||
|
case BehaviourTreeNodeStatus.SUCCESS:
|
||||||
|
status = BehaviourTreeNodeStatus.SUCCESS;
|
||||||
|
onExit(BehaviourTreeNodeStatus.SUCCESS);
|
||||||
|
return status;
|
||||||
|
case BehaviourTreeNodeStatus.FAILURE:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status = BehaviourTreeNodeStatus.FAILURE;
|
||||||
|
onExit(BehaviourTreeNodeStatus.FAILURE);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: BehaviourTreeSelector
|
||||||
|
ID: 167568513
|
||||||
|
Type: 9
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file BehaviourTreeSequence.cs
|
||||||
|
* \author Ryan Wang Nian Jing
|
||||||
|
* \brief Based off Kheng Ian's SC_BTSelector.cs
|
||||||
|
* Sequences function like "AND" nodes, having to process every child
|
||||||
|
* successfully to return a success. Returns a failure on the first
|
||||||
|
* child that fails
|
||||||
|
*
|
||||||
|
* \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 System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SHADE_Scripting.AIBehaviour.BehaviourTree
|
||||||
|
{
|
||||||
|
public class BehaviourTreeSequence : BehaviourTreeNode
|
||||||
|
{
|
||||||
|
public BehaviourTreeSequence(string name) : base(name) { }
|
||||||
|
public BehaviourTreeSequence(string name, List<BehaviourTreeNode> children) :
|
||||||
|
base(name, children) { }
|
||||||
|
|
||||||
|
public override BehaviourTreeNodeStatus Evaluate()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
for (int i = 0; i < children.Count; ++i)
|
||||||
|
{
|
||||||
|
switch (children[i].Evaluate())
|
||||||
|
{
|
||||||
|
case BehaviourTreeNodeStatus.SUCCESS:
|
||||||
|
continue;
|
||||||
|
case BehaviourTreeNodeStatus.RUNNING:
|
||||||
|
status = BehaviourTreeNodeStatus.RUNNING;
|
||||||
|
onExit(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
return status;
|
||||||
|
case BehaviourTreeNodeStatus.FAILURE:
|
||||||
|
status = BehaviourTreeNodeStatus.FAILURE;
|
||||||
|
onExit(BehaviourTreeNodeStatus.FAILURE);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
status = BehaviourTreeNodeStatus.SUCCESS;
|
||||||
|
onExit(BehaviourTreeNodeStatus.SUCCESS);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: BehaviourTreeSequence
|
||||||
|
ID: 154302585
|
||||||
|
Type: 9
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file Homeowner1.cs
|
||||||
|
* \author Ryan Wang Nian Jing
|
||||||
|
* \brief The implemented behaviour tree for the homeowner
|
||||||
|
* A prototype to prove that behaviour trees can be worked and expanded
|
||||||
|
* on in the custom engine for GAM300 Milestone 3 and expanded over
|
||||||
|
* GAM350
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \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 required for the AI to function
|
||||||
|
//To be attached to the game object via the inspector
|
||||||
|
public partial class Homeowner1 : BehaviourTree
|
||||||
|
{
|
||||||
|
private BehaviourTreeEvents _events { get; set; }
|
||||||
|
public override BehaviourTreeEvents events { get => _events; }
|
||||||
|
|
||||||
|
[Tooltip("The player the AI should chase and attempt to capture")]
|
||||||
|
public GameObject player;
|
||||||
|
|
||||||
|
//PATROL FIELDS///////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("The list of waypoints for the AI to cycle around")]
|
||||||
|
private List<Vector3> waypoints = new List<Vector3>();
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("The AI will patrol at this speed")]
|
||||||
|
private float patrolSpeed;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("The speed at which the AI will chase the player if sighted")]
|
||||||
|
private float chaseSpeed;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("Turning speed multiplier of the AI. 10 is good")]
|
||||||
|
private float turningSpeed;
|
||||||
|
|
||||||
|
//FIELD OF VISION/////////////////////////////////////////////////////////////
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("How far the AI can see up to")]
|
||||||
|
private float sightDistance;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("How far the eyes are offset from the AI's actual position")]
|
||||||
|
private Vector3 eyeOffset;
|
||||||
|
|
||||||
|
//ATTACKING///////////////////////////////////////////////////////////////////
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("How near the player mut be to the AI for capture")]
|
||||||
|
private float distanceToCapture;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("How long the player should be in the attack range for successful capture")]
|
||||||
|
private float captureTime;
|
||||||
|
|
||||||
|
|
||||||
|
//There's definitely a better way to do this
|
||||||
|
[SerializeField]
|
||||||
|
[Tooltip("TO BE REMOVED IN 350. Interval multiplier between footsteps")]
|
||||||
|
private float footstepSFXIntervalMultiplier;
|
||||||
|
|
||||||
|
private float footstepTimeRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
//AI tree
|
||||||
|
public partial class Homeowner1 : BehaviourTree
|
||||||
|
{
|
||||||
|
Transform _thisTransform = null;
|
||||||
|
RigidBody _thisRigidbody = null;
|
||||||
|
GameObject _playerObject;
|
||||||
|
private LeafPatrol leafPatrol;
|
||||||
|
|
||||||
|
protected override void AwakeCall()
|
||||||
|
{
|
||||||
|
_thisTransform = GetComponent<Transform>();
|
||||||
|
if (!_thisTransform)
|
||||||
|
Debug.LogError("EMPTY TRANSFORM");
|
||||||
|
|
||||||
|
_thisRigidbody = GetComponent<RigidBody>();
|
||||||
|
if (!_thisRigidbody)
|
||||||
|
Debug.LogError("EMPTY RIGIDBODY");
|
||||||
|
|
||||||
|
if (!player)
|
||||||
|
Debug.Log("PLAYER MISSING!");
|
||||||
|
|
||||||
|
//_playerObject = GameObject.Find("Player").GetValueOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Called at the start
|
||||||
|
protected override void Initialise()
|
||||||
|
{
|
||||||
|
_events = new Homeowner1Events(this);
|
||||||
|
events.Initialise();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Called every tick
|
||||||
|
protected override void Tick()
|
||||||
|
{
|
||||||
|
events.Tick();
|
||||||
|
|
||||||
|
float velocity = GetComponent<RigidBody>().LinearVelocity.GetMagnitude();
|
||||||
|
leafPatrol.waypoints = waypoints;
|
||||||
|
|
||||||
|
footstepTimeRemaining -= velocity * Time.DeltaTimeF;
|
||||||
|
if (footstepTimeRemaining < 0.0f)
|
||||||
|
{
|
||||||
|
Debug.Log("AI Play Footstep SFX");
|
||||||
|
footstepTimeRemaining = footstepSFXIntervalMultiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Define the behaviour tree here
|
||||||
|
//Order of which nodes are created affects order of execution
|
||||||
|
//The tree is called from the root every tick
|
||||||
|
protected override BehaviourTreeNode CreateTree()
|
||||||
|
{
|
||||||
|
leafPatrol = new LeafPatrol("Patrol", _thisTransform, waypoints, patrolSpeed, turningSpeed, _thisRigidbody);
|
||||||
|
//Start from the root, structure it like this to make it look like a tree
|
||||||
|
BehaviourTreeNode root = new BehaviourTreeSelector("Root", new List<BehaviourTreeNode>
|
||||||
|
{
|
||||||
|
/* new BehaviourTreeSequence("Alerted", new List<BehaviourTreeNode>
|
||||||
|
{
|
||||||
|
new LeafSearch("SearchFOV", _thisTransform, eyeOffset, sightDistance),
|
||||||
|
new BehaviourTreeSequence("CatchPlayer", new List<BehaviourTreeNode>
|
||||||
|
{
|
||||||
|
new LeafChase("Chasing", _thisTransform, _thisRigidbody, chaseSpeed, turningSpeed, distanceToCapture, captureTime),
|
||||||
|
new LeafAttack("Attacking")
|
||||||
|
})
|
||||||
|
}),*/
|
||||||
|
leafPatrol
|
||||||
|
});
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: Homeowner1
|
||||||
|
ID: 159563628
|
||||||
|
Type: 9
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file Homeowner1Events.cs
|
||||||
|
* \author Ryan Wang Nian Jing
|
||||||
|
* \brief The implemented events for the homeowner
|
||||||
|
* Presently unused for GAM300
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \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_Scripting.AIBehaviour.BehaviourTree;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
public partial class Homeowner1Events : BehaviourTreeEvents
|
||||||
|
{
|
||||||
|
public Homeowner1Events(BehaviourTree tree) : base(tree) { }
|
||||||
|
|
||||||
|
//Called at the start
|
||||||
|
public override void Initialise()
|
||||||
|
{
|
||||||
|
//Tree.GetNode("Search FOV").onExitEvent += (s, e) => { PlayScreamSFX(s, e); };
|
||||||
|
}
|
||||||
|
|
||||||
|
//Called at every tick
|
||||||
|
public override void Tick()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: Homeowner1Events
|
||||||
|
ID: 156914017
|
||||||
|
Type: 9
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file LeafAttack.cs
|
||||||
|
* \author Ryan Wang Nian Jing
|
||||||
|
* \brief Leaf node implementation for AI attacking the player
|
||||||
|
* when the AI is close enough after chasing
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \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 LeafAttack : BehaviourTreeNode
|
||||||
|
{
|
||||||
|
//Holds the player game object
|
||||||
|
private GameObject player;
|
||||||
|
}
|
||||||
|
|
||||||
|
//FUNCTIONS
|
||||||
|
public partial class LeafAttack : BehaviourTreeNode
|
||||||
|
{
|
||||||
|
public LeafAttack(string name) : base (name)
|
||||||
|
{
|
||||||
|
//player = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BehaviourTreeNodeStatus Evaluate()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
if (!player)
|
||||||
|
{
|
||||||
|
player = GameObject.Find("Player").GetValueOrDefault();
|
||||||
|
Debug.Log("HERE2");
|
||||||
|
if (!player) { return BehaviourTreeNodeStatus.FAILURE; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Debug.LogWarning("LeafAttack");
|
||||||
|
//Fail if no target in blackboard?
|
||||||
|
|
||||||
|
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
|
||||||
|
//Succeed when stand in hurt box for long enough
|
||||||
|
float captureTime = (float)GetNodeData("captureTimeLeft");
|
||||||
|
captureTime -= Time.DeltaTimeF;
|
||||||
|
SetNodeData("captureTimeLeft", captureTime);
|
||||||
|
//Debug.Log(captureTime.ToString());
|
||||||
|
if (captureTime <= 0.0f)
|
||||||
|
{
|
||||||
|
//Catch player when in range for long enough
|
||||||
|
player.GetScript<PlayerController>().currentState = PlayerController.RaccoonStates.CAUGHT;
|
||||||
|
status = BehaviourTreeNodeStatus.SUCCESS;
|
||||||
|
onExit(BehaviourTreeNodeStatus.SUCCESS);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return running if not success
|
||||||
|
|
||||||
|
//Debug.Log("Success: Caught");
|
||||||
|
status = BehaviourTreeNodeStatus.RUNNING;
|
||||||
|
onExit(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: LeafAttack
|
||||||
|
ID: 162827155
|
||||||
|
Type: 9
|
|
@ -0,0 +1,135 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \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;
|
||||||
|
private float turnSpeed;
|
||||||
|
private float captureDistance;
|
||||||
|
private float captureTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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
|
||||||
|
public LeafChase(string name, Transform t, RigidBody rb, float cSpd, float tSpd, float capDist, float capTime) : base (name)
|
||||||
|
{
|
||||||
|
transform = t;
|
||||||
|
this.rb = rb;
|
||||||
|
chaseSpeed = cSpd;
|
||||||
|
turnSpeed = tSpd;
|
||||||
|
captureDistance = capDist;
|
||||||
|
captureTime = capTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BehaviourTreeNodeStatus Evaluate()
|
||||||
|
{
|
||||||
|
//Debug.LogWarning("LeafChase");
|
||||||
|
|
||||||
|
//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;
|
||||||
|
normalisedDifference.y = 0.0f; //Do not consider Y
|
||||||
|
normalisedDifference /= normalisedDifference.GetMagnitude();
|
||||||
|
|
||||||
|
//Over maximum distance, stop chase
|
||||||
|
if ((transform.GlobalPosition - target.GlobalPosition).GetMagnitude() > 1000.0f)
|
||||||
|
{
|
||||||
|
//Debug.Log("Failure: Over maximum distance");
|
||||||
|
ClearNodeData("target");
|
||||||
|
|
||||||
|
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true)
|
||||||
|
{
|
||||||
|
Debug.Log("AI play unalert hmm");
|
||||||
|
}
|
||||||
|
SetNodeData("isAlert", false);
|
||||||
|
|
||||||
|
status = BehaviourTreeNodeStatus.FAILURE;
|
||||||
|
onExit(BehaviourTreeNodeStatus.FAILURE);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
else if (false) //TODO If collided against a wall
|
||||||
|
{
|
||||||
|
//Debug.Log("Running: Collided against wall");
|
||||||
|
SetNodeData("isPathfinding", true);
|
||||||
|
|
||||||
|
status = BehaviourTreeNodeStatus.RUNNING;
|
||||||
|
onExit(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
return BehaviourTreeNodeStatus.RUNNING;
|
||||||
|
}
|
||||||
|
//Keep chasing
|
||||||
|
else if ((transform.GlobalPosition - target.GlobalPosition).GetMagnitude() > captureDistance)
|
||||||
|
{
|
||||||
|
//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);
|
||||||
|
|
||||||
|
//TODO delete this when original intendd code above works with velocity being limited correctly
|
||||||
|
rb.LinearVelocity = normalisedDifference * chaseSpeed;
|
||||||
|
|
||||||
|
//Reset capture timing to base
|
||||||
|
SetNodeData("captureTimeLeft", captureTime);
|
||||||
|
|
||||||
|
//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
|
||||||
|
{
|
||||||
|
//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);
|
||||||
|
|
||||||
|
//Play SFX
|
||||||
|
if (GetNodeData("isCapturing") != null && (bool)GetNodeData("isCapturing") == false)
|
||||||
|
{
|
||||||
|
Debug.Log("AI Play capturing SFX");
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: LeafChase
|
||||||
|
ID: 151301333
|
||||||
|
Type: 9
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \file LeafPatrol.cs
|
||||||
|
* \author Ryan Wang Nian Jing
|
||||||
|
* \brief Leaf node implementation for patrolling AI
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* \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 HERE
|
||||||
|
public partial class LeafPatrol : BehaviourTreeNode
|
||||||
|
{
|
||||||
|
//Waypoints and movement
|
||||||
|
private Transform transform;
|
||||||
|
public List<Vector3> waypoints;
|
||||||
|
private RigidBody rb;
|
||||||
|
private float patrolSpeed = 1.0f;
|
||||||
|
private float turningSpeed = 5.0f;
|
||||||
|
private float retreatTimer = 0.0f;
|
||||||
|
private int currentWaypointIndex = 0;
|
||||||
|
private bool retreatState = false;
|
||||||
|
|
||||||
|
//Small delays between waypoints
|
||||||
|
private bool isWaiting = false;
|
||||||
|
private const float waitDuration = 2.0f;
|
||||||
|
private float waitCounter = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//FUNCTIONS HERE
|
||||||
|
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, List<Vector3> wps, float patrolSpeed, float turnSpeed, RigidBody rb) : base(name)
|
||||||
|
{
|
||||||
|
transform = t;
|
||||||
|
waypoints = wps;
|
||||||
|
this.patrolSpeed = patrolSpeed;
|
||||||
|
turningSpeed = turnSpeed;
|
||||||
|
this.rb = rb;
|
||||||
|
|
||||||
|
currentWaypointIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//When it comes to evaluating,
|
||||||
|
//le this node keep returning RUNNING as it is the last fallback node on tree
|
||||||
|
public override BehaviourTreeNodeStatus Evaluate()
|
||||||
|
{
|
||||||
|
//Debug.LogWarning("LeafPatrol");
|
||||||
|
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
if (isWaiting) DelayAtWaypoint();
|
||||||
|
else MoveToWaypoint();
|
||||||
|
|
||||||
|
status = BehaviourTreeNodeStatus.RUNNING;
|
||||||
|
onExit(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Move and cycle between waypoints
|
||||||
|
private void MoveToWaypoint()
|
||||||
|
{
|
||||||
|
//Debug.Log("MoveToWaypoint");
|
||||||
|
//Waiting, do not move
|
||||||
|
if (GetNodeData("isWaiting") != null)
|
||||||
|
{
|
||||||
|
waitCounter = 0.0f;
|
||||||
|
isWaiting = true;
|
||||||
|
ClearNodeData("isWaiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3 remainingDistance = Vector3.Zero;
|
||||||
|
Debug.Log($"{waypoints.Count}");
|
||||||
|
if (currentWaypointIndex > 0)
|
||||||
|
{
|
||||||
|
|
||||||
|
Vector3 targetPosition = waypoints[currentWaypointIndex];
|
||||||
|
|
||||||
|
//Reach waypoint by X and Z being near enough
|
||||||
|
//Do not consider Y of waypoints yet
|
||||||
|
remainingDistance = targetPosition - transform.GlobalPosition;
|
||||||
|
remainingDistance.y = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Reached waypoint, cycle
|
||||||
|
if (remainingDistance.GetSqrMagnitude() < 0.1f)
|
||||||
|
{
|
||||||
|
//Cycle waypoints
|
||||||
|
++currentWaypointIndex;
|
||||||
|
if (currentWaypointIndex >= waypoints.Count)
|
||||||
|
currentWaypointIndex = 0;
|
||||||
|
|
||||||
|
waitCounter = 0.0f;
|
||||||
|
isWaiting = true;
|
||||||
|
}
|
||||||
|
else if (false /*Physics.OverlapSphere(_selfTransform.position, 0.3f, 1 << 8).Length > 0 && retreatState == false*/)
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
//This main segment is to check if the NPC is walking into a solid wall
|
||||||
|
//If they are, do a raycast to find the nearest unobstructed waypoint and head there instead
|
||||||
|
}
|
||||||
|
else //Proceed to waypoint as usual
|
||||||
|
{
|
||||||
|
//Get the difference vector to the waypoint
|
||||||
|
//Debug.Log("Current Waypoint " + waypoints[currentWaypointIndex].x.ToString() + " " + waypoints[currentWaypointIndex].y.ToString() + " " + waypoints[currentWaypointIndex].z.ToString());
|
||||||
|
//Debug.Log("AI is at " + transform.GlobalPosition.x.ToString() + " " + transform.GlobalPosition.y.ToString() + " " + transform.GlobalPosition.z.ToString());
|
||||||
|
Vector3 normalisedDifference = waypoints[currentWaypointIndex] - transform.GlobalPosition;
|
||||||
|
normalisedDifference.y = 0.0f; //Do not move vertically
|
||||||
|
normalisedDifference /= normalisedDifference.GetMagnitude();
|
||||||
|
//Debug.Log("Normalised Difference x " + normalisedDifference.x.ToString() + " z " + normalisedDifference.z.ToString());
|
||||||
|
|
||||||
|
//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, turningSpeed * Time.DeltaTimeF);
|
||||||
|
|
||||||
|
//transform.GlobalPosition += normalisedDifference * moveSpeed * (float)Time.DeltaTime;
|
||||||
|
//rb.LinearVelocity = normalisedDifference * patrolSpeed;
|
||||||
|
|
||||||
|
//ORIGINAL INTENDED CODE
|
||||||
|
/*rb.AddForce(new Vector3(normalisedDifference.x, 0.0f, normalisedDifference.z) * movementForceMultiplier);
|
||||||
|
float currentSpeed = MathF.Sqrt(rb.LinearVelocity.x * rb.LinearVelocity.x + rb.LinearVelocity.z * rb.LinearVelocity.z);
|
||||||
|
if (currentSpeed > patrolSpeed)
|
||||||
|
{
|
||||||
|
float adjustmentFactor = patrolSpeed / currentSpeed;
|
||||||
|
Vector3 adjustedVelocity = rb.LinearVelocity;
|
||||||
|
//adjustedVelocity *= adjustmentFactor;
|
||||||
|
adjustedVelocity.x = patrolSpeed;
|
||||||
|
adjustedVelocity.z = patrolSpeed;
|
||||||
|
rb.LinearVelocity = adjustedVelocity;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
if (retreatState)
|
||||||
|
{
|
||||||
|
if (retreatTimer < 1.0f) retreatTimer += Time.DeltaTimeF;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
retreatState = false;
|
||||||
|
retreatTimer = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DelayAtWaypoint()
|
||||||
|
{
|
||||||
|
//Debug.Log("DelayAtWaypoint");
|
||||||
|
waitCounter += Time.DeltaTimeF;
|
||||||
|
if (waitCounter >= waitDuration)
|
||||||
|
isWaiting = false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: LeafPatrol
|
||||||
|
ID: 160826340
|
||||||
|
Type: 9
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* \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 GameObject player;
|
||||||
|
private Transform transform;
|
||||||
|
private Vector3 eyeOffset;
|
||||||
|
private float sightDistance;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//FUNCTIONS HERE
|
||||||
|
public partial class LeafSearch : BehaviourTreeNode
|
||||||
|
{
|
||||||
|
public LeafSearch(string name, Transform t, Vector3 eo, float sDist) : base(name)
|
||||||
|
{
|
||||||
|
Debug.Log($"===============================PLAYER: {t}");
|
||||||
|
// player = p;
|
||||||
|
transform = t;
|
||||||
|
eyeOffset = eo;
|
||||||
|
sightDistance = sDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override BehaviourTreeNodeStatus Evaluate()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
if (!player)
|
||||||
|
{
|
||||||
|
player = GameObject.Find("Player").GetValueOrDefault();
|
||||||
|
if (!player) { Debug.Log("HERE1"); return BehaviourTreeNodeStatus.FAILURE; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Debug.LogWarning("LeafSearch");
|
||||||
|
onEnter(BehaviourTreeNodeStatus.RUNNING);
|
||||||
|
|
||||||
|
//Fail if unable to find a player
|
||||||
|
//Get player's transform
|
||||||
|
Transform plrT = player.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");
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Name: LeafSearch
|
||||||
|
ID: 166109634
|
||||||
|
Type: 9
|
Loading…
Reference in New Issue