Merge pull request #124 from SHADE-DP/SP3-6-c-scripting

Added Collider & RigidBody and Initial Implementation of CallbackActions and CallbackEvent
This commit is contained in:
XiaoQiDigipen 2022-10-27 23:26:02 +08:00 committed by GitHub
commit de1407f49e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 3427 additions and 55 deletions

52
SHADE_CSharp/premake5.lua Normal file
View File

@ -0,0 +1,52 @@
project "SHADE_CSharp"
architecture "x64"
kind "SharedLib"
language "C#"
clr "NetCore"
dotnetframework "net5.0"
namespace ("SHADE")
targetdir (outputdir)
objdir (interdir)
systemversion "latest"
files
{
"%{prj.location}/src/**.cs",
"%{prj.location}/src/**.tt"
}
flags
{
"MultiProcessorCompile"
}
dependson
{
"SHADE_Engine"
}
warnings 'Extra'
filter "configurations:Debug"
symbols "On"
defines {"_DEBUG"}
filter "configurations:Release"
optimize "On"
defines{"_RELEASE"}
filter "configurations:Publish"
optimize "On"
defines{"_RELEASE"}
require "vstudio"
function platformsElement(cfg)
_p(2,'<Platforms>x64</Platforms>')
end
premake.override(premake.vstudio.cs2005.elements, "projectProperties", function (oldfn, cfg)
return table.join(oldfn(cfg), {
platformsElement,
})
end)

View File

