用新浪微博登录

只需一步,快速搞定

 找回密码
 立即注册

用新浪微博登录

只需一步,快速搞定

查看: 2738|回复: 4
打印 上一主题 下一主题

新手编程导论(十)

[复制链接]

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

跳转到指定楼层
楼主
发表于 2011-10-22 18:40:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式 |          
第三部分 进阶: C,C++代码阅读与控制
如果说在本书第二部分里我力求向你们提出一个思想体系,那么在这本书的这部分我将要讲述的就是代码控制和实践能力了,这是程序设计的基础二部曲。这本书完成之后,你应该具备基础的编码实践能力(或阅读别人代码的能力)。
这部分主体是,C,C++语法,,及各自标准库的分析与使用,stdc,stl,glibc,boost,loki,(设计模式,数据结构,业务逻辑),而且更侧重使用(因为分析出来的是库逻辑,是设计抽象密集的)。比如自己开发例子出来(这才是使用密集的)。
目录可以这样定:轮子分析,再造轮子
1.C,C++基础(语法级的,,数组啊,字串啊,控制结构啊,初级标准库级的,比如IO,,OO啊,模板啊)。
2,数据结构,STL(分析库不如自写来得权威,,但是参照别人的src也是最好的方法)
3,设计模式上的,LOKI,我在这里不把BOOST拿来讨论,是因为我觉得成为语言标准的只需要数据结构作为数据抽明和设计模式作为代码抽象就可以了,,而BOOST有太多的对具体事物的抽象,,实际上随着问题的增多,BOOST会越来越大,,这(对各个事物的抽象解决集)不应该成为一门语言的标准。。而LOKI刚好对应只用模板解决的DP问题。。显然合理。
4,这是放在第二部分最后一节(抽象之领域逻辑)分析的某个库比如OO的OGRE,我在1月2号决定取消这一部分,,那么我作了什么决定呢,我决定写一个实现比如实化版的yake或者是一个yake类的引擎加一个游戏实现(直接把其当成写第六部分的内容,而不再分析并使用别人的游戏引擎,),可能用到其它的库(比如net,mysql,boost),直接产生一个游戏,,
具体如何进行呢,尽量少用轮子,只用OPENGL这样的必要的轮子。考虑进STL和LOKI,做成一个简单的引擎,然后写游戏实现。尽量在写的过程中与ogre,yake对比,突出为什么全的设计是它们,而现在自己在写的是一个克意不用其它轮子的轮子(为了教学的目的)。。
在第四部分,才是一个系统的解决方案(一个中型例子,而不再写库或分析库了,,,应该找什么现成的例子呢还是自写,,在这里要分析出设计的细节,大中型软件如何形成的),提出一个中型程序,,第四部分 一个例子,结合OO,模板,语言,领域逻辑写出的大型逻辑的软件
如果说STL是templaate与C的结合,那么LOKI有些更多靠近OO与template的结合。

第9章 语法与初级标准库
参考书《C++ Primer 第三版》Neckman
9.1 C++的基于过程设计
9.2 C++的基于对象设计: 模板与设计
不幸的是,理解STL深层的原理是需要懂与模板相关的设计的,比如仿函数的本质,迭代器,配接器的本质,模板导致的泛型开发与它提出的这些设计相关的东西可以另外写成一本书。学习STL首先是学习这些设计手法,再学习其数据结构和算法的实现。
泛型有二层意思,第一,基础泛化,它把泛型参数化,用于动态产生关于不同型别组合的相同逻辑(可以联系函数声明和函数定义来理解),这也就是一般泛化了,第二,它把一切设计中可能出现的因素都类型化(template class化),即在template class这个字眼中不主要强调template泛化而是class类型化,(只不过它也会用到泛型的第一层基础泛化作用而已)比如,迭代器,仿函数实际上都是(模板)类,这其实更像是C++的概念而不是泛型的概念。(因为class是c++的而stl及它导致的template手法是另外一个人发明的)
为什么需要把指针,函数封装为class呢,这是因为在C++中,class几乎就是一种逻辑粘剂(即将数据成员和函数成员,,当然在模板中也可以是模板成员数据和函数,封装为ADT),在这里并不强调这些Class运行于runtime的那些特征,比如多态,等,而是强调class封装逻辑成adt并提供private,public,protect修饰机制的能力(相比之下C++的struct太简陋因为它只能提供全public,而且不能成为adt,因此没有adt的诸多好处,比如C++的只对class有效的运算符重载,,而class+oper overloading+template class你呆会会看到,,这在泛型设计中是多么有用处的东西。),,所以在C++中,相比面向对象来说,这些基于对象的开发范式也需要被重视。。
一句话,class化可以获得语义级的value, 只要给该class一个copy ctor就可以复制并传统它,给它一个重载的括号就可以成为跟函数动作一样的东西出现在C++语法相容的东西(虽然语义实际跟标准的对应物不一样),,,
template class是泛型设计中的重头武器,因为:
函数+oper () overloading+template class化 = function objects,这就是stl中的仿函数。
pointer+oper * overloading(和->)+template class化 = smartpointer,这就相当stl中的interate.
Multiple inhert + template class作为另一个template的参数=policy,即loki中的策略。
Struct+template=nested type,,内欠型别。。
元编程里的metafunction
重载是多态的简单形式,,模板特化与实例化是不一样的,,,其实任何一个模板,都存在二套参数,一套是泛用的,在tempalte关键字后面,另一套是特化或偏特化用的,在具体的模板后。特化与实例化的区别在于实例化不需要人去干预。

9.3 面向对象设计

9.4 泛型开发与初级StdC库

第10章 数据逻辑与STL库

