Added Camera Collision WIP #278

Merged
maverickdgg merged 2 commits from SP3-141-Camera-System into main 2022-11-25 11:08:11 +08:00
27 changed files with 9162 additions and 249 deletions
Showing only changes of commit f3e7f1747a - Show all commits

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
Name: MainGameWithAIFixed
ID: 89830755
Type: 5

View File

@ -40,15 +40,7 @@ namespace SHADE_Scripting.AIBehaviour.BehaviourTree
//awake and update functions //awake and update functions
//the only segment in the entire AI that is dependent on the engine //the only segment in the entire AI that is dependent on the engine
private bool test = false;
protected override void awake() protected override void awake()
{
AwakeCall();
}
protected override void start()
{ {
_root = CreateTree(); _root = CreateTree();
_root.InitialiseNode(this); _root.InitialiseNode(this);
@ -59,7 +51,7 @@ namespace SHADE_Scripting.AIBehaviour.BehaviourTree
_root?.Evaluate(); _root?.Evaluate();
Tick(); Tick();
} }
protected abstract void AwakeCall();
protected abstract void Initialise(); protected abstract void Initialise();
protected abstract void Tick(); protected abstract void Tick();
} }

View File

@ -28,14 +28,13 @@ public partial class Homeowner1 : BehaviourTree
private BehaviourTreeEvents _events { get; set; } private BehaviourTreeEvents _events { get; set; }
public override BehaviourTreeEvents events { get => _events; } public override BehaviourTreeEvents events { get => _events; }
[Tooltip("The player the AI should chase and attempt to capture")]
public GameObject player;
//PATROL FIELDS/////////////////////////////////////////////////////////////// //PATROL FIELDS///////////////////////////////////////////////////////////////
[SerializeField] [SerializeField]
[Tooltip("The list of waypoints for the AI to cycle around")] [Tooltip("The list of waypoints for the AI to cycle around")]
private List<Vector3> waypoints = new List<Vector3>(); private GameObject waypointsPool;
private List<GameObject> waypoints;
[SerializeField] [SerializeField]
[Tooltip("The AI will patrol at this speed")] [Tooltip("The AI will patrol at this speed")]
@ -79,32 +78,18 @@ public partial class Homeowner1 : BehaviourTree
//AI tree //AI tree
public partial class Homeowner1 : BehaviourTree 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 //Called at the start
protected override void Initialise() protected override void Initialise()
{ {
_events = new Homeowner1Events(this); _events = new Homeowner1Events(this);
events.Initialise(); events.Initialise();
//Initialise the waypoints here
if (waypointsPool)
{
waypoints = (List<GameObject>)waypointsPool.GetChildren();
SetData("waypoints", waypoints);
}
} }
//Called every tick //Called every tick
@ -112,8 +97,8 @@ public partial class Homeowner1 : BehaviourTree
{ {
events.Tick(); events.Tick();
//Footsteps SFX, move them somewhere else soon
float velocity = GetComponent<RigidBody>().LinearVelocity.GetMagnitude(); float velocity = GetComponent<RigidBody>().LinearVelocity.GetMagnitude();
leafPatrol.waypoints = waypoints;
footstepTimeRemaining -= velocity * Time.DeltaTimeF; footstepTimeRemaining -= velocity * Time.DeltaTimeF;
if (footstepTimeRemaining < 0.0f) if (footstepTimeRemaining < 0.0f)
@ -128,22 +113,20 @@ 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()
{ {
leafPatrol = new LeafPatrol("Patrol", _thisTransform, waypoints, patrolSpeed, turningSpeed, _thisRigidbody);
//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", _thisTransform, eyeOffset, sightDistance), new LeafSearch("SearchFOV", GetComponent<Transform>(), eyeOffset, sightDistance),
new BehaviourTreeSequence("CatchPlayer", new List<BehaviourTreeNode> new BehaviourTreeSequence("CatchPlayer", new List<BehaviourTreeNode>
{ {
new LeafChase("Chasing", _thisTransform, _thisRigidbody, chaseSpeed, turningSpeed, distanceToCapture, captureTime), new LeafChase("Chasing", GetComponent<Transform>(), GetComponent<RigidBody>(), chaseSpeed, turningSpeed, distanceToCapture, captureTime),
new LeafAttack("Attacking") new LeafAttack("Attacking", GameObject.Find("Player").GetValueOrDefault())
}) })
}),*/ }),
leafPatrol new LeafPatrol("Patrol", GetComponent<Transform>(), patrolSpeed, turningSpeed, GetComponent<RigidBody>())
}); });
return root; return root;
} }
} }

View File