@ -0,0 +1,852 @@
/************************************************************************************//*!
\file CallbackAction.cs
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the definition of CallbackAction and related classes.
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.Reflection;
namespace SHADE
{
/// <summary>
/// Interface for a CallbackAction that all variants inherit from.
/// </summary>
public interface ICallbackAction
{
/// <summary>
/// Whether or not this CallbackAction is runtime assigned. If it is, then the
/// TargetMethodName and TargetObject properties are invalid.
/// </summary>
bool IsRuntimeAction { get; }
/// <summary>
/// Name of the method that this CallbackAction is using.
/// </summary>
string TargetMethodName { get; }
/// <summary>
/// Object which the specified target method is called on.
/// </summary>
Object TargetObject { get; }
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 1 parameter.
/// </summary>
public class CallbackAction<T1> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1)
{
if (targetAction != null)
{
targetAction.Invoke(t1);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 2 parameters.
/// </summary>
public class CallbackAction<T1, T2> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2)
{
if (targetAction != null)
{
targetAction.Invoke(t1, t2);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
parameters[1] = t2;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 3 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3)
{
if (targetAction != null)
{
targetAction.Invoke(t1, t2, t3);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
parameters[1] = t2;
parameters[2] = t3;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 4 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4)
{
if (targetAction != null)
{
targetAction.Invoke(t1, t2, t3, t4);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
parameters[1] = t2;
parameters[2] = t3;
parameters[3] = t4;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 5 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{
if (targetAction != null)
{
targetAction.Invoke(t1, t2, t3, t4, t5);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
parameters[1] = t2;
parameters[2] = t3;
parameters[3] = t4;
parameters[4] = t5;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 6 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{
if (targetAction != null)
{
targetAction.Invoke(t1, t2, t3, t4, t5, t6);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
parameters[1] = t2;
parameters[2] = t3;
parameters[3] = t4;
parameters[4] = t5;
parameters[5] = t6;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 7 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6, T7> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6, T7> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{
if (targetAction != null)
{
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
parameters[1] = t2;
parameters[2] = t3;
parameters[3] = t4;
parameters[4] = t5;
parameters[5] = t6;
parameters[6] = t7;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 8 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6, T7, T8> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{
if (targetAction != null)
{
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
parameters[1] = t2;
parameters[2] = t3;
parameters[3] = t4;
parameters[4] = t5;
parameters[5] = t6;
parameters[6] = t7;
parameters[7] = t8;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 9 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9)
{
if (targetAction != null)
{
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
parameters[1] = t2;
parameters[2] = t3;
parameters[3] = t4;
parameters[4] = t5;
parameters[5] = t6;
parameters[6] = t7;
parameters[7] = t8;
parameters[8] = t9;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with 10 parameters.
/// </summary>
public class CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10)
{
if (targetAction != null)
{
targetAction.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
}
else if (TargetObject != null && targetMethod != null)
{
parameters[0] = t1;
parameters[1] = t2;
parameters[2] = t3;
parameters[3] = t4;
parameters[4] = t5;
parameters[5] = t6;
parameters[6] = t7;
parameters[7] = t8;
parameters[8] = t9;
parameters[9] = t10;
_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
}

View File

@ -0,0 +1,132 @@
<#
/************************************************************************************//*!
\file CallbackAction.tt
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the T4 template for the definition of CallbackAction and
related classes.
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.
*//*************************************************************************************/#>
<#@ template hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<# var max = 10; #>
/************************************************************************************//*!
\file CallbackAction.cs
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the definition of CallbackAction and related classes.
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.Reflection;
namespace SHADE
{
/// <summary>
/// Interface for a CallbackAction that all variants inherit from.
/// </summary>
public interface ICallbackAction
{
/// <summary>
/// Whether or not this CallbackAction is runtime assigned. If it is, then the
/// TargetMethodName and TargetObject properties are invalid.
/// </summary>
bool IsRuntimeAction { get; }
/// <summary>
/// Name of the method that this CallbackAction is using.
/// </summary>
string TargetMethodName { get; }
/// <summary>
/// Object which the specified target method is called on.
/// </summary>
Object TargetObject { get; }
}
<# for (int i = 1; i <= max; ++i) { #>
/// <summary>
/// Represents a function call that can be serialised and put togetheer with scripts.
/// This variant accepts functions with <#=i#> parameter<# if (i > 1) {#>s<#} #>.
/// </summary>
public class CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackAction
{
#region Properties ------------------------------------------------------------
/// <inheritdoc/>
public Object TargetObject { get; private set; }
/// <inheritdoc/>
public string TargetMethodName => targetMethod == null ? "" : targetMethod.Name;
/// <inheritdoc/>
public bool IsRuntimeAction => targetAction != null;
#endregion
#region Fields ------------------------------------------------------------------
private MethodInfo targetMethod;
private Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> targetAction;
private Object[] parameters;
#endregion
#region Constructors ------------------------------------------------------------
/// <summary>
/// Constructs an empty Callback action.
/// </summary>
public CallbackAction() {}
/// <summary>
/// Constructs a CallbackAction that represents a call to the specified method on the
/// specified target.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
/// <exception cref="ArgumentException">
/// Thrown if a method that is not compatible with the target is specified. The method's
/// source type must match the target's type.
/// </exception>
public CallbackAction(Object target, MethodInfo method)
{
// Error Checks
if (method.DeclaringType != target.GetType())
throw new ArgumentException("[CallbackAction] Attempted register an action using an incompatible target object and method.");
// No errors, assign
TargetObject = target;
targetMethod = method;
// Create storage for parameters for calling
parameters = new Object[1];
}
/// <summary>
/// Constructs a Callback action based on an action.
/// </summary>
/// <param name="action"></param>
public CallbackAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{
targetAction = action;
}
#endregion
#region Usage Functions ---------------------------------------------------------
/// <summary>
/// Invokes the CallbackAction's stored method/action with the specified parameters.
/// </summary>
public void Invoke(<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#> t<#=t#><# if (t != i) { #>, <# } #><# } #>)
{
if (targetAction != null)
{
targetAction.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>);
}
else if (TargetObject != null && targetMethod != null)
{
<# for (int t = 0; t < i; ++t) {#>parameters[<#=t#>] = t<#=t+1#>;
<# } #>_ = targetMethod.Invoke(TargetObject, parameters);
}
}
#endregion
}
<# } #>
}

View File

@ -0,0 +1,908 @@
/************************************************************************************//*!
\file CallbackEvent.cs
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the definition of CallbackEvent and related classes.
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.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
namespace SHADE
{
/// <summary>
/// Interface for a CallbackEvent that all variants inherit from.
/// </summary>
public interface ICallbackEvent
{
/// <summary>
/// Registers an empty ICallbackAction.
/// </summary>
void RegisterAction();
/// <summary>
/// Registers an ICallbackAction with the event such that it will be called in
/// future
/// </summary>
/// <param name="action">ICallbackAction to register with.</param>
void RegisterAction(ICallbackAction action);
/// <summary>
/// Deregisters an ICallbackAction that was previously added. This should
/// only emit a warning if an action that was not previous added was
/// provided.
/// </summary>
/// <param name="action">ICallbackAction to remove.</param>
void DeregisterAction(ICallbackAction action);
/// <summary>
/// Iterable set of ICallbackActions that were registered to this event.
/// </summary>
IEnumerable<ICallbackAction> Actions { get; }
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1> action)
{
actions.Add(new CallbackAction<T1>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1)
{
foreach (CallbackAction<T1> action in actions)
{
try
{
action.Invoke(t1);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2> action)
{
actions.Add(new CallbackAction<T1, T2>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2)
{
foreach (CallbackAction<T1, T2> action in actions)
{
try
{
action.Invoke(t1, t2);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3> action)
{
actions.Add(new CallbackAction<T1, T2, T3>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3)
{
foreach (CallbackAction<T1, T2, T3> action in actions)
{
try
{
action.Invoke(t1, t2, t3);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4)
{
foreach (CallbackAction<T1, T2, T3, T4> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
{
foreach (CallbackAction<T1, T2, T3, T4, T5> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7, T8> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7, T8, T9> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9, T10 t10)
{
foreach (CallbackAction<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> action in actions)
{
try
{
action.Invoke(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
}

View File

@ -0,0 +1,152 @@
<#
/************************************************************************************//*!
\file CallbackEvent.tt
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the T4 template for the definition of CallbackEvent and
related classes.
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.
*//*************************************************************************************/#>
<#@ template hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<# var max = 10; #>
/************************************************************************************//*!
\file CallbackEvent.cs
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 23, 2022
\brief Contains the definition of CallbackEvent and related classes.
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.Diagnostics;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
namespace SHADE
{
/// <summary>
/// Interface for a CallbackEvent that all variants inherit from.
/// </summary>
public interface ICallbackEvent
{
/// <summary>
/// Registers an empty ICallbackAction.
/// </summary>
void RegisterAction();
/// <summary>
/// Registers an ICallbackAction with the event such that it will be called in
/// future
/// </summary>
/// <param name="action">ICallbackAction to register with.</param>
void RegisterAction(ICallbackAction action);
/// <summary>
/// Deregisters an ICallbackAction that was previously added. This should
/// only emit a warning if an action that was not previous added was
/// provided.
/// </summary>
/// <param name="action">ICallbackAction to remove.</param>
void DeregisterAction(ICallbackAction action);
/// <summary>
/// Iterable set of ICallbackActions that were registered to this event.
/// </summary>
IEnumerable<ICallbackAction> Actions { get; }
}
<# for (int i = 1; i <= max; ++i) { #>
/// <summary>
/// A container of CallbackActions that is correlated to a specific scenario as
/// specified by the user of this class.
/// This variant accepts CallbackEvents with 1 generic parameter.
/// </summary>
public class CallbackEvent<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> : ICallbackEvent
{
#region Properties --------------------------------------------------------------
/// <inheritdoc/>
public IEnumerable<ICallbackAction> Actions => actions;
#endregion
#region Fields ------------------------------------------------------------------
private List<ICallbackAction> actions = new List<ICallbackAction>();
#endregion
#region Usage Functions ---------------------------------------------------------
/// <inheritdoc/>
public void RegisterAction()
{
actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>());
}
/// <inheritdoc/>
public void RegisterAction(ICallbackAction action)
{
// Check if valid action
if (action.GetType() != typeof(CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>))
{
Debug.LogWarning("Attempted to register an invalid CallbackAction type. Ignoring.", this);
return;
}
actions.Add(action);
}
/// <summary>
/// Adds a CallbackAction into the event.
/// </summary>
/// <param name="action">CallbackAction to add.</param>
public void RegisterAction(CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{
actions.Add(action);
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="action">System.Action to add as a CallbackAction.</param>
public void RegisterAction(Action<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action)
{
actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>(action));
}
/// <summary>
/// Constructs and adds a CallbackACtion into the event.
/// </summary>
/// <param name="target">Object to call the method on.</param>
/// <param name="method">Method to call.</param>
public void RegisterAction(Object target, MethodInfo method)
{
actions.Add(new CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>>(target, method));
}
/// <inheritdoc/>
public void DeregisterAction(ICallbackAction action)
{
if (!actions.Remove(action))
{
Debug.LogWarning("Attempted to deregister invalid action. Ignored.", this);
}
}
/// <summary>
/// Invokes all stored CallbackActions with the specified parameters.
/// </summary>
public void Invoke(<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#> t<#=t#><# if (t != i) { #>, <# } #><# } #>)
{
foreach (CallbackAction<<# for (int t = 1; t < i + 1; ++t) { #>T<#=t#><# if (t != i) { #>, <# } #><# } #>> action in actions)
{
try
{
action.Invoke(<# for (int t = 1; t < i + 1; ++t) { #>t<#=t#><# if (t != i) { #>, <# } #><# } #>);
}
catch (Exception e)
{
Debug.LogException(e, this);
}
}
}
#endregion
}
<# } #>
}

View File

@ -0,0 +1,37 @@
using System;
using System.Runtime.InteropServices;
namespace SHADE
{
internal static class Debug
{
[DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Info")]
public static extern void LogInfo([MarshalAs(UnmanagedType.LPStr)] string str);
[DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Warning")]
public static extern void LogWarning([MarshalAs(UnmanagedType.LPStr)] string str);
[DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Error")]
public static extern void LogError([MarshalAs(UnmanagedType.LPStr)] string str);
[DllImport("SHADE_Engine.dll", EntryPoint = "SHLog_Critical")]
public static extern void LogCritical([MarshalAs(UnmanagedType.LPStr)] string str);
public static void LogInfo(string msg, Object thrower)
{
LogInfo($"[{thrower.GetType().Name}] {msg}");
}
public static void LogWarning(string msg, Object thrower)
{
LogWarning($"[{thrower.GetType().Name}] {msg}");
}
public static void LogError(string msg, Object thrower)
{
LogError($"[{thrower.GetType().Name}] {msg}");
}
public static void LogCritical(string msg, Object thrower)
{
LogCritical($"[{thrower.GetType().Name}] {msg}");
}
public static void LogException(Exception exception, Object thrower)
{
LogError($"[{ thrower.GetType().Name }] Unhandled exception: { exception.ToString() }");
}
}
}

View File

@ -54,7 +54,7 @@ namespace SHADE
/*-----------------------------------------------------------------------------------*/
bool SHEditorUI::CollapsingHeader(const std::string& title)
{
return ImGui::CollapsingHeader(title.c_str());
return ImGui::CollapsingHeader(title.c_str(), ImGuiTreeNodeFlags_DefaultOpen);
}
void SHEditorUI::SameLine()

View File

@ -10,6 +10,9 @@
#include <SHpch.h>
// External Dependencies
#include <reactphysics3d/reactphysics3d.h>
// Primary Header
#include "SHRigidBodyComponent.h"

View File

