记录一些UE4文档以外编程相关的底层基础的概念和使用方法,如GC和Gameplay,各种宏/配置项等说明和使用
备查
文档:http://api.unrealengine.com/INT/Programming/index.html
Q. UE4 配置Game的默认UGameEngine类:
UGameEngine算是整个Game的入口类了(Editor模式时是UEditorEngine),
最初的Viewport的Layout都是通过GameEngine里进行生成的.
可不使用源码版本的情况下,可通过继承UGameEngine类,修改扩展初始化Game的初始化布局等功能:
step:
往DefaultEngine.ini的[/Script/Engine.Engine]下添加,如:
+GameEngine=/Script/BJShowEx.QGameEngine
Q. UE4 第三人称(SpringArm控制下)设置初始视口位置 :
Q. UE4的委托和事件(Delegate):
记一下,开发方便Copy.
吐槽:UE4 的Delegate得定义宏又臭又长又多,C#的委托和事件不知道比UE4高到哪里去了!(UE5请务必砍掉从新实现!)
快速索引:委托文档:https://docs.unrealengine.com/en-US/Programming/UnrealArchitecture/Delegates/index.html
概念:
从设计模式上来说 多播Delegate就是 观察者模式得实现,只不过C#集成到了语言特性上,刚好C#(QT single-slot)得方式 被UE4借鉴到了引擎里
Q0:C++是怎么去实现委托的?
链接:C++实现的类C# Delegate 参考: https://stackoverflow.com/questions/23973914/c-like-delegates-in-c
实现委托的代码:
/* 代码来着上述stackoverflow */ #include <algorithm> #include <iostream> #include <memory> #include <utility> #include <vector> template <typename Signature> struct delegate; template <typename... Args> struct delegate<void(Args...)> { struct base { virtual ~base() {} virtual bool do_cmp(base* other) = 0; virtual void do_call(Args... args) = 0; }; template <typename T> struct call : base { T d_callback; template <typename S> call(S&& callback) : d_callback(std::forward<S>(callback)) { } bool do_cmp(base* other) { call<T>* tmp = dynamic_cast<call<T>*>(other); return tmp && this->d_callback == tmp->d_callback; } void do_call(Args... args) { return this->d_callback(std::forward<Args>(args)...); } }; std::vector<std::unique_ptr<base>> d_callbacks; delegate(delegate const&) = delete; void operator=(delegate const&) = delete; public: delegate() { } template <typename T> delegate& operator+= (T&& callback) { this->d_callbacks.emplace_back(new call<T>(std::forward<T>(callback))); return *this; } template <typename T> delegate& operator-= (T&& callback) { call<T> tmp(std::forward<T>(callback)); auto it = std::remove_if(this->d_callbacks.begin(), this->d_callbacks.end(), [&](std::unique_ptr<base>& other) { return tmp.do_cmp(other.get()); }); this->d_callbacks.erase(it, this->d_callbacks.end()); return *this; } void operator()(Args... args) { for (auto& callback : this->d_callbacks) { callback->do_call(args...); } } }; // ---------------------------------------------------------------------------- template <typename RC, typename Class, typename... Args> class member_call { Class* d_object; RC(Class::* d_member)(Args...); public: member_call(Class* object, RC(Class::* member)(Args...)) : d_object(object) , d_member(member) { } RC operator()(Args... args) { return (d_object->*d_member)(std::forward<Args>(args)...); } bool operator== (member_call const& other) const { return (this->d_object == other.d_object) && (this->d_member == other.d_member); } bool operator!= (member_call const& other) const { return !(*this == other); } }; /** * @prarms RC 返回类型, Class **/ template <typename RC, typename Class, typename... Args> member_call<RC, Class, Args...> mem_call(Class& object, RC(Class::* member)(Args...)) { return member_call<RC, Class, Args...>(&object, member); } // ---------------------------------------------------------------------------- void f(char const* str) { std::cout << "f(" << str << ")\n"; } void g(char const* str) { std::cout << "g(" << str << ")\n"; } void h(char const* str) { std::cout << "h(" << str << ")\n"; } // ---------------------------------------------------------------------------- struct foo { int d_id; explicit foo(int id) : d_id(id) { } void bar(char const* str) { std::cout << "foo(" << this->d_id << ")::bar(" << str << ")\n"; } void cbs(char const* str) { std::cout << "foo(" << this->d_id << ")::cbs(" << str << ")\n"; } }; // ---------------------------------------------------------------------------- int main() { delegate<void(char const*)> d0; foo f0(0); foo f1(1); d0 += f; d0 += g; d0 += g; d0 += h; d0 += mem_call(f0, &foo::bar); d0 += mem_call(f0, &foo::cbs); d0 += mem_call(f1, &foo::bar); d0 += mem_call(f1, &foo::cbs); d0("first call"); d0 -= g; d0 -= mem_call(f0, &foo::cbs); d0 -= mem_call(f1, &foo::bar); d0("second call"); }