@ -28,22 +28,13 @@ public partial class LeafAttack : BehaviourTreeNode
//FUNCTIONS //FUNCTIONS
public partial class LeafAttack : BehaviourTreeNode public partial class LeafAttack : BehaviourTreeNode
{ {
public LeafAttack(string name) : base (name) public LeafAttack(string name, GameObject p) : base (name)
{ {
//player = p; player = p;
} }
public override BehaviourTreeNodeStatus Evaluate() public override BehaviourTreeNodeStatus Evaluate()
{ {
{
if (!player)
{
player = GameObject.Find("Player").GetValueOrDefault();
Debug.Log("HERE2");
if (!player) { return BehaviourTreeNodeStatus.FAILURE; }
}
}
//Debug.LogWarning("LeafAttack"); //Debug.LogWarning("LeafAttack");
//Fail if no target in blackboard? //Fail if no target in blackboard?

View File

@ -22,10 +22,10 @@ public partial class LeafPatrol : BehaviourTreeNode
{ {
//Waypoints and movement //Waypoints and movement
private Transform transform; private Transform transform;
public List<Vector3> waypoints; private List<GameObject> waypoints;
private RigidBody rb; private RigidBody rb;
private float patrolSpeed = 1.0f; private float patrolSpeed;
private float turningSpeed = 5.0f; 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;
@ -42,10 +42,9 @@ 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, List<Vector3> wps, float patrolSpeed, float turnSpeed, RigidBody rb) : base(name) public LeafPatrol(string name, Transform t, float patrolSpeed, float turnSpeed, RigidBody rb) : base(name)
{ {
transform = t; transform = t;
waypoints = wps;
this.patrolSpeed = patrolSpeed; this.patrolSpeed = patrolSpeed;
turningSpeed = turnSpeed; turningSpeed = turnSpeed;
this.rb = rb; this.rb = rb;
@ -59,6 +58,10 @@ public partial class LeafPatrol : BehaviourTreeNode
{ {
//Debug.LogWarning("LeafPatrol"); //Debug.LogWarning("LeafPatrol");
onEnter(BehaviourTreeNodeStatus.RUNNING); onEnter(BehaviourTreeNodeStatus.RUNNING);
if(GetNodeData("currentWaypointIndex") == null)
{
SetNodeData("currentWaypointIndex", 0);
}
if (isWaiting) DelayAtWaypoint(); if (isWaiting) DelayAtWaypoint();
else MoveToWaypoint(); else MoveToWaypoint();
@ -80,27 +83,25 @@ public partial class LeafPatrol : BehaviourTreeNode
return; return;
} }
Vector3 remainingDistance = Vector3.Zero; waypoints = (List<GameObject>)GetNodeData("waypoints");
Debug.Log($"{waypoints.Count}"); Vector3 targetPosition = waypoints[currentWaypointIndex].GetComponent<Transform>().GlobalPosition;
if (currentWaypointIndex > 0)
{
Vector3 targetPosition = waypoints[currentWaypointIndex]; //Reach waypoint by X and Z being near enough
//Do not consider Y of waypoints yet
//Reach waypoint by X and Z being near enough Vector3 remainingDistance = targetPosition - transform.GlobalPosition;
//Do not consider Y of waypoints yet remainingDistance.y = 0.0f;
remainingDistance = targetPosition - transform.GlobalPosition;
remainingDistance.y = 0.0f;
}
//Reached waypoint, cycle //Reached waypoint, cycle
if (remainingDistance.GetSqrMagnitude() < 0.1f) if (remainingDistance.GetSqrMagnitude() < 0.1f)
{ {
//Cycle waypoints //Cycle waypoints
++currentWaypointIndex; ++currentWaypointIndex;
if (currentWaypointIndex >= waypoints.Count) if (currentWaypointIndex >= waypoints.Count())
currentWaypointIndex = 0; currentWaypointIndex = 0;
//Write to blackboard
SetNodeData("currentWaypointIndex", currentWaypointIndex);
waitCounter = 0.0f; waitCounter = 0.0f;
isWaiting = true; isWaiting = true;
} }
@ -115,7 +116,7 @@ public partial class LeafPatrol : BehaviourTreeNode
//Get the difference vector to the waypoint //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("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()); //Debug.Log("AI is at " + transform.GlobalPosition.x.ToString() + " " + transform.GlobalPosition.y.ToString() + " " + transform.GlobalPosition.z.ToString());
Vector3 normalisedDifference = waypoints[currentWaypointIndex] - transform.GlobalPosition; Vector3 normalisedDifference = targetPosition - transform.GlobalPosition;
normalisedDifference.y = 0.0f; //Do not move vertically normalisedDifference.y = 0.0f; //Do not move vertically
normalisedDifference /= normalisedDifference.GetMagnitude(); normalisedDifference /= normalisedDifference.GetMagnitude();
//Debug.Log("Normalised Difference x " + normalisedDifference.x.ToString() + " z " + normalisedDifference.z.ToString()); //Debug.Log("Normalised Difference x " + normalisedDifference.x.ToString() + " z " + normalisedDifference.z.ToString());

View File

@ -21,11 +21,10 @@ using System.Threading.Tasks;
//VARIABLES HERE //VARIABLES HERE
public partial class LeafSearch : BehaviourTreeNode public partial class LeafSearch : BehaviourTreeNode
{ {
private GameObject player;
private Transform transform; private Transform transform;
private Vector3 eyeOffset; private Vector3 eyeOffset;
private float sightDistance; private float sightDistance;
private GameObject? player; //To be searched for and marked
} }
//FUNCTIONS HERE //FUNCTIONS HERE
@ -33,111 +32,143 @@ public partial class LeafSearch : BehaviourTreeNode
{ {
public LeafSearch(string name, Transform t, Vector3 eo, float sDist) : base(name) public LeafSearch(string name, Transform t, Vector3 eo, float sDist) : base(name)
{ {
Debug.Log($"===============================PLAYER: {t}");
// player = p;
transform = t; transform = t;
eyeOffset = eo; eyeOffset = eo;
sightDistance = sDist; 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() public override BehaviourTreeNodeStatus Evaluate()
{ {
{
if (!player)
{
player = GameObject.Find("Player").GetValueOrDefault();
if (!player) { Debug.Log("HERE1"); return BehaviourTreeNodeStatus.FAILURE; }
}
}
//Debug.LogWarning("LeafSearch"); //Debug.LogWarning("LeafSearch");
onEnter(BehaviourTreeNodeStatus.RUNNING); onEnter(BehaviourTreeNodeStatus.RUNNING);
//Fail if unable to find a player //Search for player
//Get player's transform player = GameObject.Find("Player");
Transform plrT = player.GetComponent<Transform>();
//DELETE THIS //Automatically fail if no player is found
//Debug.Log("X " + MathF.Sin(transform.LocalEulerAngles.y).ToString() + " Z " + MathF.Cos(transform.LocalEulerAngles.y).ToString()); if (player == null)
//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); SetNodeData("isAlert", false);
status = BehaviourTreeNodeStatus.FAILURE; status = BehaviourTreeNodeStatus.FAILURE;
onExit(BehaviourTreeNodeStatus.FAILURE); onExit(BehaviourTreeNodeStatus.FAILURE);
return status; return status;
} }
else
//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"); //Fail if unable to find a player
if (GetNodeData("isAlert") != null && (bool)GetNodeData("isAlert") == true) //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("AI play unalert hmm"); //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;
} }
SetNodeData("isAlert", false);
status = BehaviourTreeNodeStatus.FAILURE; //Fail if player is out of FOV
onExit(BehaviourTreeNodeStatus.FAILURE); //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; 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;
} }
} }

View File

@ -74,7 +74,9 @@ namespace Sandbox
SHSystemManager::CreateSystem<SHScriptEngine>(); SHSystemManager::CreateSystem<SHScriptEngine>();
SHSystemManager::CreateSystem<SHTransformSystem>(); SHSystemManager::CreateSystem<SHTransformSystem>();
SHSystemManager::CreateSystem<SHPhysicsSystem>(); SHSystemManager::CreateSystem<SHPhysicsSystem>();
#ifndef _PUBLISH
SHSystemManager::CreateSystem<SHPhysicsDebugDrawSystem>(); SHSystemManager::CreateSystem<SHPhysicsDebugDrawSystem>();
#endif
SHSystemManager::CreateSystem<SHAudioSystem>(); SHSystemManager::CreateSystem<SHAudioSystem>();
SHSystemManager::CreateSystem<SHCameraSystem>(); SHSystemManager::CreateSystem<SHCameraSystem>();
@ -114,7 +116,9 @@ namespace Sandbox
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsFixedUpdate>();
SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>(); SHSystemManager::RegisterRoutine<SHPhysicsSystem, SHPhysicsSystem::PhysicsPostUpdate>();
#ifndef _PUBLISH
SHSystemManager::RegisterRoutine<SHPhysicsDebugDrawSystem, SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine>(); SHSystemManager::RegisterRoutine<SHPhysicsDebugDrawSystem, SHPhysicsDebugDrawSystem::PhysicsDebugDrawRoutine>();
#endif
SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>(); SHSystemManager::RegisterRoutine<SHTransformSystem, SHTransformSystem::TransformPostPhysicsUpdate>();
SHSystemManager::RegisterRoutine<SHDebugDrawSystem, SHDebugDrawSystem::ProcessPointsRoutine>(); SHSystemManager::RegisterRoutine<SHDebugDrawSystem, SHDebugDrawSystem::ProcessPointsRoutine>();
@ -189,6 +193,13 @@ namespace Sandbox
SHSystemManager::RunRoutines(false, SHFrameRateController::GetRawDeltaTime()); SHSystemManager::RunRoutines(false, SHFrameRateController::GetRawDeltaTime());
#endif #endif
// TODO: Move into an Editor menu // TODO: Move into an Editor menu
static bool drawContacts = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F9))
{
drawContacts = !drawContacts;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_POINTS, drawContacts);
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_NORMALS, drawContacts);
}
static bool drawColliders = false; static bool drawColliders = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10)) if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F10))
{ {
@ -201,13 +212,7 @@ namespace Sandbox
drawRays = !drawRays; drawRays = !drawRays;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays); SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::RAYCASTS, drawRays);
} }
static bool drawContacts = false;
if (SHInputManager::GetKeyDown(SHInputManager::SH_KEYCODE::F9))
{
drawContacts = !drawContacts;
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_POINTS, drawContacts);
SHSystemManager::GetSystem<SHPhysicsDebugDrawSystem>()->SetDebugDrawFlag(SHPhysicsDebugDrawSystem::DebugDrawFlags::CONTACT_NORMALS, drawContacts);
}
} }
// Finish all graphics jobs first // Finish all graphics jobs first
graphicsSystem->AwaitGraphicsExecution(); graphicsSystem->AwaitGraphicsExecution();