@ -10,7 +10,6 @@
#pragma once
#include <reactphysics3d/reactphysics3d.h>
#include <rttr/registration>
// Project Headers
@ -23,6 +22,11 @@
// class SHPhysicsSystem;
//}
namespace reactphysics3d
{
class RigidBody;
}
namespace SHADE
{
/*-----------------------------------------------------------------------------------*/
@ -153,7 +157,7 @@ namespace SHADE
uint16_t dirtyFlags;
bool interpolate;
rp3d::RigidBody* rp3dBody;
reactphysics3d::RigidBody* rp3dBody;
float mass;
float drag;

View File

@ -24,6 +24,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Events/SHEvent.h"
#include "Events/SHEventReceiver.h"
#include "Events/SHEventManager.hpp"
#include "Physics/SHPhysicsSystem.h"
namespace SHADE
{
@ -60,7 +61,7 @@ namespace SHADE
// Initialise the CSharp Engine
csEngineInit();
// Register entity creation events
// Register all events
registerEvents();
}
void SHScriptEngine::UnloadScriptAssembly()
@ -191,6 +192,12 @@ namespace SHADE
// 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 debug, we want to copy the PDB so that we can do script debugging
if (debug)
{
std::filesystem::copy_file("./tmp/SHADE_Scripting.pdb", "SHADE_Scripting.pdb", std::filesystem::copy_options::overwrite_existing);
}
oss << "[ScriptEngine] Successfully built Managed Script Assembly (" << MANAGED_SCRIPT_LIB_NAME << ")!";
SHLOG_INFO(oss.str());
}
@ -255,6 +262,10 @@ namespace SHADE
<HintPath Condition=\"Exists('..\\bin\\Debug\\SHADE_Managed.dll')\">..\\bin\\Debug\\SHADE_Managed.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\bin\\Release\\SHADE_Managed.dll')\">..\\bin\\Release\\SHADE_Managed.dll</HintPath>\n\
</Reference>\n\
<Reference Include=\"SHADE_CSharp\">\n\
<HintPath Condition=\"Exists('..\\bin\\Debug\\SHADE_Managed.dll')\">..\\bin\\Debug\\SHADE_CSharp.dll</HintPath>\n\
<HintPath Condition=\"Exists('..\\bin\\Release\\SHADE_Managed.dll')\">..\\bin\\Release\\SHADE_CSharp.dll</HintPath>\n\
</Reference>\n\
</ItemGroup>\n\
</Project>";
@ -280,6 +291,28 @@ namespace SHADE
return eventData->handle;
}
SHEventHandle SHScriptEngine::onColliderAdded(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHPhysicsColliderAddedEvent>*>(eventPtr.get());
csColliderOnListChanged(eventData->data->entityID);
return eventData->handle;
}
SHEventHandle SHScriptEngine::onColliderRemoved(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHPhysicsColliderRemovedEvent>*>(eventPtr.get());
csColliderOnListChanged(eventData->data->entityID);
return eventData->handle;
}
SHEventHandle SHScriptEngine::onColliderComponentRemoved(SHEventPtr eventPtr)
{
auto eventData = reinterpret_cast<const SHEventSpec<SHComponentRemovedEvent>*>(eventPtr.get());
if (eventData->data->removedComponentType == ComponentFamily::GetID<SHColliderComponent>())
csColliderOnRemoved(eventData->data->eid);
return eventData->handle;
}
/*-----------------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------------*/
@ -380,6 +413,18 @@ namespace SHADE
DEFAULT_CSHARP_NAMESPACE + ".ScriptStore",
"DeserialiseScripts"
);
csColliderOnListChanged = dotNet.GetFunctionPtr<CsEventRelayFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Collider",
"OnColliderBoundChanged"
);
csColliderOnRemoved = dotNet.GetFunctionPtr<CsEventRelayFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
DEFAULT_CSHARP_NAMESPACE + ".Collider",
"OnColliderRemoved"
);
csEditorRenderScripts = dotNet.GetFunctionPtr<CsScriptEditorFuncPtr>
(
DEFAULT_CSHARP_LIB_NAME,
@ -407,8 +452,28 @@ namespace SHADE
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onEntityDestroyed)
};
ReceiverPtr receiver = std::dynamic_pointer_cast<SHEventReceiver>(destroyedEventReceiver);
SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, receiver);
SHEventManager::SubscribeTo(SH_ENTITY_DESTROYED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(destroyedEventReceiver));
// Register for collider added event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> addedColliderEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderAdded)
};
SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_ADDED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(addedColliderEventReceiver));
// Register for collider removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderRemoved)
};
SHEventManager::SubscribeTo(SH_PHYSICS_COLLIDER_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderEventReceiver));
// Register for collider component removed event
std::shared_ptr<SHEventReceiverSpec<SHScriptEngine>> removedColliderComponentEventReceiver
{
std::make_shared<SHEventReceiverSpec<SHScriptEngine>>(this, &SHScriptEngine::onColliderComponentRemoved)
};
SHEventManager::SubscribeTo(SH_COMPONENT_REMOVED_EVENT, std::dynamic_pointer_cast<SHEventReceiver>(removedColliderComponentEventReceiver));
}
void SHScriptEngine::dumpBuildLog(const std::string_view& buildLogPath)

View File

@ -218,6 +218,7 @@ namespace SHADE
using CsScriptSerialiseYamlFuncPtr = bool(*)(EntityID, void*);
using CsScriptDeserialiseYamlFuncPtr = bool(*)(EntityID, const void*);
using CsScriptEditorFuncPtr = void(*)(EntityID);
using CsEventRelayFuncPtr = void(*)(EntityID);
/*-----------------------------------------------------------------------------*/
/* Constants */
@ -250,6 +251,9 @@ namespace SHADE
CsScriptOptionalFuncPtr csScriptsRemoveAllImmediately = nullptr;
CsScriptSerialiseYamlFuncPtr csScriptsSerialiseYaml = nullptr;
CsScriptDeserialiseYamlFuncPtr csScriptsDeserialiseYaml = nullptr;
// - Events
CsEventRelayFuncPtr csColliderOnListChanged = nullptr;
CsEventRelayFuncPtr csColliderOnRemoved = nullptr;
// - Editor
CsScriptEditorFuncPtr csEditorRenderScripts = nullptr;
CsFuncPtr csEditorUndo = nullptr;
@ -259,6 +263,9 @@ namespace SHADE
/* Event Handler Functions */
/*-----------------------------------------------------------------------------*/
SHEventHandle onEntityDestroyed(SHEventPtr eventPtr);
SHEventHandle onColliderAdded(SHEventPtr eventPtr);
SHEventHandle onColliderRemoved(SHEventPtr eventPtr);
SHEventHandle onColliderComponentRemoved(SHEventPtr eventPtr);
/*-----------------------------------------------------------------------------*/
/* Helper Functions */

View File

@ -51,4 +51,24 @@ namespace SHADE
}
#endif
void SHLog_Info(const char* msg) noexcept
{
SHLOG_INFO(msg)
}
void SHLog_Warning(const char* msg) noexcept
{
SHLOG_WARNING(msg)
}
void SHLog_Error(const char* msg) noexcept
{
SHLOG_ERROR(msg)
}
void SHLog_Critical(const char* msg) noexcept
{
SHLOG_CRITICAL(msg)
}
}

View File

@ -45,4 +45,12 @@ namespace SHADE
static void Trace(const std::string& msg) noexcept;
#endif
};
extern "C"
{
static void SHLog_Info(const char* msg) noexcept;
static void SHLog_Warning(const char* msg) noexcept;
static void SHLog_Error(const char* msg) noexcept;
static void SHLog_Critical(const char* msg) noexcept;
}
}

View File

@ -45,7 +45,8 @@ project "SHADE_Managed"
{
"yaml-cpp",
"imgui",
"SHADE_Engine"
"SHADE_Engine",
"SHADE_CSharp"
}
disablewarnings

