最近在做Alice Engine v0.4的时候,发现Alice Engine0.3版本有一个可以推敲的问题。
就是Alice Engine v0.3中,窗口的创建是通过AliceDelegate这一个类来实现的。如下描述:
AliceDelegate是放在Alice Engine中,与用户项目耦合度非常低。
用户需要创建游戏的时候,首先需要基于抽象类Game派生出自己的Game类(暂定叫CMyGame),然后在Main.cpp中实例化CMyGame,再实例化AliceDelegate,最后把CMyGame的对象指针通过AliceDelegate的
SetGameInstance(Game*);
函数把Game的对象传递到AliceDelegate中。
一开始这样设计的时候,觉得这样设计的好处就是用户的工程和引擎的耦合度很低,但我在写v0.4的时候,发现用户必须要自己派生一个Game类,这样一来,用户需要派生一个类,并且实例化一个类,再把这一个派生类的实例对象传递给AliceDelegate,最后CreateGame才能够正确创建窗口。
由于Delegate只有cocos2d-x这样大型的游戏引擎才会使用到,所以在我这样小的框架中,这些代码就显得十分多余。对于这个情况,我考虑了如下几种新的方案。
1、去除AliceDelegate,把原来AliceDelegate所有内容交由Main托管。
2、去除AliceDelegate,把原来AliceDelegate所有内容移如Game类中成为虚函数,用户可以在工程中派生出来自己的用法。
3、保留AliceDelegate,但是把AliceDelegate当做Game类的成员对象,用户实例化CMyGame类后调用实例对象的Init函数来初始化AliceDelegate。
罗列三种方案之后,考虑了一下如下三种方案的优缺点
三种方案的优缺点
方案 | 方案一 | 方案二 | 方案三 |
优点 | 1、移除了AliceDelegate,用户使用逻辑变得简单了。 2、窗体注册和创建,消息循环都放到了main.cpp中,符合使用逻辑。 3、用户可以定制使用的内容变得丰富。 | 1、移除了AliceDelegate,用户使用逻辑变得简单了。 2、窗体注册和创建变得简单了,用户只需要派生Game类,再调用Game类中集成原有的AliceDelegate的内容就可以创建窗体。 3、用户使用代码量变少,需要实例化的东西变少了。
| 1、用户使用代码量变少,需要实例化的东西变少了。 2、窗体注册和创建变得简单了,用户只需要派生Game类,再调用Game类中集成原有的AliceDelegate的内容就可以创建窗体。
|
缺点 | 1、用户创建工程后,main.cpp要更多的内容来创建窗体,引擎的内容要用户实例化CMyGame后才能得到体现。 2、用户定制的内容丰富,但是对于使用者来说,其实做游戏的话,对于窗口的样式要求不高。 | 1、用户需要定制的内容变少了,虽然许多游戏工程对于窗口样式要求不高,但是毕竟这也是限制。 | 1、这样会包涵一个互相引用。 2、引擎的逻辑变得混乱,用户读代码阅读成本变得更高。 3、用户需要定制的内容变少了,虽然许多的游戏工程对于窗口样式要求不高,但是毕竟这也是限制。 |
评估 | 1、如果把这些AliceDelegate的内容放在main中,就会很符合教学的思路。因为学校Windows编程课中,需要学习注册窗口类,创建窗口,消息循环等内容。所以这样更加适合教学。 2、由于代码非常的多,导致学生建立新工程要写的代码很多。
结论:放做备选方案。 | 1、虽然窗口样式定制的内容变少了,但是我可以增加多一些接口函数给外部调用。 这样可以尽可能丰富用户选择,引擎的逻辑也会变得简单。 2、教学中其实对于Windows编程需要掌握的是注册窗口类与消息循环。这两样东西教学中可以重写InitGame这个函数来学习。 3、引擎和用户的代码之间的耦合度降低了,这样用户创建新项目完全可以重头开始写很少的代码来创建一个游戏。
结论:首选该方案 | 1、这是我首先不考虑的方案。因为这个方案涉及到两个.h文件的互相嵌套,所以需要添加前置声明,这样当我们需要引入的类越多,代码就会变的丑陋不堪。 2、在一个类里面把AliceDelegate当做一个成员变量是一个奇怪的行为,既然可以把他当做成员变量,为什么不集成进去呢?
结论:抛弃,不采用 |
上面几个方案罗列一下,我总结了关于这两个类的一个处理的原则:
1、能简单的逻辑,尽可能简单的逻辑;
2、两个类之间最好不要互相包含;
3、尽量与用户的代码耦合度低一点;
4、能由派生出来解决的东西,最好还是让用户派生出来解决。