原生脚本是一种使用与游戏引擎相同语言(一般是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