参考书:《STL源码分析》完整版 侯捷
10.1 仿函数
仿函数是C++基于对象编程的典型,,,它把对象class化{也可能是template class化},使之具有copy ctor可被复制,再给它提供一个重载的小括号这样在语法上就可以跟普通函数一样写了,整个过程并不需要面向运行期(面向对象),,,所谓模板加基于对象的基于对象之说只适合发生于编译期。
STL中为什么需要仿函数呢?它为了成为算法的某种策略,,loki中的仿函数用来实现一种command的设计模式,因为仿函数可以用来封装一系列请求;
10.2 iterater
Stl中,与template相关的一个设计手法就是迭代器,迭代器成为表达各种数据结构以及跟它们有关的各种算法操作的支持概念。当然也是一种泛型手法。Idioms 其实也是一种设计模式,即迭代器模式(traits,adapter泛型设计手法可用于广泛目的,相比之下iterate好像只用于数据结构的设计手法设计模式),
既然是泛型编程,迭代器是在什么样的泛化需求下以什么样的泛化方式被提出来的呢?
我们知道数据结构都是某种区间,把数据结构视为区间这本身就体现了某种泛化(能泛即能提供通用性,可复用性,所以是一种对代码趋近于人的设计抽象),某种抽象,实际上无论是以何种结构形成的关联式(key+value=pair对)还是非关联式数据结构(),,迭代器都将提供一种游动于元素(一般来说元素只是value的说法)或节点(一般来说node=key,value)之间并能对算法提供迭代支持。只不过迭代器作为泛型的型它也可以有多种iterate associated traits而已,有的是input,有的是单向,有的是双向,有的是const,有的是mutable而已。
10.3 adapter
配接器的说法很形象, 你可以联系现实生活中把ps/2鼠标加一个ps/2 2 usb接口,,把它转为USB接口的这样一种动作,,这种动作就是改变接口的机制使之由旧接口变成新接口,一种设计策略(改变原有代码,使之适应某种复用考虑,,所以是人控制代码的过程,,是设计抽象,,这个动作也称为重构,即不改变原有系统设计的情况下,利用设计手段修补式地改造原系统,因此跟DP相关),,往往把它归为专门的一门设计模式。
因为客户(你的电脑ps/2口坏了不能插ps/2鼠标了)只能使用某种接口的东西,所以需要对原有接口(原有代码)进行接口重新封装,使之向现呈现客户能用的接口。这是典型的设计模式应用于给代码打补丁的情形即复用的情形。(当然设计模式也可一开始用于纯设计的地方)
那么stl中的这些配接器都是些什么呢,又怎么样在stl的整个设计中发挥了作用呢??
回复

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

沙发
 楼主| 发表于 2011-10-22 18:42:53 | 只看该作者
第11章 高级代码逻辑与LOKI库
参考书:《C++新思维》中文完整版
11.1 typelist
对类型的设计才是设计。
为什么写代码需要设计呢,因为代码是人写给人看的,所以对代码逻辑的控制是需要的,而这就是设计,,设计更多指一种人类活动,比如艺术设计,所以它包括测试,重构等诸多过程组成的与编码相对的过程。设计首先是一种对问题的积极抽象过程,booch甚至说抽象是解决设计问题最有效的方法之一,当然,维护,重构也是,所以说抽象问题只是设计的一部分然而是最重要部分。
在C++中,设计首先是对类型进行设计进行抽象(泛型这个字眼本身就表明了对各种类型其功能通用,所以是一种设计抽象),有OO。有template。OO是类型化即面向对象,template是泛型化即主要用C++的基于对象机制来工作。
泛型编程中对型进行的抽象,有make types to be a list,有mapping type to sth,有get traits from types,尽量在编译期间将型别抽象到应用,形成设计,因为静态语言的编译期间正好提供强大的类型功能,,,而这里谈到的typelist就是一种。。
对类型作了这么多抽象之后,再提出iterate,等设计手法用于stl,提出policy用于policy based design,,学习范型编程,始终要提醒自己把握这个精神(即一般泛型设计会分成三个层次,第一层是型别抽象,第二层在第一层的基础上提出邻域相关的设计手法,第三问题本身,STL和LOKI中都是这样)。。

11.2 traits
Traits是剥离器,是一种设计抽象(往往人们也把它称为concept,,满足concept的实现就是它的一个model,即concept是编译期关于类型的interface),广泛应用于stl,loki,等设计理念中(剥离器一般只用于泛型设计,因为需要从泛化了的型剥离并获得它的traits,实际上这个词更多地强调的是结果),是成就stl,loki等的支撑逻辑。因为类型有“一般type”,作为template class的迭代器,等等,所以也有相应的type traits,iterate traits.即模板的参数可以是什么,那么泛型也可泛化什么,形成相应的泛化意义(比如traits),因此泛型可以将型别泛化,可以将操作泛化,甚至可以将一大类的操作和型别泛化。更甚至,可以将“template template参数”泛化,注意我并没有多打字,现列举可能作为template所有参数的情况,并一一加以解释:

11.2 policy
为什么需要policy呢,,因为我们知道在应用开发中设计往往是做多选题,对应于应用域在解域和语言域中有大量可供选择的方案,所以可复用组件最好是给用户小的设计组件,用户才能借以组合它们形成更强大的设计方案(具体到每个领域,它的设计都应该如此,比如loki,的智能指针,仿函数等具体领域都是策略based的)。因为设计元素只能分解而后才能复合,而不应该是一开始就复合了。。如果一开始就提出一个do it all全功能型的接口,那么往往复用性从一开始就固化了(OO就是如此,单根继承往往涉及大量不必需的东西进入设计,组合才是科学的机制)。这往往很不好。因为它只能向前发展不能向后发展。那么组合大量小policy形成的对某个瓴域的某套组合polices,给了我们后退的空间,我们可以组合需要的去除不需要的,这才是我们需要的,即设计中可以在此做选择题的能力和场所。。
第四部分 一个例子:游戏引擎和实现
War3这个游戏引擎我认为是我见过的颇为先进和完善的引擎,不知你有没看过War3的“铭谢”CS,它提到这个引擎用到了比如ZLIB,TRUETYPE等库,下面我们来实现一个属于我们自己的War3吧,这个War3就叫NotWar3了!
是使用本书前面三部分这些知识的时候了,在对这个框架的设计中,我将向你呈现大部分出现在本书中的思想或细节,比如对外来库的使用,三种思想的运用,建立自己的中间逻辑即库,基于策略的设计(MetaDesignPolicy)等,并给出作者写这个框架过程中的一些合理或不合理尝试,模拟一次真正的软件工程!