View File

@ -84,14 +84,27 @@ namespace SHADE
{ {
const SHCollisionInfo& C_INFO = *eventIter; const SHCollisionInfo& C_INFO = *eventIter;
const bool CLEAR_EVENT = C_INFO.GetCollisionState() == SHCollisionInfo::State::EXIT || C_INFO.GetCollisionState() == SHCollisionInfo::State::INVALID;
const bool INVALID_ENTITY = !SHEntityManager::IsValidEID(C_INFO.GetEntityA()) || !SHEntityManager::IsValidEID(C_INFO.GetEntityB()); const bool INVALID_ENTITY = !SHEntityManager::IsValidEID(C_INFO.GetEntityA()) || !SHEntityManager::IsValidEID(C_INFO.GetEntityB());
const bool INACTIVE_OBJECT = !SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(C_INFO.GetEntityA()) || !SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(C_INFO.GetEntityB()); if (INVALID_ENTITY)
{
if (CLEAR_EVENT || INVALID_ENTITY || INACTIVE_OBJECT)
eventIter = container.erase(eventIter); eventIter = container.erase(eventIter);
continue;
}
else else
++eventIter; {
const bool CLEAR_EVENT = C_INFO.GetCollisionState() == SHCollisionInfo::State::EXIT || C_INFO.GetCollisionState() == SHCollisionInfo::State::INVALID;
const bool INACTIVE_OBJECT = !SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(C_INFO.GetEntityA())
|| !SHSceneManager::CheckNodeAndComponentsActive<SHColliderComponent>(C_INFO.GetEntityB());
if (CLEAR_EVENT || INACTIVE_OBJECT)
{
eventIter = container.erase(eventIter);
continue;
}
}
++eventIter;
} }
}; };

View File

