WAYNETS.ORG

Game and Program

原生脚本

作者:

发表于

Context Polling System Post-Processing Renderer

原生脚本是一种使用与游戏引擎相同语言(一般是C++)编写的游戏行为逻辑代码,它们:

  • 直接编译到游戏程序中(不像C#或Lua需要解释器或虚拟机)
  • 性能非常高,没有跨语言调用开销
  • 通过注册机制与引擎内部数据打通

脚本基类ScriptableEntity

所有挂在Entity上的脚本都应该继承它。该类的主要作用是为脚本类提供一种简单、安全的方式访问其所在Entity的Component

class ScriptableEntity
{
public:
	template<typename T>
	T& GetComponent()
	{
            return m_Entity.GetComponent<T>();
	}
private:
	Entity m_Entity;
	friend class Scene;
};

脚本组件

这个组件用于添加到Entity上。它使得你可以将一个继承自ScriptableEntity的 C++ 类(比如PlayerScript)挂载到某个 Entity 上,并在运行时自动实例化/销毁/调用生命周期函数

struct NativeScriptComponent
{
	ScriptableEntity* Instance = nullptr; // 脚本类运行时的实例

	std::function<void()> InstantiateFunction;     // 生成脚本类的实例
	std::function<void()> DestroyInstanceFunction; // 销毁脚本类的实例

	std::function<void(ScriptableEntity*)> OnCreateFunction;
	std::function<void(ScriptableEntity*)> OnDestroyFunction;
	std::function<void(ScriptableEntity*, TimeStep)> OnUpdateFunction;

	template<typename T>
	void Bind()
	{
		InstantiateFunction = [&]() { Instance = new T(); };
		DestroyInstanceFunction = [&]() { delete (T*)Instance; Instance = nullptr; };

		OnCreateFunction = [](ScriptableEntity* instance) { ((T*)instance)->OnCreate(); };
		OnDestroyFunction = [](ScriptableEntity* instance) { ((T*)instance)->OnDestroy(); };
		OnUpdateFunction = [](ScriptableEntity* instance, TimeStep ts) { ((T*)instance)->OnUpdate(ts); };
	}
};

为Entity挂载一个脚本Component:

// 控制摄像机的脚本类
class CameraController : public ScriptableEntity
{
public:
	void OnCreate()
	{
	}

	void OnDestroy()
	{
	}

	void OnUpdate(TimeStep ts)
	{
		auto& transform = GetComponent<TransformComponent>().Transform;
		float speed = 5.0f;

		if (Input::IsKeyPressed(KeyCode::A))
			transform[3][0] -= speed * ts;
		if (Input::IsKeyPressed(KeyCode::D))
			transform[3][0] += speed * ts;
		if (Input::IsKeyPressed(KeyCode::W))
			transform[3][1] += speed * ts;
		if (Input::IsKeyPressed(KeyCode::S))
			transform[3][1] -= speed * ts;
	}
};

// 为摄像机Entity添加并绑定脚本类
m_CameraEntity.AddComponent<NativeScriptComponent>().Bind<CameraController>();

为Entity添加了脚本Component后,就可以在类Scene的函数OnUpdate()中调用了:

m_Registry.view<NativeScriptComponent>().each([=](auto entity, auto& nsc)
{
	if (!nsc.Instance)
	{
		nsc.InstantiateFunction();
		nsc.Instance->m_Entity = Entity{ entity, this };

		if (nsc.OnCreateFunction) nsc.OnCreateFunction(nsc.Instance);
	}

	if (nsc.OnUpdateFunction) nsc.OnUpdateFunction(nsc.Instance, ts);
});

Leave a comment