周末杂想

许久没有更新,上一篇文章居然是两年以前发布的。

再往前推一点,从大学毕业开始算,现在竟然一晃已经4年。工作四年中,我只跳槽过一次。跳槽前我在西山居,跳槽后我来到了网易,算一算也有2年了。能够一直在喜欢的行业和喜欢的公司里从事着自己喜欢的工作,我觉得我是一个幸运的人。

虽然我已经年近中年,但我的内心还是个少年人。翻看之前的博客,看到以前的我,我一直没有变,我依旧保持着对游戏和对技术的热爱。我认为Coding是一门手艺活,要不断地练习,才能保证技艺精湛。说到底,还是我能从编码本身中获得乐趣。

但我的一部分还是变了。随着所接触的技术、项目和代码的增多,我变得不那么像以前那样愤世嫉俗。我逐渐意识到大部分的技术是会受到所处时代和环境的影响的,每种设计都有着自己的历史原因和理由。具体来说,我不再讨厌java,也不再那么喜欢C++。但我依旧保留着一个良好的习惯,那就是去研究透彻自己所用到的每种语言。编程语言对于程序员来说就好比工具对于工匠,工匠应该熟悉自己的工具,这是再自然不过的事情。

我变成了一个技术上的从简主义者。我认为简单的方法如果能解决问题,那就不必要搞的太复杂。我觉得if..else..就很好,线性查找就很好,数组就很好。这是懒惰,但并不是天真。简单的方法除了更具扩展性,更好维护,通常性能也更高。我认为复杂的方法应该留给复杂的问题。

我向来不太善于给文章收尾,那就这样吧。

Unity3D根据Prefab自动生成UI类,并自动关联变量和控件

在制作UI界面的时候,我们需要获取界面上的UI控件,以实现对UI界面的控制。比如,获取文本框控件来输入文字,或者获取按钮控件注册事件回调。对于Unity3D来说,我们有两种方式把某个控件关联到某变量上。
  1. 静态关联:在类中暴露public变量给编辑器,然后在编辑器中通过拖拽控件的方法把变量和控件关联上。
  2. 动态关联:从UI界面的根节点开始向下遍历,一直找到自己想要的控件。
如果可能的话,当然最好是使用静态关联。这种方法不需要在游戏运行时查找控件,效率高于动态关联,因此能提高界面的加载速度。然而这种方式的痛苦之处在于,我们需要手动为每个界面编写对应的类文件,暴露变量,并手动在编辑器中拖拽控件赋予变量。考虑到每个游戏都会有巨量的界面,能否使用自动的方式生成对应的UI类文件,并自动关联变量呢?这样将会给界面开发提供巨大的便利,省去很多繁琐的事。

继续阅读

快速判断塔防迷宫中的割点(Tarjan算法)

凡是允许玩家自行建造迷宫的塔防游戏都有一个规则,那就是不允许玩家封死迷宫。目前我观察到的塔防游戏大概有三种处理方法:

  1. 基于魔兽RPG地图的塔防大多有这种设定,当玩家封死迷宫后,怪物会变成主动攻击玩家的炮塔。
  2. 另外有一些作品,比如《防御阵型:觉醒》,当玩家封死迷宫后,怪物可以从炮塔建筑的间隙中穿过。
  3. 还有一些作品,比如《兽人必须死》,游戏根本就不允许你在可以封死迷宫的位置建造炮塔。

第一处理方法是比较简单讨巧的。当玩家建造或拆除炮塔后,游戏必然会重新触发一次怪物的寻路。如果此时发现无法到达终点,那么久开启怪物的攻击性。

第二种方法更加简单,建造炮塔的位置并不是完全封死的,而是给一个极大的障碍权重值。这样,寻路算法自然会在路被堵死的时候穿越炮塔了。

难就难在第三种处理方法:我要怎么知道建造了哪些炮塔后路会被堵死?

继续阅读

基于Flash3D的粒子系统实现

因为项目需要,自己动手实现了一个粒子系统,同时为其编写了配套的粒子编辑器。由于自己对这一块并不是很熟悉,于是前前后后推翻重做了好多版,花费了大量的时间。所谓折腾使人进步,随着对粒子系统的编写、重构、优化,我自己对3D渲染的各方面也有了更深入的理解。随着时间的推进,粒子系统的设计也已经慢慢稳定下来,并经受了实际项目的考验。我想是时候记录一下自己在粒子系统这块探索的过程。