View File

@ -0,0 +1,257 @@
/************************************************************************************//*!
\file Collider.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 20, 2022
\brief Contains the definition of the functions of the managed Collider class.
Note: This file is written in C++17/CLI.
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.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "Collider.hxx"
#include "Utility/Debug.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* ColliderBound - Constructors */
/*---------------------------------------------------------------------------------*/
ColliderBound::ColliderBound(int arrayIdx, Entity attachedEntity)
: arrayIndex { arrayIdx }
, entity { attachedEntity }
{}
/*---------------------------------------------------------------------------------*/
/* ColliderBound - Setter Functions */
/*---------------------------------------------------------------------------------*/
void ColliderBound::updateArrayIndex(int index)
{
arrayIndex = index;
}
/*---------------------------------------------------------------------------------*/
/* BoxColliderBound - Constructors */
/*---------------------------------------------------------------------------------*/
BoxColliderBound::BoxColliderBound(int arrayIdx, Entity attachedEntity)
: ColliderBound { arrayIndex, attachedEntity }
{}
/*---------------------------------------------------------------------------------*/
/* BoxColliderBound - Properties */
/*---------------------------------------------------------------------------------*/
Vector3 BoxColliderBound::Center::get()
{
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetCenter());
}
void BoxColliderBound::Center::set(Vector3 value)
{
getNativeBoundObject<SHBoundingBox>().SetCenter(Convert::ToNative(value));
}
Vector3 BoxColliderBound::HalfExtents::get()
{
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetHalfExtents());
}
void BoxColliderBound::HalfExtents::set(Vector3 value)
{
getNativeBoundObject<SHBoundingBox>().SetHalfExtents(Convert::ToNative(value));
}
Vector3 BoxColliderBound::Min::get()
{
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetMin());
}
void BoxColliderBound::Min::set(Vector3 value)
{
getNativeBoundObject<SHBoundingBox>().SetMin(Convert::ToNative(value));
}
Vector3 BoxColliderBound::Max::get()
{
return Convert::ToCLI(getNativeBoundObject<SHBoundingBox>().GetMax());
}
void BoxColliderBound::Max::set(Vector3 value)
{
getNativeBoundObject<SHBoundingBox>().SetMax(Convert::ToNative(value));
}
/*---------------------------------------------------------------------------------*/
/* BoxColliderBound - Usage Functions */
/*---------------------------------------------------------------------------------*/
bool BoxColliderBound::TestPoint(Vector3 point)
{
return getNativeBoundObject<SHBoundingBox>().TestPoint(Convert::ToNative(point));
}
bool BoxColliderBound::Raycast(Ray ray, float maxDistance)
{
return getNativeBoundObject<SHBoundingBox>().Raycast(Convert::ToNative(ray), maxDistance);
}
/*---------------------------------------------------------------------------------*/
/* BoxColliderBound - Properties */
/*---------------------------------------------------------------------------------*/
Vector3 SphereColliderBound::Center::get()
{
return Convert::ToCLI(getNativeBoundObject<SHBoundingSphere>().GetCenter());
}
void SphereColliderBound::Center::set(Vector3 value)
{
getNativeBoundObject<SHBoundingSphere>().SetCenter(Convert::ToNative(value));
}
float SphereColliderBound::Radius::get()
{
return getNativeBoundObject<SHBoundingSphere>().GetRadius();
}
void SphereColliderBound::Radius::set(float value)
{
getNativeBoundObject<SHBoundingSphere>().SetRadius(value);
}
/*---------------------------------------------------------------------------------*/
/* SphereColliderBound - Usage Functions */
/*---------------------------------------------------------------------------------*/
bool SphereColliderBound::TestPoint(Vector3 point)
{
return getNativeBoundObject<SHBoundingBox>().TestPoint(Convert::ToNative(point));
}
bool SphereColliderBound::Raycast(Ray ray, float maxDistance)
{
return getNativeBoundObject<SHBoundingBox>().Raycast(Convert::ToNative(ray), maxDistance);
}
/*---------------------------------------------------------------------------------*/
/* SphereColliderBound - Constructors */
/*---------------------------------------------------------------------------------*/
SphereColliderBound::SphereColliderBound(int arrayIndex, Entity attachedEntity)
: ColliderBound{ arrayIndex, attachedEntity }
{}
/*---------------------------------------------------------------------------------*/
/* Collider - Constructors */
/*---------------------------------------------------------------------------------*/
Collider::Collider(Entity entity)
: Component(entity)
{
// Create lists if they don't exist
if (colliders == nullptr)
colliders = gcnew CollidersMap;
if (!colliders->ContainsKey(entity))
colliders->Add(entity, gcnew WeakReferenceList());
// Store a weak reference
colliders[entity]->Add(gcnew System::WeakReference(this));
}
/*---------------------------------------------------------------------------------*/
/* Collider - Properties */
/*---------------------------------------------------------------------------------*/
int Collider::ColliderBoundsCount::get()
{
return static_cast<int>(GetNativeComponent()->GetColliders().size());
}
/*---------------------------------------------------------------------------------*/
/* Collider - ColliderBound Functions */
/*---------------------------------------------------------------------------------*/
ColliderBound^ Collider::GetColliderBound(int index)
{
// Populate the list if it hasn't been
if (subColliderList == nullptr)
{
updateSubColliderList();
}
// Check if valid
if (index < 0 || index >= subColliderList->Count)
throw gcnew System::ArgumentException("[Collider] Invalid index for Collider Bound retrieval.");
// Return the bound
return subColliderList[index];
}
generic<typename T>
T Collider::GetColliderBound(int index)
{
return safe_cast<T>(GetColliderBound(index));
}
/*---------------------------------------------------------------------------------*/
/* Event Handling Functions */
/*---------------------------------------------------------------------------------*/
void Collider::OnColliderRemoved(EntityID entity)
{
SAFE_NATIVE_CALL_BEGIN
// Check if there are any colliders to update
if (colliders == nullptr || !colliders->ContainsKey(entity))
return;
// Remove the key
colliders->Remove(entity);
SAFE_NATIVE_CALL_END("Collider.OnColliderRemoved")
}
void Collider::OnColliderBoundChanged(EntityID entity)
{
SAFE_NATIVE_CALL_BEGIN
// Check if there are any colliders to update
if (colliders == nullptr || !colliders->ContainsKey(entity))
return;
// Update any colliders
System::Collections::Generic::List<System::WeakReference^>^ toRemove = gcnew System::Collections::Generic::List<System::WeakReference ^>();
WeakReferenceList^ collidersList = colliders[entity];
for each (System::WeakReference^ wr in collidersList)
{
Collider^ collider = safe_cast<Collider^>(wr->Target);
// Update collider bounds
if (collider && collider->subColliderList != nullptr)
collider->updateSubColliderList();
else
toRemove->Add(wr);
}
// Sweep through and clear any invalid references while we're at it
for each (System::WeakReference ^ wr in toRemove)
{
collidersList->Remove(wr);
}
SAFE_NATIVE_CALL_END("Collider.OnColliderBoundChanged")
}
void Collider::updateSubColliderList()
{
// Prepare the list
if (subColliderList)
subColliderList->Clear();
else
subColliderList = gcnew System::Collections::Generic::List<ColliderBound^>();
// Populate the list
int i = 0;
for (const auto& collider : GetNativeComponent()->GetColliders())
{
ColliderBound^ bound = nullptr;
switch (collider.first.GetType())
{
case SHCollider::Type::BOX:
bound = gcnew BoxColliderBound(i, Owner.GetEntity());
break;
case SHCollider::Type::SPHERE:
bound = gcnew SphereColliderBound(i, Owner.GetEntity());
break;
case SHCollider::Type::CAPSULE:
// TODO
break;
default:
Debug::LogWarning("[Collider] An invalid Collider Type was detected. Skipping.");
break;
}
++i;
// Add into list
subColliderList->Add(bound);
}
}
}

