September 27, 2014

随机地形生成

玩过 矮人要塞 Dwarf Fortress 的同学都会惊叹于它的随机地形生成系统。如果你对 ascii art 无感,那么可以 google 一下 stonesense 的图片。

矮人要塞是 3d 的地形系统。在游戏 wiki 上有介绍地形生成系统的参数细节

大体上是这样的: 首先有一张高度图(Elevation),决定了每个坐标的高度。然后给出一张降雨图 (Rainfall),来影响当地的植被和河流。通常降雨图是根据高度图(海岸和季风影响)计算出来的。这里有一篇文章简单描述了这个过程。

温度图(Temperature)一般根据纬度以及当地的海拔计算出来,也会影响当地的动植物。

地质的排水情况(Drainage)可以影响当地能否形成湖泊、湿地和河流。同样影响了当地的土质(进一步影响植被)。

另外还有,火山的分布情况(Volcanism),以及野生物分布图(Savagery) 会改变当地的矿产和动物分布。


阅读全文 "随机地形生成" »

September 21, 2014

ejoy2d shader 模块改进计划

由于有公司很多同事参与 ejoy2d 的开发,所以 ejoy2d 这个项目已经转移到 ejoy 的 github 名下。

有更多项目的参与的情况下,原来 ejoy2d 的简单构架慢慢显出一些局限性。主要是不同的项目会根据项目的需要(通常是针对某些特定需求的优化,以及特别的效果需求)修改底层 shader 的部分。最早设计的时候,因为考虑到只是用于 2d 游戏的开发,所以把 shader 模块实现的比较简单。特别是 attribute layout 是固定的,而 uniform 管理也没有留下太多扩展性。

在现代手机的 GPU 架构下,从渲染层渲染层 API 看,其实 2d 和 3d 其实没有本质上的区别。都是基于三角片渲染的。需要把顶点上传到 GPU 中由 vs 处理,在最后对像素做 fs 渲染出来。

而 2d engine 和 3d engine 的区别通常在于 2d engine 的顶点变换很简单。不需要用 projection matrix 和 view matrix 做变换。2d engine 中的对象多半是四边形,数量很多,常见的优化手法是将大量的四边型合并到同一个渲染批次中;所以 world matrix (以平移变换为主)在 CPU 中和顶点计算再提交更常见一些。

2d engine 从应用上说,就是在处理一张张图片。所以对图片(四边型)的处理的变化要多一些。这使得 fs 要多变一点,需要引擎提供一定的可定制性。但很少去处理 3d engine 常见的光照投影这些东西。更多的是为了优化贴图用量等目的而技巧性的去使用一些图片。

突出 2d engine 的专门面对的业务的特性,而简化 GPU 提供的模型,用简短的代码构建 engine 框架,是 ejoy2d 设计的初衷。而且我也相信,简单可以带来更好的性能。所以一开始设计 ejoy2d 的时候,shader 模块的很多东西都被写死了,以最简单的方式达到目的。仅暴露了很少的外部接口,再在这些有限的接口上设计数据结构,做性能优化。

阅读全文 "ejoy2d shader 模块改进计划" »

September 08, 2014

2014 IGF 评选

前两天受邀去上海参加今年的独立游戏节评选,准确说是亚洲及太平洋地区的 IGF 。

居然有接近 400 个参选游戏是让我事前没有想到的,尤其是在学生组还发现了不少好作品是个惊喜。

评审用了整整两天时间,从一大早到半夜,中间全部是叫的外卖。基本流程就是看介绍视频,(有兴趣)就试玩,讨论,反复这个过程。但明显还是时间不够用的(想想 20 多个小时看 400 个游戏是啥感觉?平均一小时 10+ 个)。

客观的说,大陆地区的整体水平还排不到前列,但也有几个亮眼的好游戏。有点不可理解的是,有些明显是 100 人以上的公司做出来的商业作品也来凑热闹。所以一般看介绍视频里有 “扫荡” 的基本都没试玩。我个人认为,IGF 还是要强调独立游戏精神的,对于可能获奖的游戏也主要是要设计出彩,好玩,而不太多考虑挖坑赚钱的因素。