@ -63,7 +63,7 @@ namespace SHADE
raycasts.clear(); raycasts.clear();
} }
SHPhysicsRaycastResult SHPhysicsRaycaster::Raycast(const SHRay& ray, float distance) noexcept SHPhysicsRaycastResult SHPhysicsRaycaster::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept
{ {
// Reset temp // Reset temp
temp = SHPhysicsRaycastResult{}; temp = SHPhysicsRaycastResult{};
@ -78,13 +78,13 @@ namespace SHADE
// If distance in infinity, cast to the default max distance of 2 km. // If distance in infinity, cast to the default max distance of 2 km.
if (distance == std::numeric_limits<float>::infinity()) if (distance == std::numeric_limits<float>::infinity())
{ {
world->raycast(ray, this); world->raycast(ray, this, collisionTag);
} }
else else
{ {
const SHVec3 END_POINT = ray.position + ray.direction * distance; const SHVec3 END_POINT = ray.position + ray.direction * distance;
const rp3d::Ray RP3D_RAY{ ray.position, END_POINT }; const rp3d::Ray RP3D_RAY{ ray.position, END_POINT };
world->raycast(RP3D_RAY, this); world->raycast(RP3D_RAY, this, collisionTag);
} }
// If a hit was found, populate temp info for return. // If a hit was found, populate temp info for return.
@ -98,7 +98,7 @@ namespace SHADE
return temp; return temp;
} }
SHPhysicsRaycastResult SHPhysicsRaycaster::Linecast(const SHVec3& start, const SHVec3& end) noexcept SHPhysicsRaycastResult SHPhysicsRaycaster::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept
{ {
temp = SHPhysicsRaycastResult{}; temp = SHPhysicsRaycastResult{};
temp.distance = SHVec3::Distance(start, end); temp.distance = SHVec3::Distance(start, end);
@ -110,7 +110,7 @@ namespace SHADE
} }
const rp3d::Ray RP3D_RAY{ start, end }; const rp3d::Ray RP3D_RAY{ start, end };
world->raycast(RP3D_RAY, this); world->raycast(RP3D_RAY, this, collisionTag);
if (temp.hit) if (temp.hit)
{ {

View File

@ -19,6 +19,7 @@
#include "Physics/PhysicsObject/SHPhysicsObjectManager.h" #include "Physics/PhysicsObject/SHPhysicsObjectManager.h"
#include "Physics/SHPhysicsWorld.h" #include "Physics/SHPhysicsWorld.h"
#include "SH_API.h" #include "SH_API.h"
#include "SHCollisionTags.h"
#include "SHPhysicsRaycastResult.h" #include "SHPhysicsRaycastResult.h"
namespace SHADE namespace SHADE
@ -67,44 +68,46 @@ namespace SHADE
SHPhysicsRaycastResult Raycast SHPhysicsRaycastResult Raycast
( (
const SHRay& ray const SHRay& ray
, float distance = std::numeric_limits<float>::infinity() , float distance = std::numeric_limits<float>::infinity()
, const SHCollisionTag& collisionTag = SHCollisionTag{}
) noexcept; ) noexcept;
SHPhysicsRaycastResult Linecast SHPhysicsRaycastResult Linecast
( (
const SHVec3& start const SHVec3& start
, const SHVec3& end , const SHVec3& end
, const SHCollisionTag& collisionTag = SHCollisionTag{}
) noexcept; ) noexcept;
SHPhysicsRaycastResult ColliderRaycast SHPhysicsRaycastResult ColliderRaycast
( (
EntityID eid EntityID eid
, const SHRay& ray , const SHRay& ray
, float distance = std::numeric_limits<float>::infinity() , float distance = std::numeric_limits<float>::infinity()
) noexcept; ) noexcept;
SHPhysicsRaycastResult ColliderRaycast SHPhysicsRaycastResult ColliderRaycast
( (
EntityID eid EntityID eid
, int shapeIndex , int shapeIndex
, const SHRay& ray , const SHRay& ray
, float distance = std::numeric_limits<float>::infinity() , float distance = std::numeric_limits<float>::infinity()
) noexcept; ) noexcept;
SHPhysicsRaycastResult ColliderLinecast SHPhysicsRaycastResult ColliderLinecast
( (
EntityID eid EntityID eid
, const SHVec3& start , const SHVec3& start
, const SHVec3& end , const SHVec3& end
) noexcept; ) noexcept;
SHPhysicsRaycastResult ColliderLinecast SHPhysicsRaycastResult ColliderLinecast
( (
EntityID eid EntityID eid
, int shapeIndex , int shapeIndex
, const SHVec3& start , const SHVec3& start
, const SHVec3& end , const SHVec3& end
) noexcept; ) noexcept;
rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override; rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override;

View File

@ -206,7 +206,7 @@ namespace SHADE
} }
// Set the half extents relative to world scale // Set the half extents relative to world scale
const SHVec3 WORLD_EXTENTS = correctedHalfExtents * COLLIDER->GetScale() * 0.5f; const SHVec3 WORLD_EXTENTS = correctedHalfExtents * COLLIDER->GetScale();
if (type != Type::BOX) if (type != Type::BOX)
{ {

View File

@ -120,21 +120,25 @@ namespace SHADE
} }
rp3d::DebugRenderer* rp3dRenderer = nullptr; rp3d::DebugRenderer* rp3dRenderer = nullptr;
#ifdef SHEDITOR if (system->physicsSystem->worldState.world)
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
{
rp3dRenderer = &system->physicsSystem->worldState.world->getDebugRenderer(); rp3dRenderer = &system->physicsSystem->worldState.world->getDebugRenderer();
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, false);
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, false);
}
#endif
for (int i = 0; i < SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); ++i) for (int i = 0; i < SHUtilities::ConvertEnum(DebugDrawFlags::NUM_FLAGS); ++i)
{ {
const bool DRAW = (system->debugDrawFlags & (1U << i)) > 0; const bool DRAW = (system->debugDrawFlags & (1U << i)) > 0;
if (DRAW) if (DRAW)
{
drawFunctions[i](debugDrawSystem, rp3dRenderer); drawFunctions[i](debugDrawSystem, rp3dRenderer);
}
else
{
if (rp3dRenderer && (i == 3 || i == 4))
{
rp3dRenderer->setIsDebugItemDisplayed(reactphysics3d::DebugRenderer::DebugItem::CONTACT_POINT, false);
rp3dRenderer->setIsDebugItemDisplayed(reactphysics3d::DebugRenderer::DebugItem::CONTACT_NORMAL, false);
}
}
} }
// Automatically clear the container of raycasts despite debug drawing state // Automatically clear the container of raycasts despite debug drawing state
@ -180,6 +184,7 @@ namespace SHADE
void SHPhysicsDebugDrawSystem::drawContactPoints(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept void SHPhysicsDebugDrawSystem::drawContactPoints(SHDebugDrawSystem* debugRenderer, rp3d::DebugRenderer* rp3dRenderer) noexcept
{ {
#ifdef SHEDITOR #ifdef SHEDITOR
const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>(); const auto* EDITOR = SHSystemManager::GetSystem<SHEditor>();
if (EDITOR && EDITOR->editorState != SHEditor::State::STOP) if (EDITOR && EDITOR->editorState != SHEditor::State::STOP)
{ {
@ -192,6 +197,18 @@ namespace SHADE
for (int i = 0; i < NUM_TRIS; ++i) for (int i = 0; i < NUM_TRIS; ++i)
debugRenderer->DrawTri(SHColour::RED, TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3); debugRenderer->DrawTri(SHColour::RED, TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3);
} }
#else
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_POINT, true);
const int NUM_TRIS = static_cast<int>(rp3dRenderer->getNbTriangles());
if (NUM_TRIS == 0)
return;
const auto& TRI_ARRAY = rp3dRenderer->getTrianglesArray();
for (int i = 0; i < NUM_TRIS; ++i)
debugRenderer->DrawTri(SHColour::RED, TRI_ARRAY[i].point1, TRI_ARRAY[i].point2, TRI_ARRAY[i].point3);
#endif #endif
} }
@ -210,6 +227,18 @@ namespace SHADE
for (int i = 0; i < NUM_LINES; ++i) for (int i = 0; i < NUM_LINES; ++i)
debugRenderer->DrawLine(SHColour::RED, LINE_ARRAY[i].point1, LINE_ARRAY[i].point2); debugRenderer->DrawLine(SHColour::RED, LINE_ARRAY[i].point1, LINE_ARRAY[i].point2);
} }
#else
rp3dRenderer->setIsDebugItemDisplayed(rp3d::DebugRenderer::DebugItem::CONTACT_NORMAL, true);
const int NUM_LINES = static_cast<int>(rp3dRenderer->getNbLines());
if (NUM_LINES == 0)
return;
const auto& LINE_ARRAY = rp3dRenderer->getLinesArray();
for (int i = 0; i < NUM_LINES; ++i)
debugRenderer->DrawLine(SHColour::RED, LINE_ARRAY[i].point1, LINE_ARRAY[i].point2);
#endif #endif
} }