第12章 设计(需求分析)
12.1 第一天:接到一个案子
客户要求我做一个类WebGame的游戏,那么这是一个什么样的类WebGame呢?他们用列举的方法来提出了以下几点要求
1. XML统一格式的方法来打包客户端文件,,用xdbm客户端统一打包(他们事先指定用yake和ogre的xml资源,,,model ,,sketeonl,,,scene),
2. 绿色客户端,如果第一条要求是html,,那么这就相当于C/S中的浏览器,, 客户端升级接口
3. 实现类war3的对战和游戏内容,类War3的CS过场界面和录像机制
4. 实现脚本机的扩展,,跟War3一样提供一个“护展编程接口”, 玩家发布任务,WorldEditor,
5. 界面设计:游戏界面有三大块,,用一张图来表示,,,input设计要好
6. 利用Jxta(C的Jxta)来构建网络环境,游戏客户端由于集成Game Logic,因此可设置一个UseLocalLogic和UseFarLogic来选对与P2P环境内的玩家对战或连接上一个C/S游戏服务器玩RPG游戏(此时Use Far Game Logic)。
7. 登入时自动下载上次存储在服务端的游戏辅助设置(Input设置,自定义头像和模型)
8. 为了能让这个游戏更好,,任何你能想到的请自由发挥(可斟情增加报酬)
这些需要大部分只是细节要求(很少是架构需要),因为我们是在模拟外行的用户不分巨细向我们提出要求(对于游戏逻辑,都闪闪其词),我们需要整理这些需求以用于后来的设计(说实话以上的需求一般现实见不到)
设计跟需求分析之间的关系很重要,这要求这些需求在设计时就应该被全面地提出来(为了扩展的需要,设计应该在允许的范围内做到全面化和合理化,,但是注意,我在对世界逻辑的设计过程中提到的设计涵盖面是巨大的,这依其说是仅仅面向需求进行分析,,不如说是大而全的通用设计,而一般人则是分析需求,然后依据经验直接简约设计,而这里我是为了纯粹教学,所以请千万明白这里的问题),否则在进入设计期时,就只能通过重构(重构是软工中一个很重要的部分)的手段来添加新功能!
12.2 第二天:需求分析
为什么要提出这么一个过程呢?这(对需求的分析)可作为设计的参考,这即为设计的参考技术总结(设计最终要体现这些,从现在开始就要考虑设计与计算机实现的结合点,因此可以用来指导多范型设计)
在一个需求中,什么是游戏的逻辑部分,什么是游戏的客户端部分,什么是游戏设计中后来才需考虑的细节部分,什么是在进行游戏设计时先考虑到的架构部分,在哪个架构中提供什么接口,一个接口应被置于哪个架构中,这不是一个有人作过专门研究的课题,然而如果给出一个具体的例子,我们应能很快地判断并决定它应放置于客户端逻辑还是游戏逻辑(这就是设计方法论学应解决的问题,游戏逻辑就是业务逻辑,而ClientSideGeneric或ServerSideGeneric就是表现逻辑了,我们也应该能确定需求分析中的哪些是架构哪些是细节),,
9. 利用Lua Bind C++的本地库来进行扩展接口的设计(客户端和服务端面向Developer的编程扩展接口),可以动态测试,不用重启服务器(提供Lua导入功能的界面接口),不过War3的游戏逻辑全部是用脚本写的,而这里用C++写LogicGeneric和DevelopGeneric,然后导出为Lua所用,再在此基础上进行扩展出一个具体游戏(事实上仅仅到这里为止,才进入“游戏”的设计,前面的GameGeneric实际上称为VRGeneric更为合适)
10. 针对界面部分,,好像中国的游戏都是策划主导编程的,,,策划提出来的想法大部分都是表现(数值设定,游戏故事,,等等都是外在表现),,很少是引擎内部架构(我们说原语设计先于多范型设计,那就是说原语设计是对应用内部架构进行设计而不是一开始就设计应用的外部表现),,实际上编程主导策划才是对的(当然如果仅仅从技术上来说是这样的),因为如果在中间逻辑层次提供了足够好的接口,那么外在表现(即实现)可以无限和快速地扩展(然而游戏开发功利的目的使我们往往颠倒了这种关系,这样做出来的引擎只能是。。。)客户端设计DllFromInterLogics,Main.DLL,,,
11. 客户端是瘦客户端,,这往往它的EXE只是一个渲染框架和界面资料(媒体资料),客户端资料比如地图这些大件可以从官方网站或某个下载点直接下到(分文件或一次性全下载),或者(这里才是重点难点)在游戏中进入一个地图时如果检查本地没有此地图即显示First Time Enter This Area,并下载地图,如果取消下载玩家进入一个黑暗区域但是依然会有障碍,故称这是一个类Web的Game(真正的WebGame就是用网页呈现的游戏,通过80端口进行通信,这样的游戏有一点迂腐和小儿科)
12. 对于xml统一打包(比如地图和对战时的P2P文件共享),封装各种二进制的格式(比如客户端的各种格式的文件和Lua代码,Developer的护展发布---一个地图文件封装Lua代码),XML也可作为Jxta的消息通用文档格式,我注意到有些游戏引擎的实现把模型资源封装为XML,这在我个人看来并不是一种好的方法,XML作为Wrapper是好的,然而用它去描述内部某个XML节点数据又是不必要的(个人看法,SQL的拥护者认为XML DB已经超出了数据存储的原语空间,他们认为XMLDB-这里着重指NavtiveXMLDB是一种过度设计)这里用xdbm,,把每一个客户端文件都作为xdbm的二进制格式,,,这样就保证了二进制载入和打包的双重需求
13. 对于绿色客户端,,将GameGeneric置为一个单DLL文件,把Yake的所有中间逻辑封装者即DLLs和LogicGeneric全部编译进一个DLL文件,称为GameEngine.DLL(如果直接在YakeBase中和LogicGeneric中删除DLL加载逻辑这就需要改动源程序尤其是YakeBase中的Logging机制,而且如果删除,以后DLL就不能动态装卸了,而且不利于对GameEngine.dll级的扩展,当然如果不删除,那么DLL就以一系列中间逻辑的样子躺在客户端这样不免难看)这就需要定义另外一种加载插件的逻辑,同样可以做到动态屏蔽和启用(而非装卸)和以后对GameEngine.dll级的的扩展(继承这个屏幕和开启接口就是了),
不要怀疑,我们正是在做软件工程(的需求分析阶段,,虽然只是初步的分析)和面向接口编程(因为接下来我们也要做库和架构)
以上都是需求分析,描述一下接下来我们的开发路线,当然是先设计后编码了(在进入真正的范型设计前,我们先进行一个原语设计,,,整理自己对游戏的认识,,这中间用到外来库因此还得说说它)
设计前工作
14. 游戏原语设计,,表现设计与细节设计(设计界面等细节,实际上这个步骤可以放到最后,因为这是表现逻辑应次于以下的业务逻辑进行,不要被这个主导设计逻辑)
15. 了解要用到的库的架构和接口(Yake表现逻辑)
设计部分
16. 范型设计并实作LogicGeneric(单OO泛型实作设计)
17. 为LogicGeneric写ExtendGeneric
编码部分
Demo编码(这就是实现,其它的实现通过lua去扩展或为三大架构自写Plugable 的DLL)
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

