Just a little tech demo of a native simulation layer written in C++ using EnTT and Unity as a rendering engine.
Remember to clone the repo with submodules
git clone --recurse-submodules -j8 <repo-link>
For VS2019, run NativeScript/Targets/Generators/VS2019.bat
.
Alternatively, you can run CMake to generate the VS solution suitable to the version you have using command line:
cmake -S ../.. -B ../VS2019 -G "Visual Studio 16 2019" -DCMAKE_CONFIGURATION_TYPES="Debug;Release;" -DEDITOR=ON
Visual Studio solution is now generated in NativeScript/Targets/VS2019/NativeScript.sln
.
All simulation code files are currently be stored inside NativeScript/Source/Simulation
, with the components are structs prefixed with C
and systems are free functions prefixed with S
. Component structs only support primitive types for now to make sure that they are generated properly on the C# side.
Example:
struct CPosition { Vector3 value; }
void SUpdateMoveForward(Registry& registry, float deltaTime)
{
PROFILER_FUNCTION();
registry.view<CPosition, COrientation, CMoveSpeed>().each(
[deltaTime](auto entity, CPosition& position, const COrientation& orientation, const CMoveSpeed& moveSpeed)
{
position.value += deltaTime * moveSpeed.value * orientation.value;
}
);
PROFILER_END();
}
Structs are parsed and generated to C# counterparts in the precompile stage of the native layer, writing to ECSBindings.cpp/cs as it succeeds.
public struct CPosition
{
public Vector3 value;
}
class ECSBindings
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate CPosition GetPositionType(UInt32 entity);
public static GetPositionType GetPosition;
//....
public static void Load()
{
GetPosition = Bindings.GetDelegate<GetPositionType>(libraryHandle, "GetPosition");
}
}
With the component struct all properly compiled, generated and ready for interopping, the final piece of the puzzle is to render it with Unity.
[RequireComponent(typeof(Native.BaseNativeEntityView))]
public class EntityPositionView : MonoBehaviour
{
[SerializeField] bool m_UpdateOnce;
[SerializeField] bool m_ViewPosition;
[SerializeField] bool m_ViewOrientation;
Native.BaseNativeEntityView m_View;
void Start()
{
m_View = GetComponent<Native.BaseNativeEntityView>();
}
void Update()
{
if (m_ViewPosition)
{
Vector3 pos = ECSBindings.GetPosition(m_View.EntityRef).value;
transform.position = new Vector3(pos.x, pos.y, pos.z);
}
if (m_ViewOrientation)
{
Vector3 orientation = ECSBindings.GetOrientation(m_View.EntityRef).value;
transform.forward = new Vector3(orientation.x, orientation.y, orientation.z);
}
if (m_UpdateOnce)
{
enabled = false;
}
}
}
- The awesome ECS library EnTT.
- Jackson Dunstan's C++ Scripting series.