shilei230

The genuine programmers use C++

 

2009年8月29日

工作体会

在深圳的这家WY公司做了一年多了,主要都是搞底层的算法,感觉有这么一些体会应该写下来,期待与哪位高手切磋:
1.数学为本:游戏设计里的很多问题的本质都能归结到一个数学问题,有意思的是这里用到的数学实在是太初级了,无非就一些矩阵,向量,四元数,曲线,插值等等;其实数学的功能极其强大,有微积分,组合数学,概率论,多项式,集合论,运筹学等等,只是感叹没机会用啊,最复杂的任务也只用到过一个最小二乘平面而已;
2.测试驱动:做算法的,考虑的是先让用例通过,然后提高效率,比如做的地平线裁减算法吧,用例出奇的多,这时只能搞可视化调试了,我的经验是宁愿多花时间写测试环境,也不要仓促下手,否则维护起来实在是太痛苦了。再比如寻路算法,每秒要被服务器调用上万次,坐标可能是任何数值,一不小心就可以哪里死循环了造成服务器不响应,另外效率要求还极其严格,所以一有机会就要及时return,呵呵;
3.注重调试:游戏模块一般都很大,自己只能负责部分,为了便于跟问题,一定要写便于调试的代码,例如:和别人模块交互一定要通过接口,因为这边是下断点的绝佳位置;日志是王道,非法返回的地方一定要写;要把复杂的代码统一写在一个地方,这样改错只要改一个地方等等;
先写这三点,希望同道中人不吝赐教,顺便把本人的博客“复活”一下,好久没更新啦

posted @ 2009-08-29 15:08 shilei230 阅读(1664) | 评论 (10)编辑 收藏

2007年8月29日

如何申请和使用内存?

考虑一个问题:函数内和函数外需要通过一块内存来交互(例如字符串),如果该内存是以局部变量的方式在函数内栈上分配的,那么随着函数的返回这个内存将被弹栈释放,所以,需要返回一块函数外部还有效的内存。解决这个问题有三种方式:
(1)在函数内部通过malloc或new在堆上分配内存,然后把这块内存的地址作为返回值返回(因为在堆上分配的内存是全局可见的)。这样将导致潜在的内存问题。因为调用者需要知道函数内部的实现,如果返回出去的内存不释放,那么就是内存泄露。或者是被多次释放,从而造成程序的崩溃。这两个问题都相当的严重,原因就是它不符合谁申请内存谁负责释放这一原则。
(2)在函数内部声明static型的变量,static的栈内存一旦分配,那这块内存不会随着函数的返回而释放,它实际上是全局可见的,只要你有这块内存的地址就能使用。所以,有一些函数使用了static的这个特性,即不用使用堆上的内存,又不需要用户传入一个缓冲区地址和其长度。从而使得自己的函数长得很漂亮,也很容易使用。但是全局的东西可以被任何人更改,安全性无法保证。
(3)让调用者通过函数参数传入一块他自己申请的内存地址,而在函数中写这块内存。很多Windows API函数或是标准C函数都需要你传入一个缓冲区的地址和长度。这种方式的好处就是由调用者来维护这块内存,比较直观,问题是在调用上要进行严格的初始化。不过相对来说这种方式把犯错误的机率减到了最低。

posted @ 2007-08-29 13:56 shilei230 阅读(156) | 评论 (0)编辑 收藏

2007年7月7日

反驳极限编程的四点理由