板凳
 楼主| 发表于 2011-10-22 18:59:48 | 只看该作者
第13章 设计(领域分析与抽象)
13.1 原语设计
你理想中的游戏是什么样子呢?什么又是游戏(你对游戏的概念直接影响了你对游戏的设计),每个人的看法都会不同吧(反问一下,什么又不是游戏,连BBS也可以是一种文字游戏,但是我们不做这种超级泛化,我们只对3D网游作泛化)?以下就是我对游戏尤其是网游的看法,更准确地说它是框架设计(在完成了这个框架和所有中间逻辑之后,最终的实现编码的过程很简单),,这里把游戏泛化为“可扩展的虚拟现实对战”,并设计出一套思想级的协议(就如同下面的一张图表示的),并用一套具体代码库实现它,但是这显然是一个巨大的工程(就好像根据P2P和一些其它的规范比如XML来实作出Jxta),。。
以下是一个一定程序上反映我的理想的一个框架设计,哈哈


我想象中的一个游戏总原语
由上述原语设计(尚属非常初级的设想)演化到多范型设计或UML实现,中间还需要很多设计上的细节,但我们会一步一步来进行,下面我们继续进行对虚拟现实这块进行细化


我想象中的一个虚拟现实原语
具体介绍一下
世界逻辑管理天气,地理变迁等游戏世界自然变迁逻辑和游戏世界社会关系逻辑(可产生一系列游戏系统GameSystem,用Plugable的DLL来实现), 数据逻辑(虚拟世界与现实的接口) ,这所有的逻辑由一个叫WorldLogic的组件来封装(上面的描述),这个组件就是独立于表现逻辑(Show Generic)的游戏逻辑(又称Logic Generic),
游戏世界就是一个社会,因此WorldGeneric就作为一个单例代表整个世界,这个世界分为SocietyGeneric和自然Generic,


图1-3 我想象中的一个虚拟世界逻辑原语
至于表现逻辑就用Yake,注意Yake仅仅是VR的表现引擎,而WorldLogic是游戏逻辑引擎,而且可从这二个组件定义出一个具体游戏(这中间还要通过一个下面要谈到的Game抽象层次和建立在Game之上的扩展接口ExtendGeneric),
这里主要任务是深化对世界逻辑的认识,为以后的设计演化服务
实际上世界逻辑设计可以无限地大(实际上我最后实作出的设计也会很大,而且现在一般的大中型游戏中也的确涉及到了大量的世界逻辑),,,所以现在的游戏引擎一般都是表现引擎,,真正引擎之后的游戏源码部分才会出现一点零散的世界逻辑(而且没有被形成一个架构,因为人们普遍觉得像世界逻辑这样的东西根本不应被用来架构并单独封装,因为这的确是一个无尽的任务,世界逻辑可以无限啊),,,然而,就现在的大中型游戏中出现的世界逻辑引擎来说的确可以总而归为一个架构(我们正是要针对这些作架构,,正如你将会在我的设计中的大量细节),所以在设计中找准问题和思路方向是重要的,用什么范型只是后来的事情
如果一个计设中存在大量细节,,难以分清什么是细节上的,那些是架构上的,,那么一个方法是多范型设计中提到的“变点与不变点”,,怎么说呢,,比如一个游戏逻辑世界,,总有角色和地图吧(在经过分析得出大量设计细节后而难以得到一个满意的分析结果时,这个想法相对来说是比较容易想出来的,历为角色是实际存在的,,这个分析结果就是能提出一个架构,,并串联上所有的设计细节),,,,,这二个不变点就可以引导所有的你不能确定的“变点”(比如各种游戏系统)
实作GameGeneric就是用UML来设计接口和大架构,先来设计一个多范型设计图
这个库我准备将其开源发行,其代号为gvwl=Generic World Logic Libary
GameGeneric为Generic Virtual Reality Lib gvrl
这一个完全与平台无关的库(除了它的DLL形式逻辑,它的内部完全是平台无关的逻辑),
好了,找准了问题之后,现在来归纳问题(世界逻辑到底是什么,有什么,,)明白这些事实对以后的设计演化非常重要,而在原语设计部分提出的那个逻辑只是非常高层的我们需要在这里深入并得出一个确切的设计结果(这样才能依据它得出确切的范型设计)
1. Actor type应有PC(),NPC,道具(又有很多分法),电脑之分
2. Stage就是任务,有世界任务,国家任务,职业任务,组织任务,居民任务,,玩家任务之分,,
3. AI有吸怪AI(Agross AI),,,电脑群攻AI
4. 时间就是纪元,当一个设定的世界任务stage被完全(世界任务就是隐创的全世界玩家的关卡),,,玩家进入一个新的纪元,,天器和器候机制,,对资源分布和技能发挥,,物品掉落,任务细节,等有影响
5. 这个世界逻辑引擎就是一个Actor_Stage_Driven_Dymic_World(完全可以脱离玩家运作,,需要提供一个初始状态集),,,,有二种干预方式,GM管理方式和gm Player(比如一个国主玩家,,国政系统)二种干预方式(admin adapter)
6. 势力范围演变(个人势力,国家势力,,组织势力),,世界地图,,,资源分布变迁,合成机制
7. War3like 多元故事机制,,多职业机制,,,采用War3的多职业,,技能组合=一种职业,,只有种族之分无明显的职业之分,,但是种族对技能学习有影响,,玩家遗迹系统(声望和称号系统,,匆滥,,声望和称号极其难得,,特殊道具难得)
8. 装备机制,,玩家装备位,,,
9. 少怪多人,,,boss为电脑,,怪物
10. 元素互克系统,,伤害数值(保证适当量度的耐打,少团灭,秒杀),能力数值机制(攻击方式,攻击伤害,,攻频,,视野能力,,白天黑夜之分,记忆系统),,,技能分职业技能和自学技能机制,,技能连携机制,
11. 拍卖行和叫卖场,,,叫卖类宠物(dual box like),,,野外雇佣兵机制,,
12. 打斗机制,,城建系统,国战场,,道具升级系统,,阵法系统,,,Macro和自定义UI的物品/技能栏
13. Actor都有一个id和一个名字集,,
14. 交通机制,,传送机制,,时空广阔,有星外,天上之分,里世界,玩家可转服
15. 此游戏
以上这些细节如果写开来,,就是一份很详尽很占篇幅的策划书,,,,因此我们采取了简单列举的方法,,,,具体的这些设计的细节和对这些设计的范型实现细节在下面一节会讲到。。
那么当设计完成进入多范型之后,我们是用一种自上而下(先提出一种架构然后慢慢发展支节逻辑)还是自下而上呢(先独立考虑各个支节,再在它们上面架构一个大架构,),这里的多范型设计我们使用自上而下(因为我个人认为这样设计得比较全面)
我对Game的看法是,