View File

@ -163,8 +163,6 @@ namespace SHADE
// Destroy an existing world // Destroy an existing world
if (worldState.world != nullptr) if (worldState.world != nullptr)
{ {
objectManager.RemoveAllObjects(); objectManager.RemoveAllObjects();
objectManager.SetWorld(nullptr); objectManager.SetWorld(nullptr);
@ -174,12 +172,12 @@ namespace SHADE
worldState.DestroyWorld(factory); worldState.DestroyWorld(factory);
} }
worldState.CreateWorld(factory); worldState.CreateWorld(factory);
#ifdef _PUBLISH #ifdef _PUBLISH
worldState.world->setIsDebugRenderingEnabled(false); worldState.world->setIsDebugRenderingEnabled(false);
#else #else
worldState.world->setIsDebugRenderingEnabled(true); worldState.world->setIsDebugRenderingEnabled(true);
#endif #endif
// Link Collision Listener & Raycaster // Link Collision Listener & Raycaster
collisionListener.BindToWorld(worldState.world); collisionListener.BindToWorld(worldState.world);
@ -260,14 +258,14 @@ namespace SHADE
} }
} }
SHPhysicsRaycastResult SHPhysicsSystem::Raycast(const SHRay& ray, float distance) noexcept SHPhysicsRaycastResult SHPhysicsSystem::Raycast(const SHRay& ray, float distance, const SHCollisionTag& collisionTag) noexcept
{ {
return raycaster.Raycast(ray, distance); return raycaster.Raycast(ray, distance, collisionTag);
} }
SHPhysicsRaycastResult SHPhysicsSystem::Linecast(const SHVec3& start, const SHVec3& end) noexcept SHPhysicsRaycastResult SHPhysicsSystem::Linecast(const SHVec3& start, const SHVec3& end, const SHCollisionTag& collisionTag) noexcept
{ {
return raycaster.Linecast(start, end); return raycaster.Linecast(start, end, collisionTag);
} }
SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept SHPhysicsRaycastResult SHPhysicsSystem::ColliderRaycast(EntityID eid, const SHRay& ray, float distance) noexcept
@ -444,11 +442,11 @@ namespace SHADE
return onPlayEvent->handle; return onPlayEvent->handle;
worldState.CreateWorld(factory); worldState.CreateWorld(factory);
#ifdef _PUBLISH #ifdef _PUBLISH
worldState.world->setIsDebugRenderingEnabled(false); worldState.world->setIsDebugRenderingEnabled(false);
#else #else
worldState.world->setIsDebugRenderingEnabled(true); worldState.world->setIsDebugRenderingEnabled(true);
#endif #endif
// Link Collision Listener & Raycaster // Link Collision Listener & Raycaster
collisionListener.BindToWorld(worldState.world); collisionListener.BindToWorld(worldState.world);