出于保密的要求,就不写那些具体的很有意思的游戏了。不过可以泛泛的谈谈评审感受。

据说以往老外比较喜欢做 soul game ,可这次明显感觉反了过来。大陆地区无论是学生组还是职业组都有许多 soul game 。可惜试玩了一下,大多不明白在玩什么,甚至怎么玩都不知道。我想游戏毕竟还是以提供乐趣为住,即使是以往获奖的 soul game ,都还是很好玩的。

有些游戏拼了命的往复杂里做,各种定制元素,连我这个一向以玩复杂游戏为主的玩家都受不了。试玩 15 分钟完全开始不了游戏主线,也想像不到后面的乐趣。

抄袭现象也有许多。如果是商业游戏为了赚钱,复刻一个游戏倒没什么;但对于独立游戏,抄一个热门游戏也可以获奖?这次有 7 个评委,似乎很难瞒过这么多玩家的眼睛。当然,制作精良的疑似抄袭作品我们都仔细玩了一下,试图发现不一样的亮点,可惜很难找到。

这次也发现几款图像向 3A 游戏靠近的独立大作,可是…… 不好玩啊。整个就是炫引擎(以 Unreal 居多)和美术的,就一个人物在绚丽的场景里跑来跑去。只要想想,如果把这些游戏放到大厂家的 3A 游戏中对比,完全不会有因为画面而购买游戏的冲动。而游戏可玩性部分又接近 0 ,最终真是可惜了制作这些人物和场景的人工。

阅读全文 "2014 IGF 评选" »

August 29, 2014

近日工作记录

sproto 基本算完成了, 等 lua 5.3 正式发布后, 还需要把 64bit 整数支持一下。我给 sproto 加了 lua 封装,以方便更好的支持 rpc 。

子熏同学完成了 sproto 的 jit 版本。但似乎性能提升不是很明显。

我希望可以在 skynet 的下个大版本,把 sproto 作为推荐 C/S 通讯协议加进去。


目前正在开发的 skynet 新特性是可以把单个服务的外来消息全部 log 在一个文件中。目前支持了 skynet 的普通消息以及 socket 消息。如果有必要,还可以把组播消息加上。

目前这个特性主要用来调试。其实可以为之开发配套的工具,比如另外做一个调试工具,能够把所以记录的消息重放给一个特定的服务脚本,便可重现一个服务的工作历史。目前 log 文件中记录的消息时间和消息内容足以重现。只要消息中不包含内存地址,这种录像重播的测试方法应该是有效的。

不过暂时还没碰到需要这种调试(比如一个服务出现异常,可以利用录像回溯之前发生的事情,以及当时的现场),等需要时再根据需要制作这样的工具。


等 lua 5.3 正式发布后,打算把 pbc 跟进一下。skynet 里的 int64 支持也可以用 lua 5.3 官方特性取代。我相信到那个时候就可以发布 skynet 的 1.0 版了。


ejoy2d 这个项目,公司有许多同事有兴趣做进一步贡献。所以我把主仓库迁移到 ejoy 名下。

由于正在用 ejoy2d 开发的两个新项目比较紧,最近 ejoy2d 里增加了不少临时项目用的接口。暂时还没有精力去规整。许多新特性(比如粒子绑定,对资源异步加载的支持)都没能及时加上文档。

目前实测在 iphone4 上 ejoy2d 可能会有性能问题。为此,增加了一个 renderbuffer 的特性,可以把一批渲染的定点输出到固定的顶点 buffer 中,这对用复杂图素拼装起来的静态背景会有一些效果。不过关键还在于 iphone4 的 GPU 性能太差,稍微复杂一点的 fragment shader 就会很勉强,为次可能需要给 ejoy2d 加入更灵活的 shader 定制特性。

经过几天的努力,终于把我们新项目在 iphone4 上的 fps 从 12 提升到了 18 ,勉强可以接受了吧。离目标 30fps 还有一些距离,如果进一步的细调还是可以达到的,但会增加很多制作上的难度。不知道到明年,还是否需要考虑 iphone4 这个档次的硬件。


btw, 乘 steam 打折,周末玩了一天文明 V 的第二扩展,还是很不错的。非常期待年底的 beyond earth 。

