显然我们不可能每次都在cpp代码中控制引擎中的某些参数,我们需要做一个像C#、Lua那样的脚本语言去连接引擎里的内容。这里还是先支持c++,后续考虑扩展
QA¶
-
为什么需要添加cpp脚本组件
-
引擎开发人员需要给引擎某个实体添加脚本功能,从而实现测试时候能运行想要的脚本功能。
比如:像Unity那样在Scene界面,摄像机可以自由移动,这是内置脚本功能,肯定是使用原生cpp语言来实现的
-
使用这引擎的游戏开发人员有的人不喜欢用c#,想用cpp来实现脚本编写。
ScriptableEntity¶
- 提供getcomponent方法
- 提供友元
- 提供组件的实体引用
-
#pragma once
#include "Entity.h"
namespace CryDust {
class ScriptableEntity
{
public:
template<typename T>
T& GetComponent()
{
return m_Entity.GetComponent<T>();
}
private:
Entity m_Entity;
friend class Scene;
};
}
component新增¶
好像不是很ecs啊,要new和delete。 不过还是有的,指针变量啥的
构成¶
- 五个生命周期的函数指针
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); }; } };
Scene里update更新¶
- 创建时调用一下创建方法
- 更新的时候则循环调用
// Update scripts { 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); }); }
本地脚本(Editor的Onattach方法中实现)¶
//本地腳本 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; } }; m_CameraEntity.AddComponent<NativeScriptComponent>().Bind<CameraController>();
Lambda¶
我们在外面绑定脚本语言,
m_CameraEntity.AddComponent<NativeScriptComponent>().Bind<CameraController>();
c++
OnCreateFunction = [](ScriptableEntity* instance) { ((T*)instance)->OnCreate(); };
OnDestroyFunction = [](ScriptableEntity* instance) { ((T*)instance)->OnDestroy(); };
OnUpdateFunction = [](ScriptableEntity* instance, Timestep ts) { ((T*)instance)->OnUpdate(ts); };