Skip to content

tongtunggiang/unity-entt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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