View File

@ -0,0 +1,41 @@
/************************************************************************************//*!
\file Collider.h++
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 20, 2022
\brief Contains the definition of templated functions for the managed Collider
and related classes.
Note: This file is written in C++17/CLI.
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.
*//*************************************************************************************/
#pragma once
// Primary Include
#include "Component.hxx"
namespace SHADE
{
template<typename ColliderBoundType>
ColliderBoundType& SHADE::ColliderBound::getNativeBoundObject()
{
SHColliderComponent* collider = SHComponentManager::GetComponent_s<SHColliderComponent>(entity);
if (!collider)
throw gcnew System::InvalidOperationException("Unable to retrieve Collider component!");
try
{
auto& bounds = collider->GetCollider(arrayIndex);
if (bounds.GetType() != SHCollider::Type::BOX)
throw gcnew System::InvalidOperationException("Attempted to retrieve invalid ColliderBound.");
return reinterpret_cast<ColliderBoundType&>(bounds);
}
catch (std::invalid_argument&)
{
throw gcnew System::IndexOutOfRangeException("Attempted to retrieve out of range ColliderBound!");
}
}
}

View File

@ -0,0 +1,264 @@
/************************************************************************************//*!
\file Collider.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 20, 2022
\brief Contains the definition of the managed Collider class with the
declaration of functions for working with it.
Note: This file is written in C++17/CLI.
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.
*//*************************************************************************************/
#pragma once
// External Dependencies
#include "Physics/Components/SHColliderComponent.h"
// Project Includes
#include "Components/Component.hxx"
#include "Math/Vector3.hxx"
#include "Utility/Convert.hxx"
#include "Math/Ray.hxx"
namespace SHADE
{
/// <summary>
/// Base interface for all Collider Shapes.
/// </summary>
public ref class ColliderBound
{
public:
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Checks if the specified point is within this shape's bounds.
/// </summary>
/// <param name="point">Point to test with.</param>
/// <returns>True if the point is in the shape's bounds.</returns>
virtual bool TestPoint(Vector3 point) = 0;
/// <summary>
/// Computes a Raycast and checks if there is a collision with any object.
/// </summary>
/// <param name="ray">The ray to cast.</param>
/// <param name="maxDistance">Maximum distance for the raycast check.</param>
/// <returns>True if the ray intersects with an object in the scene.</returns>
virtual bool Raycast(Ray ray, float maxDistance) = 0;
protected:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
ColliderBound(int arrayIdx, Entity attachedEntity);
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
int arrayIndex; // Index into the colliders vector on the native object
Entity entity; // Entity holding the collider component that this collider bounds is on
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
template<typename ColliderBoundType>
ColliderBoundType& getNativeBoundObject();
internal:
/*-----------------------------------------------------------------------------*/
/* Setter Functions */
/*-----------------------------------------------------------------------------*/
void updateArrayIndex(int index);
};
/// <summary>
/// Box-shaped Collider Bound.
/// </summary>
public ref class BoxColliderBound : public ColliderBound
{
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Center of the Bounding Box formed by this bound.
/// </summary>
property Vector3 Center
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Half of the scale of the Bounding Box formed by this bound.
/// </summary>
property Vector3 HalfExtents
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Position of the bottom left back corner of the Bounding Box formed by this
/// bound.
/// </summary>
property Vector3 Min
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Position of the top right front corner of the Bounding Box formed by this
/// bound.
/// </summary>
property Vector3 Max
{
Vector3 get();
void set(Vector3 value);
}
/*-----------------------------------------------------------------------------*/
/* ColliderBound Functions */
/*-----------------------------------------------------------------------------*/
/// <inheritdoc/>
bool TestPoint(Vector3 point) override;
/// <inheritdoc/>
bool Raycast(Ray ray, float maxDistance) override;
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
BoxColliderBound(int arrayIndex, Entity attachedEntity);
};
/// <summary>
/// Sphere-shaped Collider Bound.
/// </summary>
public ref class SphereColliderBound : public ColliderBound
{
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Center of the Bounding Sphere formed by this bound.
/// </summary>
property Vector3 Center
{
Vector3 get();
void set(Vector3 value);
}
/// <summary>
/// Radius of the Bounding Sphere formed by this bound.
/// </summary>
property float Radius
{
float get();
void set(float value);
}
/*-----------------------------------------------------------------------------*/
/* ColliderBound Functions */
/*-----------------------------------------------------------------------------*/
/// <inheritdoc/>
bool TestPoint(Vector3 point) override;
/// <inheritdoc/>
bool Raycast(Ray ray, float maxDistance) override;
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
SphereColliderBound(int arrayIndex, Entity attachedEntity);
};
/// <summary>
/// CLR version of the the SHADE Engine's SHColliderComponent.
/// A single Collider component can contain one or multiple Collider Bounds.
/// </summary>
public ref class Collider : public Component<SHColliderComponent>
{
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructs a Collider Component that represents a native SHColliderComponent
/// component tied to the specified Entity.
/// </summary>
/// <param name="entity">Entity that this Component will be tied to.</param>
Collider(Entity entity);
public:
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Total number of ColliderBounds in the Collider component.
/// </summary>
property int ColliderBoundsCount
{
int get();
}
/*-----------------------------------------------------------------------------*/
/* Usage Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Retrieves a ColliderBound at the specified index in the ColliderBound list.
/// </summary>
/// <param name="index">Index to retrieve a ColliderBound from.</param>
/// <returns>ColliderBound for the specified index.</returns>
ColliderBound^ GetColliderBound(int index);
/// <summary>
/// Retrieves a ColliderBound at the specified index in the ColliderBound list
/// and casts it to the appropriate type.
/// </summary>
/// <typeparam name="T">Type of the ColliderBound to cast to.</typeparam>
/// <param name="index">Index to retrieve a ColliderBound from.</param>
/// <returns>ColliderBound for the specified index.</returns>
generic<typename T> where T:ColliderBound
T GetColliderBound(int index);
internal:
/*-----------------------------------------------------------------------------*/
/* Event Handling Functions */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// To be called from native code when a collider has been removed.
/// </summary>
/// <param name="entity">The entity which has it's collider removed.</param>
static void OnColliderRemoved(EntityID entity);
/// <summary>
/// To be called from native code when a Collider bound has been removed.
/// </summary>
/// <param name="entity">
/// The entity which has it's collider bounds changed.
/// </param>
static void OnColliderBoundChanged(EntityID entity);
private:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
using WeakReferenceList = System::Collections::Generic::List<System::WeakReference^>;
using CollidersMap = System::Collections::Generic::Dictionary<EntityID, WeakReferenceList^>;
/*-----------------------------------------------------------------------------*/
/* Static Data Members */
/*-----------------------------------------------------------------------------*/
static CollidersMap^ colliders;
/*-----------------------------------------------------------------------------*/
/* Data Members */
/*-----------------------------------------------------------------------------*/
System::Collections::Generic::List<ColliderBound^>^ subColliderList;
/*-----------------------------------------------------------------------------*/
/* Helper Functions */
/*-----------------------------------------------------------------------------*/
void updateSubColliderList();
};
}
#include "Collider.h++"

View File