August 12, 2014

STM 的简单实现

STM 全称 Software transactional memory

在前年的项目里,我制作了一个类似的东西。随着 skynet 的日趋完善,我希望找到一个更为简单易用的方法实现类似的需求。

对于不常更新的数据,我在 skynet 里增加了 sharedata 模块,用于配置数据的共享。每次更新数据,就将全部数据打包成一个只读的树结构,允许多个 lua vm 共享读。改写的时候,重新生成一份,并将老数据设置脏标记,指示读取者去获取新版本。

这个方案有两个缺点,不适合实时的数据更新。其一,更新成本过大;其二,新版本的通告有较长时间的延迟。

我希望再设计一套方案解决这个实时性问题,可以用于频繁的数据交换。(注:在 mmorpg 中,很可能被用于同一地图上的多个对象间的数据交换)

一开始的想法是做一个支持事务的树结构。对于写方,每次对树的修改都同时修改本地的 lua table 以及被修改 patch 累计到一个尽量紧凑的序列化串中。一个事务结束时,调用 commit 将快速 merge patch 。并将整个序列化串共享出去。相当于快速做一个快照。

读取者,每次读取时则对最新版的快照增加一次引用,并要需反序列化它的一部分,变成本地的 lua table 。

我花了一整天实现这个想法,在写了几百行代码后,意识到设计过于复杂了。因为,对于最终在 lua 中操作的数据,实现一个复杂的数据结构,并提供复杂的 C 接口去操作它性能上不会太划算。更好的方法是把数据分成小片断(树的一个分支),按需通过序列化和反序列化做数据交换。

既然序列化过程是必须的,我们就不需要关注数据结构的问题。STM 需要管理的只是序列化后的消息的版本而已。这一部分(尤其是每个版本的生命期管理)虽然也不太容易做对,但结构简单的多。

阅读全文 "STM 的简单实现" »

August 02, 2014

Unity3D asset bundle 格式简析

Unity3D 的 asset bundle 的格式并没有公开。但为了做更好的差异更新,我们还是希望了解其打包格式。这样可以制作专门的差异比较合并工具,会比直接做二进制差异比较效果好的多。因为可以把 asset bundle 内的数据拆分为独立单元,只对变更的单元做差异比较即可。

网上能查到的资料并不是官方给出的,最为流行的是一个叫做 disunity 的开源工具。它是用 java 编写的,只有源代码,而没有给出格式说明(而后者比代码重要的多)。通过阅读 disunity 的代码,我整理出如下记录:


阅读全文 "Unity3D asset bundle 格式简析" »

July 30, 2014

skynet 中如何实现邮件达到通知服务

skynet 中可以独立的业务都是以独立服务形式存在的。昨天和同事讨论如何实现一个邮件通知服务。

目前大概是这样的:有一个独立的邮件中心服务,它可以处理三条协议:

  1. 向一个 mailbox 投递一封邮件。
  2. 查询一个 mailbox 里有多少封邮件。
  3. 收取 mailbox 里指定的一封邮件。

用户读了多少邮件没有放在邮件中心,而是记在玩家数据里的。

用户的界面上需要显示是否有几封未读邮件,如果有新邮件达到,这个数字会自动变更。你可以想像成 iOS 上的那种带数字的小红点。

当然,在 skynet 的设计惯例中,每个用户在服务器上有一个 agent 代理,所以我们不单独考虑和客户端数据交互的问题,而只用考虑 agent 如何和邮件中心的交互。

现在的做法是,在用户上线的时候,就去邮件中心查一次,比较邮件数量后知道是否有新邮件,然后推送给玩家。

在玩家特定的操作后,比如进出副本等,都会重新查询一次。如果玩家在一个场景停留太久,客户端也会定期发起查询请求。

如果邮件必须在新邮件达到时,立刻通知给玩家怎么办呢?那么系统中另外有个用户中心的服务。邮件服务可以把消息推送到那里;用户中心发现玩家不在线,就扔掉消息;如果在线就做消息推送。


我觉得这个方案有那么一点点不好,所以提出了我的想法。

阅读全文 "skynet 中如何实现邮件达到通知服务" »

Misc

Categories

Archives

Recent Comments