f

继续阅读

Flash骨骼动画渲染优化

这里的优化思路或许也不仅限于flash。优化说到底就是个发现问题 -解决问题的过程,首先使用性能分析工具找到瓶颈,然后再对症下药。

第一步:

在原有的设计中,我们的每根骨骼都是一个Object3D,会挂接在渲染树上,参与绘制流程。这样的方便之处在于我们可以很方便地把特效或者武器等物件挂接在某根骨骼上,只需要找到对应的骨骼调用addChild()就可以了。然而,这带来的比较大的性能开销:
1. 每根骨骼都要参与可见性判断、裁剪等过程。
2. 每根骨骼都要参与矩阵级联运算。

优化思路也很简单:
1. 把骨骼从渲染树上拆解出来,单独成为一套更新体系,省去了一系列可见性判断。
2. 原本每根骨骼的矩阵是相对于父骨骼的,现在会在解析模型的阶段将所有骨骼的矩阵预处理成相对于根骨骼的,避免了每次渲染时的矩阵级联运算。据说相对于根骨骼的矩阵在做插值时会遇到问题,但项目开发到现在,依旧没有出现肉眼能观察到的问题,所以这样是可行的。
3. 至于特效和武器的挂接问题,需要另外写机制实现,但总体效率会好过优化前。

继续阅读

优化Flash中的3D模型加载

最近在做一个公司的Flash3D页游项目,遇到了这个问题,前前后后断断续续也优化了一段时间,觉得还是有必要记录一下一些优化的心得。

Flash中加载资源一个最大的问题在于难以使用另外的线程加载资源。诚然Flash有Worker线程,但Worker存在以下几个问题:
1. 使用Worker要求客户的FlashPlayer播放器版本不能过低。
2. 不同Worker之间传递数据手段非常少,缺乏共享内存。使用ByteArray共享数据的话需要先把数据序列化成AMF格式,无论序列化还是解析都是一个耗时的操作。
3. Worker实际上是另一个swf文件,增加程序复杂度。
4. 需要使用FlashBuilder4.7才能开发worker,而4.7一堆bug。

既然只能在渲染线程中加载和解析模型,那么我们就只能力求加载速度足够快。同时,作为页游,模型文件的体积也要足够小。

继续阅读

如何写出健壮的C++代码?

这个问题是没有完整的答案的,我们永远在路上。

还有一种说法是,要写出健壮的C++代码,你要先能写出健壮的代码。

扯远了,回到话题。

昨天写了个类,功能是从字符串中读取算术表达式,计算后返回结果。实际上就是Python的eval()函数,不过C++和AS3都没有这个功能,所以要自己写一个。实现也比较简单,首先是要解析字符串生成逆序波兰式,然后再递归运算逆序波兰式得到结果。每个波兰式节点有以下定义:

enum RPN_ENTRY_TYPE
{
    OPERATOR_TYPE = 0,
    OPERAND_TYPE,
}

struct RPN_ENTRY
{
    RPN_ENTRY_TYPE eType;
    union
    {
        char chOperator;
        int nOperand;
    }
}

每个节点有可能保存着操作符(operator)或者操作数(operand),有一个枚举用以标识当前节点是什么类型,随后跟着一个存放着操作符或操作数的联合体。

继续阅读

关于C++变长参数的一些细节

存在仅含变长参数的函数吗?
当然可以,至少编译器不会报错。你可以像这样定义一个仅含变长参数的函数:

void foo(...)
{
    //...
}

不过这样的函数基本上没什么用,主要原因是你无法取出它的参数。C++通过宏va_start以及va_arg从函数的变长参数列表中取值,其中va_start用以定位变长参数列表的起始地址,这需要借助于参数列表中最后一个固定参数:

var bar(int firstArg, ...)
{
    va_list pArgs;
    va_start(pArgs, firstArg);
    int nextArg = va_arg(pArgs, int);
}

当然,由于函数的参数都在栈中,因此也许有些十分诡异的手段可以直接从栈里将参数抠出来,不过这些用法太高端,我也不懂。
继续阅读