@ -0,0 +1,197 @@
/************************************************************************************//*!
\file RigidBody.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 22, 2022
\brief Contains the definition of the functions of the managed RigidBody class.
Note: This file is written in C++17/CLI.
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.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "RigidBody.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
RigidBody::RigidBody(Entity entity)
: Component(entity)
{}
/*---------------------------------------------------------------------------------*/
/* Properties */
/*---------------------------------------------------------------------------------*/
bool RigidBody::IsGravityEnabled::get()
{
return GetNativeComponent()->IsGravityEnabled();
}
void RigidBody::IsGravityEnabled::set(bool value)
{
return GetNativeComponent()->SetGravityEnabled(value);
}
bool RigidBody::IsAllowedToSleep::get()
{
return GetNativeComponent()->IsAllowedToSleep();
}
void RigidBody::IsAllowedToSleep::set(bool value)
{
return GetNativeComponent()->SetIsAllowedToSleep(value);
}
RigidBody::Type RigidBody::BodyType::get()
{
return static_cast<Type>(GetNativeComponent()->GetType());
}
void RigidBody::BodyType::set(Type value)
{
return GetNativeComponent()->SetType(static_cast<SHRigidBodyComponent::Type>(value));
}
float RigidBody::Mass::get()
{
return GetNativeComponent()->GetMass();
}
void RigidBody::Mass::set(float value)
{
return GetNativeComponent()->SetMass(value);
}
float RigidBody::Drag::get()
{
return GetNativeComponent()->GetDrag();
}
void RigidBody::Drag::set(float value)
{
return GetNativeComponent()->SetDrag(value);
}
float RigidBody::AngularDrag::get()
{
return GetNativeComponent()->GetAngularDrag();
}
void RigidBody::AngularDrag::set(float value)
{
return GetNativeComponent()->SetAngularDrag(value);
}
bool RigidBody::FreezePositionX::get()
{
return GetNativeComponent()->GetFreezePositionX();
}
void RigidBody::FreezePositionX::set(bool value)
{
return GetNativeComponent()->SetFreezePositionX(value);
}
bool RigidBody::FreezePositionY::get()
{
return GetNativeComponent()->GetFreezePositionY();
}
void RigidBody::FreezePositionY::set(bool value)
{
return GetNativeComponent()->SetFreezePositionY(value);
}
bool RigidBody::FreezePositionZ::get()
{
return GetNativeComponent()->GetFreezePositionZ();
}
void RigidBody::FreezePositionZ::set(bool value)
{
return GetNativeComponent()->SetFreezePositionZ(value);
}
bool RigidBody::FreezeRotationX::get()
{
return GetNativeComponent()->GetFreezeRotationX();
}
void RigidBody::FreezeRotationX::set(bool value)
{
return GetNativeComponent()->SetFreezeRotationX(value);
}
bool RigidBody::FreezeRotationY::get()
{
return GetNativeComponent()->GetFreezeRotationY();
}
void RigidBody::FreezeRotationY::set(bool value)
{
return GetNativeComponent()->SetFreezeRotationY(value);
}
bool RigidBody::FreezeRotationZ::get()
{
return GetNativeComponent()->GetFreezeRotationZ();
}
void RigidBody::FreezeRotationZ::set(bool value)
{
return GetNativeComponent()->SetFreezeRotationZ(value);
}
Vector3 RigidBody::LinearVelocity::get()
{
return Convert::ToCLI(GetNativeComponent()->GetLinearVelocity());
}
void RigidBody::LinearVelocity::set(Vector3 value)
{
return GetNativeComponent()->SetLinearVelocity(Convert::ToNative(value));
}
Vector3 RigidBody::AngularVelocity::get()
{
return Convert::ToCLI(GetNativeComponent()->GetAngularVelocity());
}
void RigidBody::AngularVelocity::set(Vector3 value)
{
return GetNativeComponent()->SetAngularVelocity(Convert::ToNative(value));
}
Vector3 RigidBody::Force::get()
{
return Convert::ToCLI(GetNativeComponent()->GetForce());
}
Vector3 RigidBody::Torque::get()
{
return Convert::ToCLI(GetNativeComponent()->GetTorque());
}
/*---------------------------------------------------------------------------------*/
/* Force Functions */
/*---------------------------------------------------------------------------------*/
void RigidBody::AddForce(Vector3 force)
{
GetNativeComponent()->AddForce(Convert::ToNative(force));
}
void RigidBody::AddForceAtLocalPos(Vector3 force, Vector3 localPos)
{
GetNativeComponent()->AddForceAtLocalPos(Convert::ToNative(force), Convert::ToNative(localPos));
}
void RigidBody::AddForceAtWorldPos(Vector3 force, Vector3 worldPos)
{
GetNativeComponent()->AddForceAtWorldPos(Convert::ToNative(force), Convert::ToNative(worldPos));
}
void RigidBody::AddRelativeForce(Vector3 relativeForce)
{
GetNativeComponent()->AddRelativeForce(Convert::ToNative(relativeForce));
}
void RigidBody::AddRelativeForceAtLocalPos(Vector3 relativeForce, Vector3 localPos)
{
GetNativeComponent()->AddRelativeForceAtLocalPos(Convert::ToNative(relativeForce), Convert::ToNative(localPos));
}
void RigidBody::AddRelativeForceAtWorldPos(Vector3 relativeForce, Vector3 worldPos)
{
GetNativeComponent()->AddRelativeForceAtWorldPos(Convert::ToNative(relativeForce), Convert::ToNative(worldPos));
}
/*---------------------------------------------------------------------------------*/
/* Torque Functions */
/*---------------------------------------------------------------------------------*/
void RigidBody::AddTorque(Vector3 torque)
{
GetNativeComponent()->AddTorque(Convert::ToNative(torque));
}
void RigidBody::AddRelativeTorque(Vector3 relativeTorque)
{
GetNativeComponent()->AddRelativeTorque(Convert::ToNative(relativeTorque));
}
}

View File

@ -0,0 +1,150 @@
/************************************************************************************//*!
\file RigidBody.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 22, 2022
\brief Contains the definition of the managed Collider class with the
declaration of functions for working with it.
Note: This file is written in C++17/CLI.
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.
*//*************************************************************************************/
#pragma once
// External Dependencies
#include "Physics/Components/SHRigidBodyComponent.h"
// Project Includes
#include "Components/Component.hxx"
namespace SHADE
{
/// <summary>
/// CLR version of the the SHADE Engine's SHRigidBodyComponent.
/// </summary>
public ref class RigidBody : public Component<SHRigidBodyComponent>
{
internal:
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Constructs a RigidBody Component that represents a native
/// SHRigidBodyComponent component tied to the specified Entity.
/// </summary>
/// <param name="entity">Entity that this Component will be tied to.</param>
RigidBody(Entity entity);
public:
/*-----------------------------------------------------------------------------*/
/* Type Definitions */
/*-----------------------------------------------------------------------------*/
enum class Type
{
Static,
Kinematic,
Dynamic
};
/*-----------------------------------------------------------------------------*/
/* Properties */
/*-----------------------------------------------------------------------------*/
property bool IsGravityEnabled
{
bool get();
void set(bool value);
}
property bool IsAllowedToSleep
{
bool get();
void set(bool value);
}
property Type BodyType
{
Type get();
void set(Type value);
}
property float Mass
{
float get();
void set(float value);
}
property float Drag
{
float get();
void set(float value);
}
property float AngularDrag
{
float get();
void set(float value);
}
property bool FreezePositionX
{
bool get();
void set(bool value);
}
property bool FreezePositionY
{
bool get();
void set(bool value);
}
property bool FreezePositionZ
{
bool get();
void set(bool value);
}
property bool FreezeRotationX
{
bool get();
void set(bool value);
}
property bool FreezeRotationY
{
bool get();
void set(bool value);
}
property bool FreezeRotationZ
{
bool get();
void set(bool value);
}
property Vector3 LinearVelocity
{
Vector3 get();
void set(Vector3 value);
}
property Vector3 AngularVelocity
{
Vector3 get();
void set(Vector3 value);
}
property Vector3 Force
{
Vector3 get();
}
property Vector3 Torque
{
Vector3 get();
}
/*-----------------------------------------------------------------------------*/
/* Force Functions */
/*-----------------------------------------------------------------------------*/
void AddForce(Vector3 force);
void AddForceAtLocalPos(Vector3 force, Vector3 localPos);
void AddForceAtWorldPos(Vector3 force, Vector3 worldPos);
void AddRelativeForce(Vector3 relativeForce);
void AddRelativeForceAtLocalPos(Vector3 relativeForce, Vector3 localPos);
void AddRelativeForceAtWorldPos(Vector3 relativeForce, Vector3 worldPos);
/*-----------------------------------------------------------------------------*/
/* Torque Functions */
/*-----------------------------------------------------------------------------*/
void AddTorque(Vector3 force);
void AddRelativeTorque(Vector3 relativeForce);
};
}