图1-2我想象中的一个Game原语
那么扩展呢?这里只说脚本机的扩展,Lua扩展并非真正的功能扩展,而是功能的导出,(当然写Lua之后的代码的确可进行功能扩展,但这里是相于Lua之前的中间逻辑来说的),脚本机的作用在于动态调试和发展用户逻辑(就是类似War3WorldEditor的开关编辑器了)
1,作为GameGeneric一部分时


2,独立于GameGeneric之上时



什么是扩展出来的某具体游戏呢?它可以是单机(比如做类War3的战役任务以熟悉游戏,这就要求游戏逻辑在本机),或对战(类War3的对战地图游戏),或C/S式的RPG(游戏逻辑也可以在服务端),这样的游戏并不局限于FPS或RPG或其它类型,这是一种泛RPG游戏,形象来说就是服务端的为客户端和服务端共享这个最终的游戏就是一个Lua写成的GameGeneric的派生,可动态测试,Lua解释器就是一个启动Shell,因为启动游戏等表现逻辑都在ShowGeneric内),这样的游戏,通过它的扩展接口,你可以在一张地图上设置赛道,这样就是一个赛车游戏,可以通过扩展接口,改变游戏视角,提供一些特别的地图,就可以做成一个FPS游戏,但它大体上是一个RPG(游戏在道理上本来就是一个完整的世界),因此说它是一种泛RPG游戏(这再一次体现了,通过某些很好的设计,可以整合某些细节或绕过它们,因此说设计是优于编码的)
这面即为NotWar3的原语图

我想象中一个具体游戏原
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

地板
 楼主| 发表于 2011-10-22 19:02:27 | 只看该作者
13.2 了解Yake
以上谈完了原语设计部分,这一节讲要用到的库,就是YAKE了,这一节可能要占很长篇幅,因为Yake本身是一个很大的架构
我发现Yake是一个很好的游戏引擎(它自称是VR和游戏引擎,,但是它明显没有提供虚拟世界的内部逻辑,而只是提供了VR和Game对于计算机的表现逻辑而已,为什么选择Yake呢?就因为它功能全面至于运行效益也要考虑),它集成了我们以上提到的多数组件(而且DLL形式的组件可以选择不编译而且各个DLL之间没有相互引用关系对于Yake主体来说完全是Plugable的)(但是我们将按需去掉一些组件,将它集成到GameGeneric上去,比如将LuaBind逻辑和Lua提到GameGeneric上去,把YakeBase中的DLL封装逻辑和Logging机制去除,因为我们将把Yake编译成一个静态库再为GameGeneric所用,把oSceneLoaderLib去除,因为根本不需要这个功能-不需要把场景图中每个节点都利用XML展现出来,我们只想用XDMB的二进制Wrapper场景文件(场景文件有它自己的非XML形式的加密格式),而用XDMB去封装场景调入逻辑),我们应了解它的架构先,并理解其存在哪些API,但是并不深入探索它们是如何实现的,因为我们仅仅是想使用它 (这就表明,我们仅仅要做库的顾客而不是让它去主导我们自己的架构)
对库的理解要深入到函数API级(只是了解一下并不探索其实现因为我们只是顾客只满足于调用它并在自己的逻辑中封装它,但是要当高级顾问时却要了解它与其它API的联系,即该API的实现,因为此时我们调用到了该API的低层,这势必要清楚它与其它API的联系),而不仅仅满足了解其库的架构(了解Yake总体大架构还是基本,如果能完成理解它的主体即引入其它库的那些逻辑就更好拿来调用了),对Yake的研究可以让你学到不少东西
我为什么要强调“我们只是顾客呢”,人们并不真正理解那些从一出生就耳闻目见的字眼的真正意义,我想信如果不是我加括号,很多人也很难理解出括号内这层意义出来(而显然这是在我们前面反复讲到的)
能写出像Yake之类高抽象的代码(除了要懂模板和OO这二种范型的各种技术细节之外,还有策略,可以称为是OO和模板之上的抽象泛型),更重要的是具备我上面提到的那些设计思想以及对游戏的认识,流行于程序员之间的用卡来表达设计的方法,最初就是思想的活动,提出一些思想字眼(设计用词),然后再形成具体类文件的名字写到卡片上,最终形成一个计算机观点能接受的范型设计。
正如Yake所言,它是一个VR引擎,又是一个Game引擎,它的Base部分提供了DLL装卸机制和Log机制,这就一定意义上对应我们接下来要谈到的“可复用”策略(ORDL),它除了RAF,Client,Server之外的表现部分是VR的表现部分,而Raf,Client,Server这些都是Game Show部分(显然Yake没提供VR Logic和Game Logic部分),它的LuaBind就是脚本级扩展接口,而Base的DLL和Log机制就是程序员级的扩展接口,下面我们来深刻了解一下这个Base Generic并探索它可以被如何完善的地方,首先来看一个概念
面向复用的设计库(Ori Reuse Design Lib),这个库是一个策略库(我们把用模板范型和OO范型来表达设计的技术实现统称为策略,这样策略就不只表示DP了),Generic Design Poliy Lib(通用策略设计库),那么这是一个什么样的库呢,这个库基于以下思想