View File

@ -85,24 +85,28 @@ namespace SHADE
* @brief Casts a ray into the world. * @brief Casts a ray into the world.
* @param ray The ray to cast. * @param ray The ray to cast.
* @param distance The distance to cast the ray. Defaults to infinity. * @param distance The distance to cast the ray. Defaults to infinity.
* @param collisionTag The collision tag to use for filtering the raycast.
* @return The result of the raycast. * @return The result of the raycast.
*/ */
SHPhysicsRaycastResult Raycast SHPhysicsRaycastResult Raycast
( (
const SHRay& ray const SHRay& ray
, float distance = std::numeric_limits<float>::infinity() , float distance = std::numeric_limits<float>::infinity()
, const SHCollisionTag& collisionTag = SHCollisionTag{}
) noexcept; ) noexcept;
/** /**
* @brief Casts a bounded ray into the world. * @brief Casts a bounded ray into the world.
* @param start The starting point of the ray. * @param start The starting point of the ray.
* @param end The end point of the ray. * @param end The end point of the ray.
* @param collisionTag The collision tag to use for filtering the bounded raycast.
* @return The result of the raycast. * @return The result of the raycast.
*/ */
SHPhysicsRaycastResult Linecast SHPhysicsRaycastResult Linecast
( (
const SHVec3& start const SHVec3& start
, const SHVec3& end , const SHVec3& end
, const SHCollisionTag& collisionTag = SHCollisionTag{}
) noexcept; ) noexcept;
/** /**

View File

@ -20,6 +20,7 @@
#include "Scripting/SHScriptEngine.h" #include "Scripting/SHScriptEngine.h"
#include "Input/SHInputManager.h" #include "Input/SHInputManager.h"
#include "Physics/Collision/SHCollisionTagMatrix.h"
/*-------------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------------*/
/* Local Functions */ /* Local Functions */
@ -334,10 +335,6 @@ namespace SHADE
if (physicsObject.GetRigidBody()->isActive()) if (physicsObject.GetRigidBody()->isActive())
physicsObject.prevTransform = CURRENT_TF; physicsObject.prevTransform = CURRENT_TF;
// Skip sleeping objects
if (physicsObject.GetRigidBody()->isSleeping())
return;
// Sync with rigid bodies // Sync with rigid bodies
if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(physicsObject.entityID)) if (rigidBodyComponent && SHSceneManager::CheckNodeAndComponentsActive<SHRigidBodyComponent>(physicsObject.entityID))
{ {
@ -369,7 +366,7 @@ namespace SHADE
colliderComponent->orientation = CURRENT_TF.getOrientation(); colliderComponent->orientation = CURRENT_TF.getOrientation();
} }
// Set transform for rendering // Set transform for rendering
if (transformComponent) if (transformComponent)
{ {
transformComponent->SetWorldPosition(renderPos); transformComponent->SetWorldPosition(renderPos);
@ -407,4 +404,13 @@ void testFunction()
rb->AddForce(SHVec3::UnitX * forceModifier); rb->AddForce(SHVec3::UnitX * forceModifier);
} }
} }
// Cast rays
auto* tag = SHCollisionTagMatrix::GetTag(1);
tag->SetLayerState(SHCollisionTag::Layer::_1, false);
tag->SetLayerState(SHCollisionTag::Layer::_2, true);
SHRay ray { SHVec3{3.0f, 3.5f, 0.0f}, -SHVec3::UnitX };
auto* physicsSystem = SHSystemManager::GetSystem<SHPhysicsSystem>();
physicsSystem->Raycast(ray, std::numeric_limits<float>::infinity(), *tag);
} }

View File

@ -197,12 +197,18 @@ namespace SHADE
if (BUILD_SUCCESS) if (BUILD_SUCCESS)
{ {
// Copy to built dll to the working directory and replace // Copy to built dll to the working directory and replace
std::filesystem::copy_file("./tmp/SHADE_Scripting.dll", "SHADE_Scripting.dll", std::filesystem::copy_options::overwrite_existing); if (!copyFile("./tmp/SHADE_Scripting.dll", "SHADE_Scripting.dll", std::filesystem::copy_options::overwrite_existing))
{
SHLOG_ERROR("[ScriptEngine] Failed to replace scripts assembly. Scripts will remain outdated.");
}
// If debug, we want to copy the PDB so that we can do script debugging // If debug, we want to copy the PDB so that we can do script debugging
if (debug) if (debug)
{ {
std::filesystem::copy_file("./tmp/SHADE_Scripting.pdb", "SHADE_Scripting.pdb", std::filesystem::copy_options::overwrite_existing); if (!copyFile("./tmp/SHADE_Scripting.pdb", "SHADE_Scripting.pdb", std::filesystem::copy_options::overwrite_existing))
{
SHLOG_WARNING("[ScriptEngine] Breakpoint debugging will not work as PDB cannot be updated. If you are currently debugging, stop the debugger first.");
}
} }
oss << "[ScriptEngine] Successfully built Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!"; oss << "[ScriptEngine] Successfully built Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!";
@ -591,6 +597,19 @@ namespace SHADE
return false; return false;
} }
bool SHScriptEngine::copyFile(const std::filesystem::path& from, const std::filesystem::path& to, const std::filesystem::copy_options options) noexcept
{
try
{
return std::filesystem::copy_file(from, to, options);
}
catch (std::exception& e)
{
SHLOG_ERROR("[ScriptEngine] Failed to copy file {} ({})", to.string(), std::string(e.what()));
return false;
}
}
DWORD SHScriptEngine::execProcess(const std::wstring& path, const std::wstring& args) DWORD SHScriptEngine::execProcess(const std::wstring& path, const std::wstring& args)
{ {
STARTUPINFOW startInfo; STARTUPINFOW startInfo;

View File

@ -319,6 +319,7 @@ namespace SHADE
/// <param name="filePath">File path to the file to check.</param> /// <param name="filePath">File path to the file to check.</param>
/// <returns> True if the file exists </returns> /// <returns> True if the file exists </returns>
static bool fileExists(const std::filesystem::path& filePath); static bool fileExists(const std::filesystem::path& filePath);
static bool copyFile(const std::filesystem::path& from, const std::filesystem::path& to, const std::filesystem::copy_options options) noexcept;
static DWORD execProcess(const std::wstring& path, const std::wstring& args); static DWORD execProcess(const std::wstring& path, const std::wstring& args);
static std::wstring generateBuildCommand(bool debug); static std::wstring generateBuildCommand(bool debug);
}; };