View File

@ -68,36 +68,36 @@ using namespace System::Collections::Generic;
/// <param name="MANAGED_TYPE">The managed type of the object to edit.</param>
/// <param name="NATIVE_TYPE">The native type of the object to edit.</param>
/// <param name="FUNC">The SHEditorUI:: function to use for editing.</param>
#define RENDER_FIELD_RANGE(MANAGED_TYPE, NATIVE_TYPE, FUNC) \
(field->FieldType == MANAGED_TYPE::typeid) \
{ \
NATIVE_TYPE val = safe_cast<NATIVE_TYPE>(field->GetValue(object)); \
NATIVE_TYPE oldVal = val; \
\
RangeAttribute^ rangeAttrib = hasAttribute<RangeAttribute^>(field); \
const std::string FIELD_NAME = Convert::ToNative(field->Name); \
bool changed = false; \
if (rangeAttrib) \
{ \
changed = SHEditorUI::InputSlider \
( \
FIELD_NAME, \
static_cast<NATIVE_TYPE>(rangeAttrib->Min), \
static_cast<NATIVE_TYPE>(rangeAttrib->Max), \
val, &isHovered \
); \
} \
else \
{ \
changed = SHEditorUI::FUNC(FIELD_NAME, val, &isHovered); \
} \
\
if (changed) \
{ \
field->SetValue(object, val); \
registerUndoAction(object, field, val, oldVal); \
} \
} \
#define RENDER_FIELD_RANGE(MANAGED_TYPE, NATIVE_TYPE, FUNC) \
(field->FieldType == MANAGED_TYPE::typeid) \
{ \
NATIVE_TYPE val = safe_cast<NATIVE_TYPE>(field->GetValue(object)); \
NATIVE_TYPE oldVal = val; \
\
RangeAttribute^ rangeAttrib = hasAttribute<RangeAttribute^>(field);\
const std::string FIELD_NAME = Convert::ToNative(field->Name); \
bool changed = false; \
if (rangeAttrib) \
{ \
changed = SHEditorUI::InputSlider \
( \
FIELD_NAME, \
static_cast<NATIVE_TYPE>(rangeAttrib->Min), \
static_cast<NATIVE_TYPE>(rangeAttrib->Max), \
val, &isHovered \
); \
} \
else \
{ \
changed = SHEditorUI::FUNC(FIELD_NAME, val, &isHovered); \
} \
\
if (changed) \
{ \
field->SetValue(object, val); \
registerUndoAction(object, field, val, oldVal); \
} \
} \
/// <summary>
/// Macro expansion that is used in renderFieldInInspector() to check the type of a field
/// named "field" against the specified type and if it matches, retrieves the value of
@ -197,7 +197,7 @@ namespace SHADE
void Editor::renderScriptInInspector(Entity entity, Script^ script, int index)
{
// Constants
const std::string LABEL = Convert::ToNative(script->GetType()->Name);
const std::string LABEL = Convert::ToNative(script->GetType()->Name);
// Header
SHEditorUI::PushID(index);
@ -286,6 +286,76 @@ namespace SHADE
registerUndoAction(object, field, Convert::ToCLI(val), Convert::ToCLI(oldVal));
}
}
else
{
array<System::Type^>^ interfaces = field->FieldType->GetInterfaces();
if (interfaces->Length > 0 && interfaces[0] == ICallbackEvent::typeid)
{
array<System::Type^>^ typeArgs = field->FieldType->GenericTypeArguments;
System::String^ title = field->Name + " : CallbackEvent<";
for (int i = 0; i < typeArgs->Length; ++i)
{
title += typeArgs[i]->Name;
if (i < typeArgs->Length - 1)
title += ", ";
}
title += ">";
if (SHEditorUI::CollapsingHeader(Convert::ToNative(title)))
{
// Constants
const std::string LABEL = Convert::ToNative(field->Name);
SHEditorUI::PushID(LABEL);
ICallbackEvent^ callbackEvent = safe_cast<ICallbackEvent^>(field->GetValue(object));
if (callbackEvent == nullptr)
{
// Construct one since it was not constructed before
callbackEvent = safe_cast<ICallbackEvent^>(System::Activator::CreateInstance(field->FieldType));
}
for each (ICallbackAction ^ action in callbackEvent->Actions)
{
if (action->IsRuntimeAction)
continue;
// Attempt to get the object if any
int entityId = static_cast<int>(-1);
if (action->TargetObject)
{
Script^ script = safe_cast<Script^>(action->TargetObject);
if (script)
{
entityId = static_cast<int>(script->Owner.GetEntity());
}
}
SHEditorUI::InputInt("", entityId);
SHEditorUI::SameLine();
System::String^ methodName = "";
if (action->TargetMethodName != nullptr)
{
methodName = action->TargetMethodName;
}
std::string methodNameNative = Convert::ToNative(methodName);
SHEditorUI::InputTextField("", methodNameNative);
SHEditorUI::SameLine();
if (SHEditorUI::Button("-"))
{
callbackEvent->DeregisterAction(action);
break;
}
}
if (SHEditorUI::Button("Add Action"))
{
callbackEvent->RegisterAction();
}
SHEditorUI::PopID();
}
}
else
{
return;
}
}
// Check if the field has a specific attribute
TooltipAttribute^ toolTip = hasAttribute<TooltipAttribute^>(field);

View File