这个库的另一个别名是:GenericInterLogicPolicyLibrary,Compliler Time 实现与Design Devidded Policy Lib,或Complier Time face可复用 Plugable Pocidy Lib(请原谅我用这么长的描述,但这不是标题,而且如果缺少任何一个字眼都不完整),如果把Yake的Base Generic进行完善,它就会这么一个库
这个Policy用了一些语言内的范型,比如OO和模板,还用了语言外的范型,比如Plugable的DLL,这样的库为设计服务(注意这句话),它主要达到一种什么样的目的呢, 通过在设计期就分开实现和设计,这样就达到了在设计期就达到充分的可复用(而可复用显然无论是设计还是实现都最先考虑的问题,OO和面向构件都是为了可复用而设计,因此这个库实际上就整合了这二个方面,语言之内是OO,语言之外是构件),(你可以看到这个库为VREngine和NotWar3的各个中间抽象层次所用)
与设计期有关的东东常称为元,比如MetaProgramming,强调设计期的作用,还比如MetaData(强调对数据的描述而不是存储,关系数据库的拥护者认为存储才是数据库真正要考虑的东西,而存储是具体数据库的事,这个道理就像我在本书最后一部分提到的Game与VR的关系,到底具体数据库才是数据库,还是对数据的描述才是数据存储?(什么是游戏,具体的游戏是游戏,还是游戏这种泛型说法才是游戏)这是鸡生鸡蛋生蛋的问题,以我看,鸡蛋问题并非不可解,答案就是先是鸡后是蛋,因为在问题中,鸡字蛋字都是具体的)因此上述库还可称为MetaDesignPolicy
运行期=计算机实现=泛型实现(RTTI),因此可复用的最大限度是你的泛型实现
图的左边是“与平台有关的表现”,称为表现Generic(需用与计算机平台有关的多范型表达),右边是“不与平台有关的纯思想”,这样就做到了在设计期就充分考虑了实现与逻辑分开(设计与编码是统一的,设计期就充分考虑了可复用,那么在编码时自然会继承这个优势,一切编码和实现级的的不可复用问题和难于复用问题都可在设计期找到答案,设计与实现本来就是统一多于其矛盾的,他们的矛盾之处在于泛型设计与原语设计的矛盾,比如在设计期把游戏中的一片叶子当成一个对象有时是一种好设计,然而当被用于多泛型实现时,在运行时就会造成效率的低下,这就是不成功的多范型设计,当然,实现与逻辑分开这个说法绝非这么简单,因此我们在SHOW和LOGIC内部也需要考虑将其OO化或策略化以增强其内部的实现与逻辑),诚然,OO可以一定程序上做到“实现与逻辑分开”,但是还有策略,然而这是语言内部的,在语言外部是库(Plugable的DLL形式发挥了重要的作用),这个技术也可提供设计时的可复用(当然可复用永远是相对的,在应用上述图作出的应用架构,在各个Genric外至少是实现与逻辑分开的,当然各个Generic的SHOW或LOGIC部分也要做到可复用),这样就是
1. 要保证在实现与Logic内部也是实现与逻辑分开的和充分的Plug化
2. 要保证Logic部分绝对是思想而没有与平台相关的细节
3. 在每一个Genric层次,可以无Logic,但不可没有Show
以的图可对应到NotWar3的原语设计部分,而它们共同的基础就是这个面向复用的策略库

1. Extend Generic=Game Generic+Lua Bind Generic(或者Game Generic自成一个Generic,此时就要求Lua Bind不是仅对Game Genric进行Bind,而是对下面各个Genric进行Bind)
2. VR Generic=Yake+World Logic Generic
3. Game Generic
4. 它们的下面是Yake Base

即见下面这个总原语图