View File

@ -107,7 +107,7 @@ namespace SHADE
Vector3 Transform::Forward::get() Vector3 Transform::Forward::get()
{ {
const SHVec3 DIRECTION = SHVec3::Rotate(SHVec3::UnitZ, Convert::ToNative(GlobalRotation)); const SHVec3 DIRECTION = SHVec3::Rotate(-SHVec3::UnitZ, Convert::ToNative(GlobalRotation));
return Convert::ToCLI(DIRECTION); return Convert::ToCLI(DIRECTION);
} }

View File

@ -200,7 +200,16 @@ namespace SHADE
{ {
if (SHEditorUI::Button("Add Item")) if (SHEditorUI::Button("Add Item"))
{ {
System::Object^ obj = System::Activator::CreateInstance(listType); System::Object^ obj;
if (listType == System::String::typeid)
{
// Special case for string
obj = gcnew System::String("");
}
else
{
obj = System::Activator::CreateInstance(listType);
}
iList->Add(obj); iList->Add(obj);
registerUndoListAddAction(listType, iList, iList->Count - 1, obj); registerUndoListAddAction(listType, iList, iList->Count - 1, obj);
} }

View File

@ -21,6 +21,9 @@ of DigiPen Institute of Technology is prohibited.
#include <algorithm> #include <algorithm>
// Project Headers // Project Headers
#include "Math.hxx" #include "Math.hxx"
#include "Quaternion.hxx"
#include "Math/Vector/SHVec3.h"
#include "Utility/Convert.hxx"
namespace SHADE namespace SHADE
{ {
@ -148,21 +151,21 @@ namespace SHADE
{ {
return vec - (Project(vec, normal.GetNormalised()) * 2.0f); return vec - (Project(vec, normal.GetNormalised()) * 2.0f);
} }
Vector3 Vector3::RotateRadians(Vector3 vec, float radians) Vector3 Vector3::RotateX(Vector3 vec, float radians)
{ {
const float SINE = sin(radians); return Convert::ToCLI(SHVec3::RotateX(Convert::ToNative(vec), radians));
const float COSINE = cos(radians);
return Vector3
(
vec.x * COSINE - vec.y * SINE,
vec.x * SINE + vec.y * COSINE,
vec.z
);
} }
Vector3 Vector3::RotateDegrees(Vector3 vec, float degrees) Vector3 Vector3::RotateY(Vector3 vec, float radians)
{ {
return RotateRadians(vec, Math::DegreesToRadians(degrees)); return Convert::ToCLI(SHVec3::RotateY(Convert::ToNative(vec), radians));
}
Vector3 Vector3::RotateZ(Vector3 vec, float radians)
{
return Convert::ToCLI(SHVec3::RotateZ(Convert::ToNative(vec), radians));
}
Vector3 Vector3::Rotate(Vector3 vec, Vector3 axis, float radians)
{
return Convert::ToCLI(SHVec3::Rotate(Convert::ToNative(vec), Convert::ToNative(axis), radians));
} }
Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs) Vector3 Vector3::Min(Vector3 lhs, Vector3 rhs)
{ {

View File

@ -19,6 +19,8 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes // Project Includes
#include "Vector2.hxx" #include "Vector2.hxx"
value struct Quaternion;
namespace SHADE namespace SHADE
{ {
///<summary> ///<summary>
@ -266,7 +268,7 @@ namespace SHADE
/// <returns>The Vector3 that represents vec reflected across normal.</returns> /// <returns>The Vector3 that represents vec reflected across normal.</returns>
static Vector3 Reflect(Vector3 vec, Vector3 normal); static Vector3 Reflect(Vector3 vec, Vector3 normal);
/// <summary> /// <summary>
/// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise /// Rotates a Vector3 about the X-axis by a specified angle in an anti-clockwise
/// direction. /// direction.
/// </summary> /// </summary>
/// <param name="vec">A Vector3 to rotate.</param> /// <param name="vec">A Vector3 to rotate.</param>
@ -274,17 +276,37 @@ namespace SHADE
/// Angle to rotate the vector by in an anti-clockwise direction in radians. /// Angle to rotate the vector by in an anti-clockwise direction in radians.
/// </param> /// </param>
/// <returns>The Vector3 that represents the rotated vector.</returns> /// <returns>The Vector3 that represents the rotated vector.</returns>
static Vector3 RotateRadians(Vector3 vec, float radians); static Vector3 RotateX(Vector3 vec, float radians);
/// <summary> /// <summary>
/// Rotates a Vector3 on the Z-axis by a specified angle in an anti-clockwise /// Rotates a Vector3 about the Y-axis by a specified angle in an anti-clockwise
/// direction. /// direction.
/// </summary> /// </summary>
/// <param name="vec">A Vector3 to rotate.</param> /// <param name="vec">A Vector3 to rotate.</param>
/// <param name="degrees"> /// <param name="radians">
/// Angle to rotate the vector by in an anti-clockwise direction in degrees. /// Angle to rotate the vector by in an anti-clockwise direction in radians.
/// </param> /// </param>
/// <returns>The Vector3 that represents the rotated vector.</returns> /// <returns>The Vector3 that represents the rotated vector.</returns>
static Vector3 RotateDegrees(Vector3 vec, float degrees); static Vector3 RotateY(Vector3 vec, float radians);
/// <summary>
/// Rotates a Vector3 about the Z-axis by a specified angle in an anti-clockwise
/// direction.
/// </summary>
/// <param name="vec">A Vector3 to rotate.</param>
/// <param name="radians">
/// Angle to rotate the vector by in an anti-clockwise direction in radians.
/// </param>
/// <returns>The Vector3 that represents the rotated vector.</returns>
static Vector3 RotateZ(Vector3 vec, float radians);
/// <summary>
/// Rotates a Vector3 about an arbitrary axis by a specified angle in an anti-clockwise
/// direction.
/// </summary>
/// <param name="vec">A Vector3 to rotate.</param>
/// <param name="radians">
/// Angle to rotate the vector by in an anti-clockwise direction in radians.
/// </param>
/// <returns>The Vector3 that represents the rotated vector.</returns>
static Vector3 Rotate(Vector3 vec, Vector3 axis, float radians);
/// <summary> /// <summary>
/// Computes and returns a Vector3 that is made from the smallest components of /// Computes and returns a Vector3 that is made from the smallest components of
/// the two specified Vector3s. /// the two specified Vector3s.

View File

@ -74,7 +74,7 @@ namespace SHADE
// Add the script in // Add the script in
script->Initialize(GameObject(entity)); script->Initialize(GameObject(entity));
entityScriptList->Insert(System::Math::Clamp(index, 0, entityScriptList->Count), script); entityScriptList->Insert(System::Math::Clamp(index, 0, entityScriptList->Count), script);
if (Application::IsPlaying && !SHSceneManager::HasSceneChanged()) if (Application::IsPlaying && !isDeserialising)
{ {
// Only call immediately if we are in game and is not loading another scene // Only call immediately if we are in game and is not loading another scene
script->Awake(); script->Awake();
@ -423,6 +423,8 @@ namespace SHADE
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
void ScriptStore::Init() void ScriptStore::Init()
{ {
isDeserialising = false;
// Create an enumerable list of script types // Create an enumerable list of script types
refreshScriptTypeList(); refreshScriptTypeList();
// Get stored methods for interop variants of functions // Get stored methods for interop variants of functions
@ -724,6 +726,10 @@ namespace SHADE
bool ScriptStore::DeserialiseScripts(Entity entity, System::IntPtr yamlNodePtr) bool ScriptStore::DeserialiseScripts(Entity entity, System::IntPtr yamlNodePtr)
{ {
SAFE_NATIVE_CALL_BEGIN SAFE_NATIVE_CALL_BEGIN
// Flag that deserialization processs is ongoing
isDeserialising = true;
// Convert to pointer // Convert to pointer
YAML::Node* yamlNode = reinterpret_cast<YAML::Node*>(yamlNodePtr.ToPointer()); YAML::Node* yamlNode = reinterpret_cast<YAML::Node*>(yamlNodePtr.ToPointer());
@ -765,9 +771,16 @@ namespace SHADE
Debug::LogWarning("[ScriptStore] Script with unloaded type detected, skipping."); Debug::LogWarning("[ScriptStore] Script with unloaded type detected, skipping.");
} }
} }
// Unset flag for deserialization process
isDeserialising = false;
return true; return true;
SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore") SAFE_NATIVE_CALL_END_N("SHADE_Managed.ScriptStore")
// Unset flag for deserialization process
isDeserialising = false;
return false; return false;
} }

View File

@ -337,6 +337,7 @@ namespace SHADE
static ScriptSet disposalQueue; static ScriptSet disposalQueue;
static System::Collections::Generic::IEnumerable<System::Type^>^ scriptTypeList; static System::Collections::Generic::IEnumerable<System::Type^>^ scriptTypeList;
static System::Reflection::MethodInfo^ addScriptMethod; static System::Reflection::MethodInfo^ addScriptMethod;
static bool isDeserialising;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Helper Functions */ /* Helper Functions */

View File

@ -279,7 +279,15 @@ namespace SHADE
for (int i = 0; i < LIST_SIZE; ++i) for (int i = 0; i < LIST_SIZE; ++i)
{ {
// Create the object // Create the object
System::Object^ obj = System::Activator::CreateInstance(elemType); System::Object^ obj;
if (elemType == System::String::typeid)
{
obj = gcnew System::String("");
}
else
{
obj = System::Activator::CreateInstance(elemType);
}
// Set it's value // Set it's value
if (varAssignYaml(obj, node[i])) if (varAssignYaml(obj, node[i]))

View File

@ -167,6 +167,10 @@ namespace SHADE
{ {
valueObj = 0; valueObj = 0;
} }
else
{
return false;
}
} }
else else
{ {
@ -181,6 +185,10 @@ namespace SHADE
valueObj = FieldType(); valueObj = FieldType();
} }
} }
else
{
return false;
}
} }
} }

View File

@ -25,7 +25,6 @@ of DigiPen Institute of Technology is prohibited.
// Project Includes // Project Includes
#include "Engine/Entity.hxx" #include "Engine/Entity.hxx"
#include "Math/Vector2.hxx" #include "Math/Vector2.hxx"
#include "Math/Vector3.hxx"
#include "Math/Quaternion.hxx" #include "Math/Quaternion.hxx"
#include "Math/Ray.hxx" #include "Math/Ray.hxx"
#include "Physics/RaycastHit.hxx" #include "Physics/RaycastHit.hxx"
@ -34,6 +33,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/Color.hxx" #include "Graphics/Color.hxx"
#include "Physics/Collision/SHPhysicsRaycastResult.h" #include "Physics/Collision/SHPhysicsRaycastResult.h"
value struct Vector3;
namespace SHADE namespace SHADE
{ {
/// <summary> /// <summary>