@ -22,6 +22,8 @@ of DigiPen Institute of Technology is prohibited.
// External Dependencies
#include "ECS_Base/Managers/SHEntityManager.h"
#include "Math/Transform/SHTransformComponent.h"
#include "Physics\Components\SHColliderComponent.h"
#include "Physics\Components\SHRigidBodyComponent.h"
#include "Scene/SHSceneManager.h"
#include "Scene/SHSceneGraph.h"
#include "Tools/SHLog.h"
@ -29,6 +31,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Utility/Convert.hxx"
#include "Utility/Debug.hxx"
#include "Components/Transform.hxx"
#include "Components\RigidBody.hxx"
#include "Components\Collider.hxx"
namespace SHADE
{
@ -242,6 +246,8 @@ namespace SHADE
static ECS::ECS()
{
componentMap.Add(createComponentSet<SHTransformComponent, Transform>());
componentMap.Add(createComponentSet<SHColliderComponent, Collider>());
componentMap.Add(createComponentSet<SHRigidBodyComponent, RigidBody>());
}
/*---------------------------------------------------------------------------------*/

View File

@ -0,0 +1,28 @@
/************************************************************************************//*!
\file Ray.cxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 20, 2022
\brief Contains the definitions of functions of the Vector2 struct.
Note: This file is written in C++17/CLI.
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.
*//*************************************************************************************/
// Precompiled Headers
#include "SHpch.h"
// Primary Header
#include "Math/Ray.hxx"
namespace SHADE
{
/*---------------------------------------------------------------------------------*/
/* Constructors */
/*---------------------------------------------------------------------------------*/
Ray::Ray(Vector3 origin, Vector3 direction)
: Origin { origin }
, Direction{ direction }
{}
}

View File

@ -0,0 +1,50 @@
/************************************************************************************//*!
\file Ray.hxx
\author Tng Kah Wei, kahwei.tng, 390009620
\par email: kahwei.tng\@digipen.edu
\date Oct 20, 2021
\brief Contains the definitions of Vector2 struct.
Note: This file is written in C++17/CLI.
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.
*//*************************************************************************************/
#pragma once
// Project Includes
#include "Vector3.hxx"
namespace SHADE
{
///<summary>
/// CLR version of the the SHADE Engine's Ray class that represents a ray in
/// 3-Dimensional space.
/// </summary>
public value struct Ray
{
public:
/*-----------------------------------------------------------------------------*/
/* Public Members */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// The start point of the ray.
/// </summary>
Vector3 Origin;
/// <summary>
/// The direction that a ray travels in.
/// </summary>
Vector3 Direction;
/*-----------------------------------------------------------------------------*/
/* Constructors */
/*-----------------------------------------------------------------------------*/
/// <summary>
/// Creates a ray starting at origin along direction.
/// </summary>
/// <param name="origin">Source of the ray.</param>
/// <param name="direction">Direction the ray travels in.</param>
Ray(Vector3 origin, Vector3 direction);
};
}

View File

@ -132,7 +132,7 @@ namespace SHADE
/// Immutable list of references to scripts of the specified type.
/// </returns>
generic<typename T> where T : ref class, Script
static System::Collections::Generic::IEnumerable<T> ^ GetScripts(Entity entity);
static System::Collections::Generic::IEnumerable<T>^ GetScripts(Entity entity);
/// <summary>
/// Retrieves an immutable list of all scripts attached to a specified Entity.
/// </summary>
@ -295,4 +295,4 @@ namespace SHADE
static System::Type^ getScriptType(System::String^ scriptName);
static bool isEntityActive(Entity entity);
};
} // namespace PlushieAPI
}

View File

@ -37,6 +37,7 @@ namespace SHADE
{
return SHVec3(vec.x, vec.y, vec.z);
}
Vector3 Convert::ToCLI(const SHVec3& vec)
{
return Vector3(vec.x, vec.y, vec.z);
@ -53,12 +54,22 @@ namespace SHADE
SHQuaternion Convert::ToNative(Quaternion quat)
{
return SHQuaternion{ quat.x, quat.y, quat.z, quat.w };
return SHQuaternion{ quat.x, quat.y, quat.z, quat.w };
}
Quaternion Convert::ToCLI(const SHQuaternion& quat)
{
return Quaternion{ quat.x, quat.y, quat.z, quat.w };
return Quaternion{ quat.x, quat.y, quat.z, quat.w };
}
SHRay Convert::ToNative(Ray vec)
{
return SHRay(ToNative(vec.Origin), ToNative(vec.Direction));
}
Ray Convert::ToCLI(const SHRay& vec)
{
return Ray(ToCLI(vec.position), ToCLI(vec.direction));
}
/*---------------------------------------------------------------------------------*/
@ -73,4 +84,4 @@ namespace SHADE
{
return msclr::interop::marshal_as<System::String^>(str);
}
} // namespace PlushieAPI
}

View File

@ -19,11 +19,14 @@ of DigiPen Institute of Technology is prohibited.
#include "Math/Vector/SHVec2.h"
#include "Math/Vector/SHVec3.h"
#include "Math/SHQuaternion.h"
#include "Math/SHRay.h"
// Project Includes
#include "Engine/Entity.hxx"
#include "Math/Vector2.hxx"
#include "Math/Vector3.hxx"
#include "Math/Quaternion.hxx"
#include "Math/Ray.hxx"
namespace SHADE
{
@ -88,6 +91,17 @@ namespace SHADE
/// <param name="quat">The native Quaternion to convert from.</param>
/// <returns>Managed copy of a native Quaternion.</returns>
static Quaternion ToCLI(const SHQuaternion& quat);
/// Converts from a managed Vector2 to a native Vector2.
/// </summary>
/// <param name="vec">The managed Vector2 to convert from.</param>
/// <returns>Native copy of a managed Vector2.</returns>
static SHRay ToNative(Ray vec);
/// <summary>
/// Converts from a native Vector2 to a managed Vector2.
/// </summary>
/// <param name="vec">The native Vector2 to convert from.</param>
/// <returns>Managed copy of a native Vector2.</returns>
static Ray ToCLI(const SHRay& vec);
/*-----------------------------------------------------------------------------*/
/* String Conversions */

View File

@ -0,0 +1,43 @@
using SHADE;
using System;
public class PhysicsTest : Script
{
[SerializeField]
[Tooltip("Force to apply when pressing Space.")]
private Vector3 Force = new Vector3(0.0f, 200.0f, 0.0f);
private Transform Transform;
private RigidBody RigidBody;
private Collider Collider;
public PhysicsTest(GameObject gameObj) : base(gameObj) { }
protected override void awake()
{
Transform = GetComponent<Transform>();
if (Transform == null)
{
Debug.LogError("Transform is NULL!");
}
RigidBody = GetComponent<RigidBody>();
if (RigidBody == null)
{
Debug.LogError("RigidBody is NULL!");
}
Collider = GetComponent<Collider>();
if (Collider == null)
{
Debug.LogError("Collider is NULL!");
}
var subColider = Collider.ColliderBoundsCount;
Debug.Log($"There are {subColider} colliders.");
}
protected override void update()
{
if (Input.GetKeyUp(Input.KeyCode.Space))
{
RigidBody.AddForce(Force);
Debug.Log($"Jump!");
}
Debug.Log($"{Transform.LocalPosition.y}");
}
}

View File

@ -12,7 +12,7 @@ public class RaccoonShowcase : Script
//private int test = 5;
[SerializeField]
[Tooltip("Speed of the scaling in radians per second around each axis.")]
private Vector3 ScaleSpeed = new Vector3(1.0, 1.0, 0.0);
private Vector3 ScaleSpeed = Vector3.One;
private Transform Transform;
private double rotation = 0.0;
private Vector3 scale = Vector3.Zero;
@ -31,9 +31,9 @@ public class RaccoonShowcase : Script
}
protected override void update()
{
rotation += RotateSpeed * 0.16;
scale += ScaleSpeed * 0.16;
Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f);
Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale);
//rotation += RotateSpeed * 0.16;
//scale += ScaleSpeed * 0.16;
//Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f);
//Transform.LocalScale = new Vector3(System.Math.Abs(System.Math.Sin(scale.x)) * originalScale, System.Math.Abs(System.Math.Cos(scale.y)) * originalScale, System.Math.Abs(System.Math.Sin(scale.z)) * originalScale);
}
}

View File

@ -5,8 +5,12 @@ public class RaccoonSpin : Script
{
[SerializeField]
[Tooltip("Speed of the rotation in radians per second.")]
private double RotateSpeed = 1.0;
private double rotation = 0.0;
private float RotateSpeed = 1.0f;
private float rotation = 0.0f;
[SerializeField]
private CallbackEvent<int> testEvent;
[SerializeField]
private CallbackEvent<int, double, Vector3> testEvent3 = new CallbackEvent<int, double, Vector3>();
private Transform Transform;
public RaccoonSpin(GameObject gameObj) : base(gameObj) { }
@ -18,9 +22,4 @@ public class RaccoonSpin : Script
Debug.LogError("Transform is NULL!");
}
}
protected override void update()
{
rotation += RotateSpeed * 0.16;
Transform.LocalRotation = new Vector3(0.0f, rotation, 0.0f);
}
}

View File

@ -22,6 +22,7 @@ workspace "SHADE"
include "SHADE_Engine"
include "SHADE_Application"
include "SHADE_Managed"
include "SHADE_CSharp"
group "Dependencies"
include "Dependencies/msdf"