请注意到,上述图中很多用词显然仅属于思想过程的中间描述(即仅仅是描述原语的用词,比如GameGeneric中的Generic这个词就表示它可能是一种架构逻辑也可能是实现逻辑,这里就用Generic来整个描述这个层次抽象, 即Generic=”一切中间逻辑”代词,它并不一定被封装成一个库也并不一定要在后来的多范型设计中要求被体现,可能会在源程序中用名字空间来表达,C++中的名字空间表达了一种什么样的本质呢?一个名字空间就是一个应用架构中某个子架构,或称为抽象层次的总称,而我们这里提出了四个即1.Design Policy Generic2,VR Generic3,Game Generic4,Extend Generic,其中3,4是特别的,如果3是为4服务,那么3,4实际上可以合并,如果Game有它自己的架构,那么3,4是分开的,Generic,Generic就是一种组织所有某个抽层的架构和实现的形式,名字空间也使我们的源程序能够很好地硬盘上被组织,Java的源程序包中的文件夹形式就是一种表现),因为我们此时在进行原语设计,不必考虑面向代码将其反映出来,这样我们考虑问题的范围会更广一点(实际进行多范型设计时要反映出来的就是那些能实际作用代码的用词,像上面大部分后带Generic饰词的中间逻辑集都要被体现,我们在实作部分会给出一个经过修饰的原语图,从原语设计到多范型设计到UML设计我们称为设计的演化),但无论如何要明白,一些对设计过程中用到的思想辅助用词是不必考虑进设计的代码实现的。原语设计跟多范型设计中间存在比较大的距离(真正的原语设计不是超级原语,虽然它名为原语,但它是在可控范围内权衡做到的原语,真正的多范型也并不是一团没有根据的计算机实现,它要也要面向前面的原语设计得出的结论,它们之间的联系要优于它们之间的区别被我们考虑)
不必拘泥以上的思想模型(任何人构架的逻辑模式和逻辑用词都可以不一样这不是严格的,但最终的应用反映在代码上要能工作这却是严格的),你画出的原语设计图同样正确,再简单也没关系,也不一定要成档,因为这只是严重参杂了个人看法的东东(只有当后来的多范型设计时才慢慢走入编程的束缚,因为这是参照编程界现成方案的设计,因此大家做出的设计都差不多一样)
这里再谈一下可复用与“逻辑实现”分开之间的联系(主要出现在设计期和重构期)
我们一直提倡逻辑与实现分开(这是设计的基本准则),这样设计有没有做到呢?,这里要说一下实现与逻辑分开,然而即便是这个说法本身也有点含糊,说实话这绝对是一个具体问题具体分析的活,(就以上面的设计来说,我至少可以找出几个逻辑与实现的说法,比如,但是大体上可以分为二类,Generic外部的和内部的,反正我自认为上图已经体现了足够好的逻辑与实现分开,如果你不这么认为,那么你一定有比我更好的方案,不妨说出来听听或指出我的缺点,对于实现与逻辑分开,我曾认真思考过为GameLogicGeneric中的每个个体增加一种联系到GameShowGeneric,但是这个设计我后来放弃了,这样做看起来合理实际上只会增加实现与逻辑的偶合性而且在实现上也是很复杂的,而且压根就不需要这样做因为GenericInterLogicPolicyLib已经是一种很好的方案,已经是一种根本的实现与逻辑分开策略,,需要作一层复杂的中间封装逻辑,这层抽象可能被集成到GameGeneric中)一个游戏GameGeneric就是LogicGeneric加上ClientSideGeneric的总和(逻辑上下或平等互饰构成逻辑总和,应用于是被建立起来)并由此定义出一个游戏比如NotWar3(这才是真正的编码与实现部分,就是几个Demo中要谈到的),或者我们可以把实作出的LogicGeneric置于ClientGeneric的底层(,这正是我们要采取的方式,作为中间逻辑的库之间应如何架构,它们之间的逻辑应如何,这也是我们要考虑的)。
我的一些不成熟的尝试和不成熟的思想导致的设计缺陷
1. 我曾设想Lua部分写Game.dll,我把总架构做到了扩展逻辑之后作为Lua代码,因为我认为那是具体游戏的事而不是GameEngine的事了,因为我还觉得“具体游戏才是游戏”,而这里的GameEngine似乎称为“用计算机模拟游戏世界的引擎”(ComputerSimutWorldEngine)更为合适,因此GameEngine.DLL最好的说法是VREngine,但是另一方面,也有另外一种做法那就是把扩展逻辑和VR逻辑中间放置一个Game总架构逻辑,这样G总架构逻辑就在Lua之前了,会是C++的代码,这样也是一种非常好的选择)游戏是一个对等或C/S的模型,因此分PeerSideGeneric和ServerSideGeneric,(我一开始设计时GameGeneric曾把这二个设计原语加了进去,说实话这就不是一个好的设计,因为只要在具体游戏的逻辑中才会出现客户端和服务端之说,而GameGeneric管理一些更为低层的逻辑,这样做就犯了设计的大忌,过早把实现混合成架构做进了设计中)
2. lua扩展是不是限制了lua级扩展的瓶颈(要深克明白脚本机扩展导出与动态修改的作用区别),因为导出的逻辑有限?当然这个扩展接口并不能导出全部的中间逻辑,实际上也没有必要(LUA级的扩展不需要导出从一开始到GameGeneric的全部中间逻辑)这里要深刻理解这个扩展接口(因为多范型设计与细节有关,只要明白各个中间抽象层次应有的细节,才能依据它来进行多范型设计),扩展接口架构在GameEngine之上(但并不需要导出这个构架),但是扩展逻辑不只是封装GameEngine这个中间逻辑层的某些接口(即它不是一个纯粹架构于GameGeneric之上的中间逻辑,虽然在原语设计图中它是,然而在范型实现中并不是这样),而是分别对其它中间逻辑层次有引用(即它必须对OIS有导出逻辑才能在扩展接口集中提供一个屏蔽鼠标的LUA接口,必须对RAF作导出逻辑才能在扩展集中提供启动一个游戏的功能,必须对CAMERA作导出才能在LUA级提供一个变换视角的游戏—而这个功能正是LUA级扩展必要的,,因为玩家写地图时总要调用到变换视角的功能,,比如通过LUA扩展出的一个泛RPG的FPS游戏,LUA护展级应提供什么功能和接口,可以参照WAR3WORLDEDITOR中的全部开关功能)LUA级的扩展全部是函数级的接口,而不是OO级的架构,,一方面是因为用LUA编程的玩家你不能要求他们有OO范型的思维,另一方面是因为实际的通过LUA扩展的过程只要用面向过程就够了并不需要形成一个架构,无非就是转动视角,控制游戏开启这些简单对外的逻辑,对内的扩展只能通过为Game.DLL写DLL来扩展----(而且LUA本身支持OO也不是很好)当然也存在另外一种做法,这就是把GameGeneric这整个抽象层次作为为Extend Generic服务的基础,也即它并不指代一个“Game”,并不打算把它设计成一个架构,而只是简单的对要导出的库(比如VREngine的方方面面)扩展封装,这样GameGeneric实际上就是1,GameGeneric加2,Extend的综合了
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

