手把手教你架构3D引擎高级篇系列七

本文深入探讨了C++中委托的封装方法,介绍了如何使用模板实现通用委托,并封装了委托列表,便于管理和调用多个委托函数。适用于Unity开发者和C++引擎编程爱好者。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇博客主要是介绍关于委托的封装,本篇博客需要读者掌握如下几个技术点:
在这里插入图片描述学习技术文章方法很重要,任何人都有自己不懂的地方,我们在学习时,遇到不懂的,可以查阅网络资源或者书籍,这样通过不停的迭代学习,你才能不断的进步,最后成为技术达人,引擎模块的封装,也不是一朝一夕就能搞定的事情,量的积累才能达到质的提升。

前面封装了数据结构中常用算法,接下来给读者封装一个好用的东西——委托。使用过Unity开发的人知道,我们经常在项目中使用委托,类似我们说的回调。使用C#编写委托,其实质是什么呢?其实就是把委托的函数加到一个列表中,这样方便管理适合封装。我们在实现引擎的委托时,首先要清楚我们的委托面对的是所有类型的,因此很容想到使用模板解决问题。在实现委托时,我们在这里将它们分两个模块,一个是关于委托的,一个是委托列表。在这里我们用了模板指针,C++模板这块技术,读者一定要掌握,不论是客户端引擎还是服务器引擎都会大量使用模板的封装。委托的功能包括:绑定bind,另一个是解除绑定unbind。下面我们开始编写引擎委托和委托列表。

template <typename T> class Delegate;

template <typename R> class Delegate
{
private:
	typedef void* InstancePtr;
	typedef R (*InternalFunction)(InstancePtr);
	struct Stub
	{
		InstancePtr first;
		InternalFunction second;
	};

	template <R (*Function)()> static FORCE_INLINE R FunctionStub(InstancePtr) { return (Function)(); }

	template <class C, R (C::*Function)()> static FORCE_INLINE R ClassMethodStub(InstancePtr instance)
	{
		return (static_cast<C*>(instance)->*Function)();
	}

	template <class C, R (C::*Function)() const> static FORCE_INLINE R ClassMethodStub(InstancePtr instance)
	{
		return (static_cast<C*>(instance)->*Function)();
	}

public:
	Delegate()
	{
		m_stub.first = nullptr;
		m_stub.second = nullptr;
	}

	template <R (*Function)()> void bind()
	{
		m_stub.first = nullptr;
		m_stub.second = &FunctionStub<Function>;
	}

	template <class C, R (C::*Function)()> void bind(C* instance)
	{
		m_stub.first = instance;
		m_stub.second = &ClassMethodStub<C, Function>;
	}

	template <class C, R(C::*Function)() const> void bind(C* instance)
	{
		m_stub.first = instance;
		m_stub.second = &ClassMethodStub<C, Function>;
	}

	R invoke() const
	{
		ASSERT(m_stub.second != nullptr);
		return m_stub.second(m_stub.first);
	}

	bool operator==(const Delegate<R>& rhs)
	{
		return m_stub.first == rhs.m_stub.first && m_stub.second == rhs.m_stub.second;
	}

private:
	Stub m_stub;
};


template <typename R, typename... Args> class Delegate<R(Args...)>
{
private:
	typedef void* InstancePtr;
	typedef R (*InternalFunction)(InstancePtr, Args...);
	struct Stub
	{
		InstancePtr first;
		InternalFunction second;
	};

	template <R (*Function)(Args...)> static FORCE_INLINE R FunctionStub(InstancePtr, Args... args)
	{
		return (Function)(args...);
	}

	template <class C, R(C::*Function)(Args...)>
	static FORCE_INLINE R ClassMethodStub(InstancePtr instance, Args... args)
	{
		return (static_cast<C*>(instance)->*Function)(args...);
	}

	template <class C, R(C::*Function)(Args...) const>
	static FORCE_INLINE R ClassMethodStub(InstancePtr instance, Args... args)
	{
		return (static_cast<C*>(instance)->*Function)(args...);
	}

public:
	Delegate()
	{
		m_stub.first = nullptr;
		m_stub.second = nullptr;
	}

	bool isValid() { return m_stub.second != nullptr; }

	template <R (*Function)(Args...)> void bind()
	{
		m_stub.first = nullptr;
		m_stub.second = &FunctionStub<Function>;
	}

	template <class C, R (C::*Function)(Args...)> void bind(C* instance)
	{
		m_stub.first = instance;
		m_stub.second = &ClassMethodStub<C, Function>;
	}

	template <class C, R(C::*Function)(Args...) const> void bind(C* instance)
	{
		m_stub.first = instance;
		m_stub.second = &ClassMethodStub<C, Function>;
	}

	R invoke(Args... args) const
	{
		ASSERT(m_stub.second != nullptr);
		return m_stub.second(m_stub.first, args...);
	}

	bool operator==(const Delegate<R(Args...)>& rhs)
	{
		return m_stub.first == rhs.m_stub.first && m_stub.second == rhs.m_stub.second;
	}

private:
	Stub m_stub;
};

