GitHub - tongtunggiang/unity-entt (original) (raw)

Introduction

Just a little tech demo of a native simulation layer written in C++ using EnTT and Unity as a rendering engine.

Cloning the project

Remember to clone the repo with submodules

git clone --recurse-submodules -j8 <repo-link>

Setup

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.

Getting Started

Native gameplay

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();

}

Code generator

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");
}

}

Unity side:

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;
    }
}

}

Useful resources