5#
 楼主| 发表于 2011-10-22 19:03:27 | 只看该作者
13.3 GVWL1.0开发
荒世:一个简单游戏引擎的实现
这一部分的目的就是为了产生一个游戏引擎可复用库,向读者展示的是设计能力。。
这里的设计在不同的情境下有二种意思,1,面向复用的工程设计,2,用语言映射现实问题的解法。。
当然,这不是游戏引擎,,仅仅是个可称为图形引擎的东西(当然,限于教育目的,我并不打算把它写得跟ogre一样面面具到不提供很多接口过多选择,比如GL,DX)。然而,通过增加网络逻辑,等其它方面的逻辑,它就可以形成为一个游戏引擎(作业:重构里面有相应的作业)
这个游戏引擎充分利用了stl和loki逻辑。而且还复用了OPENGL,我始终相信stl和loki才是标准库,为了最大清楚程序地呈现利用C++和这二个语言标准库来设计应用,,,我没有引入太多的库,,我克意不引进太多的第三方库,(所以很多小逻辑我都直接发明轮子以避免使用到第三方库),,因为这是基于前述清楚教育的目的而且我个人能力也有限,,(比如下面我不会的碰撞检测逻辑所以我刚好省掉它);,所以这个游戏引擎也是省略了很多功能的(比如碰撞等瓴域逻辑,本来一般图形引擎和游戏引擎是需要ODE的但我省了),。但这个库作为游戏引擎,最最基础的功能它还是都包括的,你完全可以二次开发,加入更多复用逻辑或自己的逻辑,,将其扩展成大全的游戏引擎。
这个产生的库要求很强的扩展能力(很强的被复用能力,所以要求基于复用的设计元素),所以我用了LOKI,OO方面的东西用得比较少(因为我相信template 加loki的设计能力和理念作为设计标准库,就该善用它,而OO更应该用在非设计的实现中,因为用OO设计复用时需要大量的学习成本,不应用OO 的眼光对设计分层级)。
当发展具体游戏也即实现部分时应该远离设计, 毕竟复用是设计复用,而不是实现复用,,但这个实现也有这个实现意义上的设计(因为二者根子上都是软件抽象的本质),设计与实现这二者是在某个范围相对的,而且只有模糊分界,,面对整个系统时架构师有划分,而且在程序员某模块中也有小设计,所以C++的各项语言能力,都可用来设计或编码,它是应用语言也是设计语言,,只是OO不太适合出现在面向复用的设计中):不要提供很大的跟OO一样的logics,,,只有通过设计模式串联起来的才是大逻辑(这才是银弹,OO维度太低了),,其它的都是小逻辑,就跟boost里面的库一样。。
设计中主要解决的大大小小的瓴域逻辑有如下(因为这些库逻辑最终要进入实现,所以我只在设计中含有最基础最原子的那些功能和接口,比如图形方面的逻辑,动画啊什么的,(这是业务领域的轮子,,外来轮子才是另外轮子,源程序树应该另外轮子各占一文件夹,主就放在根文件夹内),更高阶部分才发展业务领域逻辑,发展更高阶的逻辑,比如场景管理,资源管理,,

13.4 范型设计与实作
那么以上多范型设计图中,“面向用户和开发者”的高阶接口应提供什么呢,这并不是一个有标准答案的问题(这不可能是一个形式的活动,只能是一个感性的活动),根据“设计的方法学”,我们只需做列举题与选择题,比如以下:
1, 是不是应提供一个“”,我以前想到用Actor封装,Stage封装
2, 如果要提供播放CS的逻辑中间件,(因为CS可能要获取网络)那么是不是应提供一个类,这个类接受网络参数,这样就有引用到Yake 的Net,不,,绝对不能这样,,,这样会增加表现与逻辑的联系,,这样做出的类(集)接口就是不好的接口设计,,,想要什么样的应用逻辑总是可以用逻辑互饪的方法达到,,而基础的中间逻辑件部分只应提供属于它自己职责的独立逻辑。最好不要与其它逻辑交叉(往往将远离应用的中间逻辑称为真正的接口,,,而靠近应用的实现逻辑,,或应用逻辑本身称为真正的实现,,只要不过早地将实现逻辑做进或混入接口逻辑,,那么你就做到了实现与逻辑分开,,,也即这里“真正的接口”主要就是发挥桥接作用的接口逻辑,因为接口逻辑也算是中间逻辑,应在这些抽象层次上提供少量逻辑,,,,后来的大量实现逻辑靠前面的接口逻辑来扩展,,)
我们要写什么样的实现呢,注意我们还得为实现构造一个架构(实际上这个还可做到GameGeneric之上,但是这个应该属于具体游戏的逻辑了,因此我们还是做到NotWar3的Lua代码构架中去)
纯逻辑的库ODE,也跟LogicGeneric一样吧,,不需考虑平台相关,Logic级应提供什么功能接口,应参照WAR3的JASS的二个基本文件来设计,那里有大部分游戏世界逻辑(但JASS用了过程,这里是C++用OO来实现),,应考虑到游戏世界这个相对它的Plugable dll的“高阶”中间逻辑层次应提供什么逻辑跟接口(很明显,这里面应有一个能容纳Plug逻辑的引入逻辑的架构(但是YAKE的引入库逻辑是引用现有的库,而这里的总架构是先于PLUG的,因此更为灵活和自由,应提供类ADDAFORCE之类的总扩展接口,才能为PLUG留足够好的对主LOGICL架构的扩展空间),和一个类YAKE BASEGENERIC的实现集,因为需要用到DLL和LOG机制,),
下面设计出一个UML图,这步开始,我们就进入设计的编码实现了,这步过后,设计就完成了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

     
    Archiver|手机版|小黑屋|( 沪ICP备12034951号 )

GMT+8, 2024-4-28 11:34 , Processed in 0.266933 second(s), 29 queries .

© 2001-2011 Powered by Discuz! X3.1

快速回复 返回顶部 返回列表