接触极限编程一段时间,找到以下四点反驳它的理由:
[1]代码质量
极限编程运用测试驱动开发(TDD),其理论基础是需求应该是可测试的,其目的在于保证软件系统的正确性和健壮性(测试用例足够充分的话)。可以这么认为:极限编程关心的是结果,不关心过程。因此它忽略了软件系统的结构性和开放性。我们知道结构性有助于修改,开放性有助于扩展,而极限编程却放弃这种追求,导致的结果就是产生一大堆丑陋的代码,而且随时有可能被彻底抛弃。
极限编程解决效率,结构性和开放性问题的对策是重构,它宣称重构无处不在,但是重构是一种补救的方式,为什么不在设计初期进行预防呢?极限编程回避不了这些问题,而只是将它们推到了后面的阶段,但是付出的代价可能会更高。
[2]工作进度
极限编程直接将代码作为文档,弱化传统文档的作用。既然如此,那么代码就应该有规范的格式和详尽的注释,以便提高它的可读性,但是由于极限编程采用的是团队合作方式,代码规范很难得到统一。那么通过注释吧,可是极限编程认为注释是一种负担,无法适应频繁修改的代码。
极限编程解决沟通问题的对策是结对编程,它认为频繁的沟通胜过面面俱到的文档,但是文档是永久的,沟通却是短暂的,大家可以看同一份文档,却要进行多次两两沟通,所需时间也许并不比写文档的时间少。更糟糕的是,经常地切换搭档将极大地破坏工作的延续性,只能拖慢进度。
[3]工作量
测试驱动开发具体应该怎么做呢?测试驱动决不是说代码从测试写起,在写测试用例之前,肯定要对需求有完整的了解,否则测试无从写起,其实这就是需求分析以及设计,还是与瀑布模型一样的流程,只不过没有文档化而已。唯一不同的是极限编程要求需求都是可测试的,因此要把这些需求翻译成系统测试用例,集成测试用例,和单元测试用例。由于写程序必须同时写它的测试,因此如果改程序则必须改测试,这将达到两倍的工作量。
[4]目的
极限编程认为需求是不断变化的,因此软件能满足当前需求就好,没有必要构造框架之类可复用的东西,它认为这是一种过度设计。这种思想是极端的,因为框架就是为了解决需求变化问题而出现的。举个例子,MFC就是一套框架(尽管我厌恶它),但是基于MFC却可以开发网络,多媒体,数据库甚至游戏应用程序。面向对象的目的就是为了复用,而且好的框架能够做到隔离变化,依赖抽象,如果认为软件系统的一切东西都是暂时的,无疑是与面向对象思想背道而驰的。

posted @ 2007-07-07 16:08 shilei230 阅读(207) | 评论 (11)编辑 收藏

2007年3月27日

针对TSE的特效系统

    本人将AFX从TGE版本移植到TSE版本,目前AFX的官方网站并没有推出该版本,以下介绍一下移植过程中主要的改动:
(1)粒子系统。TGE的粒子系统来自三个类:ParticleEngine,ParticleEmitter,Particle。三者的关系是前者管理后者。ParticleEmitter以一个链表来存储Particle,ParticleEngine则负责Particle的创建和删除工作。TSE的粒子系统将ParticleEngine取消,Particle的创建和删除转由ParticleEmitter执行,粒子的存储方式改为数组方式,以C语言的方式动态地扩展空间。
(2)地形网格。考虑这个问题的原因是要将纹理贴到地表(不同于Decal),主要用于形成光环。TGE的地形网格是以索引数组的方式存储,若干个连续的索引组成一个单位,每个单位或者是三角形Triangle,或者是一个扇形TriangleFan,前者直接存储三角形的三个顶点索引,后者则先存储共用顶点,再存储单独的顶点。TSE中将两种类型的数据统一成Triangle,并使用TerrBatch类封装了大量针对地形的操作。
(3)渲染方式。TGE使用OpenGL进行渲染,TSE使用D3D进行渲染。TSE提供了PrimBuild命名空间,能够很方便地将OpenGL语句以类似的方式移植过来,OpenGL中的各种渲染状态设置语句在D3D中也有相应的语句相对应。
(4)材质纹理
    TSE为了支持Shader,将材质单独提取出来。因此在移植模型动画特效的时候,要在模型类里做一些材质方面的处理。

posted @ 2007-03-27 17:04 shilei230 阅读(142) | 评论 (4)编辑 收藏

2007年2月3日