以上是我们引擎的委托类封装,下面我们实现委托列表封装,如下所示:

template <typename T> class DelegateList;

template <typename R, typename... Args> class DelegateList<R(Args...)>
{
public:
	explicit DelegateList(IAllocator& allocator)
		: m_delegates(allocator)
	{
	}

	template <typename C, R (C::*Function)(Args...)> void bind(C* instance)
	{
		Delegate<R(Args...)> cb;
		cb.template bind<C, Function>(instance);
		m_delegates.push(cb);
	}

	template <R (*Function)(Args...)> void bind()
	{
		Delegate<R(Args...)> cb;
		cb.template bind<Function>();
		m_delegates.push(cb);
	}

	template <typename C, R (C::*Function)(Args...)> void unbind(C* instance)
	{
		Delegate<R(Args...)> cb;
		cb.template bind<C, Function>(instance);
		for (int i = 0; i < m_delegates.size(); ++i)
		{
			if (m_delegates[i] == cb)
			{
				m_delegates.eraseFast(i);
				break;
			}
		}
	}

	void invoke(Args... args)
	{
		for (auto& i : m_delegates) i.invoke(args...);
	}

private:
	Array<Delegate<R(Args...)>> m_delegates;
};

我们实现这个委托的目的跟Unity的类似,比如我们的输入系统,UI都会使用我们引擎提供的委托函数。引擎代码编写都是比较枯燥的,其实要学好C++编程不是那么容易的事情,需要大量的练习,尤其是模板的使用。对于模板不熟悉的读者多学习一下,编写引擎使用的时C++11,关于C++11的特性读者要熟悉,比如auto,智能指针等等。

3D游戏引擎编程-3D.Game.Engine.Programming.pdf,作者:Stefan Zerbst & Oliver Duvel,本书是英文版,大小 271 MB,被压缩成两部分分别上传。这是第一部分,第二部分下载地址:http://download.csdn.net/source/2697012。 IT业中游戏业最吃香?为什么呢?大家说有多少网民没有玩过游戏?不过中国游戏人才也是缺啊!看看盛大为了招收人才自己到各个大学去招收计算机本科生啊!中国最大的游戏公司竟然自己去招收人才,可想而知啊!!中国游戏人才到底缺多少!我们缺的不是玩游戏的,而是做游戏的!大家想必都有过要自己做游戏的梦想吧?为什么没有实现呢?因为觉得自己办不到?错!你能办到!从现在开始吧!我们一起将韩国泡菜赶出国门!一起努力实现中国第一个暴雪公司!创造中国自己畅销全世界的游戏!以中国的武侠魅力去震撼世界!我们不要让外国人牵着鼻子走! 我们技术上比不过美国,美工上比不过日本,创意上比不过韩国!我们有什么可以自豪的呢?中国游戏产业的振兴就靠我们这一代,不要让我们的下一代都只玩美国的XBOX,日本的PS,韩国的传奇!我们看到了中国游戏业这块大蛋糕已经让外国瓜分的剩不下多少了!中国的公司为了代理外国的一个游戏争的头破血流!这样的事情不要让他们再一次次重演了! 游戏开发职业虽然含金量较高,但从业门槛也高高在上,因此,学习前一定要先看看自己是否适合这一职业。判断标准主要有以下点:一看学历,一般需有大专以上的育背景;二看年龄,游戏业是年轻人的行业,18-35岁是最佳年龄段;三看逻辑性,从业人员除具备IT基本知识外,还要有相当强的逻辑能力,否则将难以担当复杂的编程工作;四看知识面,游戏软件开发设计编剧、美术、音乐、动画、程序等诸多方面,知识面宽泛;五看创新能力,游戏开发需要经常翻花头,对开发者创新能力的要求较高;六看合作能力,游戏软件开发往往由一个小组负责,需要开发者有团队合作精神;看兴趣,游戏开发是一项异常枯燥的工作,如果对此没有足够的兴趣,将很难做好。 发布的这些书都是原版的英文书籍,没有中文的,因为中文翻译的慢!大家如果想从事游戏开发,我真的建议大家先学英语,英语是你一切的一切的基础!大家也可以下载一个金山词霸来边翻译边看!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海洋_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值