借鉴AFX实现TSE的效果系统

    Torque Shader Engine只提供了简单的几个类来支持效果,只能是小打小闹,要运用于商业运营,必须自己整合一套架构。我参考了AFX的实现方式,认为它的架构大致可以这样描述:
    AFX是面向TGE的一套效果系统,它由一个效果引擎和一个DEMO构成。构成效果引擎的单元被成为组件效果(Component Effect),它们有的封装了TGE的类,有的是AFX自定义的。所谓组件效果是指它们与效果引擎是相对独立的,这意味着AFX即可以支持在TGE中定义的一些原有效果,也可以通过修改和扩展各种适配器来定制新效果。
    效果引擎使用效果管理器(afxChoreographer)来管理效果,目前已实现了三种效果管理器:选元(afxSelectron)、效元(afxEffectron)、魔法(afxMagicSpell),其中比较完整的是魔法,它将效果分为若干阶段(afxPhrase),使用载体(afxMagicMissile)进行抛射。效果管理器管理若干统一格式的效果包装器(afxEffectWrapper),并使用限制器(afxConstraint)来将包装器应用于特定目标,例如地点或人物。
    包装器的作用是隐藏具体效果的底层细节,使得所有的效果在外部看起来都一样,用面向对象的话来说就是实现了多态性,这样AFX支持的效果不仅可以是图形的,也可以是声音和脚本的。效果分为两种:被动效果和主动效果,两者的区别在于后者会改变其它的对象而前者不会。因此被动效果可以只在客户端运行,而主动效果必须通过服务器来运行。包装器使用修改器(afxXfmModBase)调整效果的位置、方向和视点,每个包装器可以使用若干个修改器。
    限制器的作用是将效果与特定的游戏实体关联,关联目标可以是一个点,一个模型,或者模型的某个部分。限制器提供历史记录功能,因此能够很容易重用效果的限制记录。
    受AFX启发,我将效果分成粒子,贴花和模型三种类型,配合动画来实现效果。重点考虑效果的组合、限制和修改机制,便于将来的扩展。目前已经正式开始动手,希望能够早点有所收获。

posted @ 2007-02-03 17:21 shilei230 阅读(187) | 评论 (1)编辑 收藏

2006年11月28日

Torque Shader Engine

Torque Shader Engine 是最新出现的一套商业游戏引擎,它的前身是 Torque Game Engine ,如今已是 XNA 框架的有机组成部分。 TSE 秉承了 TGE 的脚本系统,文件目录结构清晰,它对 TGE 的改进之处主要在于将 Material 独立出来,使用脚本配置材质属性和附加 Shader ,可以利用最新的硬件实现特效。

但是 TSE 只是一款 FPS 类型的游戏引擎,代码很零乱,性能不稳定,存在不少 BUG 。看过它的类图之后,我认为该引擎效果不错,但是结构不合理,给人一种拼凑的感觉。它的主框架,效果系统和物理系统的实现并不高明,当前甚至不支持 OpenGL Garagegames 的那帮老外写代码到底是急功近利还是尚未优化,真叫人拿不准,如此质量,难怪只卖 100$

posted @ 2006-11-28 17:04 shilei230 阅读(314) | 评论 (0)编辑 收藏

2006年10月20日

Cg之我见

    说来惭愧,学了这么久的图形学,今天才动手编了自己的第一个Cg程序,参考的就是那本《The Cg Tutorial》。Cg的GPU概念彻底改变了我对图形学的看法,传统的程序都是由CPU执行的,这种观念在其它方向的程序员看来天经地义,但是对于图形程序员来说,从2002年Cg诞生开始就已经颠覆了。面向GPU编程,让CPU解放出来,能够极大地提高了渲染速度。还有,它实现了可编程的渲染,对于游戏来说,就意味着能够以脚本的形式来渲染场景了,如果再配合那些AI脚本,游戏引擎基本上就能够建立在脚本之上了!大部分的C++程序员都会对Cg有种似曾相识的感觉,因为它是面向图形的C语言,配置和编程都很符合习惯。对于使用DirectX的游戏程序员来说,Cg与HLSL其实上同一种语言。我个人认为DirectX的所有组件其实都可以使用别的工具代替,而Cg则是其中最高级的替代品,决定用它了。

posted @ 2006-10-20 21:36 shilei230 阅读(103) | 评论 (1)编辑 收藏

2006年10月7日

面向对象技术的困惑

        面向对象技术推崇的是分而治之的思想,每个类既有属性又有操作。它构建了模块化的模型结构,但是也带来网络式的消息机制。面向对象技术的难点就在于对控制流的建模,下面举两个例子。例一,一个组合之间各个单元之间的交互,例如页面之间的切换。过程式技术可以设置一个组合代理,通过代理这个中介来切换单元。如果使用面向对象技术的消息通信机制,不仅要大刀用斧使用线程,而且每个单元都要感知其它单元的存在!例二,为一个类附加一个功能,例如页面切换时执行载入或者统计。过程式技术可以使用函数映射表的方法,而面向对象技术只能使用虚拟函数和继承机制了,除去生成很多琐碎的类不说,如果功能函数涉及到多个对象,同样存在着感知的问题。写类谁都会,关键是怎样把他们组织起来以便使用,因此要想学好面向对象技术,多在接口(公有属性及值域、公有方法及参数等)上花些工夫吧。

posted @ 2006-10-07 20:52 shilei230 阅读(100) | 评论 (0)编辑 收藏

2006年9月28日

射击类三维游戏引擎

        毕业论文的初稿已经出来了,暂时可以先喘一口气,我做的是《射击类三维游戏引擎》,总的感觉是“麻雀虽小,五脏倶全”。我将引擎分成了七块:界面包、资源包、设备包、实体包、实用包、工具包和一个程序框架。界面包负责显示视图,资源包负责调度资源,设备包负责虚拟设备,实体包管理游戏中有意义的实体,实用包包括物理系统、效果系统、媒体系统和脚本系统,工具包包含一些数学和图形学的数据结构,程序框架采用Windows的消息驱动和消息映射机制。体系结构比较清晰,但是技术含量还有待提高。当前主流的游戏引擎都支持图形两套引擎(OpenGL和Direct3D)以及一门高级渲染语言Cg,而我的引擎只用了OpenGL,只能感叹自己学艺不精。图形学方面从来就不缺牛人,而且很多都是从数学转过来的,不过我也是从数学科班出身,也许几年之后...不管那么多,向人家取经吧。

posted @ 2006-09-28 11:30 shilei230 阅读(189) | 评论 (1)编辑 收藏

2006年9月19日

软件复用级别之我见

      软件复用程度的级别可以按以下准则来衡量(级别从低到高):
(1)函数:将那些重复或者类似的程序集中起来放在函数里,对外提供参数以利复用,是功能型的重用;
(2)实在类:将若干经常使用的函数集中起来,将函数的参数转化为类的成员变量,自定义构造和销毁函数,是资源型的重用;
(3)抽象类:使用纯虚函数对外提供接口,这些接口仅仅声明了基类的功能,而将实现拖延到子类中去,是强调可变性的资源型重用;
(4)包:将若干耦合度较大的类集中起来,统一地对外提供接口,是一种有机的资源型重用;
(5)模板:将变量的类型通用化,它是一种强调通用性的资源型重用,可以应用在上面四个层次上;
(6)组件:封装了数据和方法的可执行代码,上面五种都属于代码级的复用,而组件属于软件级的重用。

posted @ 2006-09-19 14:28 shilei230 阅读(247) | 评论 (2)编辑 收藏

仅列出标题  下一页

导航

统计

常用链接

留言簿(2)

随笔档案

文章档案

搜索

最新评论

  • 1. re: 工作体会
  • @diwayou
    视频编码确实挺痛苦,小波变换,头疼啊
    @Vertexer
    prt没试过,能否探讨一下,呵呵
  • --shilei230
  • 2. re: 工作体会
  • 呵呵,试试prt算法吧,或者水体模拟,尤其是能够互动的
    这其中的数学会让你爽呆的
  • --Vertexer
  • 3. re: 工作体会
  • 评论内容较长,点击标题查看
  • --shilei230
  • 4. re: 工作体会
  • 评论内容较长,点击标题查看
  • --oday
  • 5. re: 工作体会
  • 呵呵 陪测、测试程序、日志是人快速成长的保证
  • --路过

阅读排行榜

评论排行榜