跳转至

云风的 BLOG

一些星舰或太空站建设类游戏

因为玩了一些星舰或太空站建造类的游戏,找找灵感。每个游戏都能给我一些启发,因为玩的都不多,所以就不评价了,只做个列表记录。有些还没有出,先加了个愿望单。 Adaptory Astro Colony Cosmoteer Deep Space Outpost Facteroids Factorio mod : Space Exploration Factorio mod : Warp Drive Machine Far Sector Generation Nova Generation Ship IXION Ostranauts Oxygen Not Included DLC: Spaced Out Rimworld mod : Save Our Ship...

监视 Lua 对象的修改

我正在制作的游戏 demo 中,所有对象逻辑上都存在于二维空间,但在 Ant Engine 中通过 3d 渲染方式绘制出来。 我希望有一组简便的 API 方便我控制这些对象的渲染,只是控制它们的位置以及在 Y 轴上的旋转量。Ant Engine 是用场景组件来控制 entity 渲染时的空间状态,但场景节点使用的是 3d 空间的 SRT 即缩放、旋转、位移。而我只需要控制其中的两个坐标轴上的空间位置以及一个旋转轴上的旋转量,直接修改 SRT 太不方便了。而且,使用引擎时,还需要每帧标记被修改过的场景组件对应的 entity ,这也很麻烦。 在 ECS 结构下,最简单的方式是为这些 entity 创建一个额外的组件,里面有 x y r 三个值。通过一个 system 把它们转换到场景节点在 3d 空间下的 SRT 组件中。但如果每帧都全部转换一次显得多余,毕竟大部分...

一个游戏的点子

宅在家里一个月了。一直在想,如果不考虑迎合市场,不顾及销量,到底应该做一个怎样的游戏才能让自己在制作过程中得到满足。 过年前曾经参加过一次老同事聚餐。组织者说,这屋子坐的都是做游戏的老人了,程序、策划、美术全齐了,还都是不差钱的主。大家要不要凑个局,想想做个啥游戏出来?接下来是一阵沉默,直到有声音说,“我没什么想法”,饭桌上的人纷纷点头,转移了话题。 前段参加一个独立游戏活动,见了些老朋友。有位同学做游戏很多年了,说起这些年的经历,入行头几年是给老板打工,接下来开了家小公司自己做,没赔钱也没赚钱。但干下来感觉变成了给员工打工。为了可以持续发出工资,每次立项都很匆忙,结果还是在不喜欢的游戏项目上耗掉了太多时间。现在干脆把团队安顿好,一个人出来,好好想想到底要做什么。 可见,想清楚做什么很难。单独一人的状态也很难得,没有太多的外界干扰,不为了做事而做,可以慢慢来。 首先,我想做一款游戏,这毋庸置疑。玩游戏是我这些年最大的爱好。光在 steam 上这些年就花掉了上万小时,switch 上也有几千小时。我能在制作游戏的过程中获得我要的东西。 其次,做一款游戏的目的不是为了收入。我对物质生活要求极低,不需要花钱满足欲望。除非需要雇人一起做游戏,不然制作游戏的开销只是自己家庭的日常开销,而我这些年的积蓄已够过完余生。我喜欢的游戏都不需要太复杂的美术资产,这方面并不需要额外的投入。 另一方面,我也不需要用游戏讨好玩家来获得成就感,不需要用一个产品来证明自己,这些成就感的体验都已有过,不是我想追求的东西。 所以,我所需要的是制作过程带来的持续体验,让自己觉得自己在做一件有意义的事。我所喜欢和擅长的其实是:认清问题,解决它们。...

Ant 的资源内存管理

这两天着手做游戏 demo 时发现 Ant 的 Asset 管理模块之前还留有一些工作没有完成。 那就是,当游戏程序加载 Asset 后,资源管理模块何时释放它们的问题。在 ant.asset 模块中,我们为每种 asset (以文件后缀名区分)定义了 loader unloader reloader 三个接口,分别处理加载、卸载、重载的工作。 但在实际实现时,几乎都没有实现 unloader 。当时是偷懒,因为我们之前的游戏即使把全部资源都加载到内存,也没多少数据,并不需要动态卸载释放内存。而即使实现了 unloader ,管理器也没有实现很好的策略去调用它。只能靠用户主动调用卸载 api 。事实上,一个个资源文件主动卸载也不实用。 考虑到占用内存最大的 asset 是贴图,我们又对贴图做了一些特殊处理: 所有的贴图都可以用一张空白贴图作为替代。引擎有权在任何时候(通常是内存不足时)主动释放长期未使用的贴图,并换用替代。这个特性也可以很好的适配异步加载过程。 所以,未释放的贴图并不会撑满内存。...

重新启程

今天,是我在广州阿里中心办公的最后一天。虽然 Last day 设定在了 5 月 20 日,但后面全部是假期,应该不会再回来这里。这些年的年假我都没有用过,总是到年底自动作废,今年算是休全(一小半)了。 回顾我的职业生涯,2001 年之前在北京经历了创业,而后又短暂的工作了数月。之后便在网易工作了十年 ,直到 2011 年离开 。2011 年底,我们创办了简悦,原本以为会把这家公司一直开下去,但在各种机缘下,于 2017 年底被阿里巴巴收购。之后,我便退出公司的管理,专心开发游戏引擎。 每段经历,印证着不同的心境。幸运的是,每次开始和结束,都是我的自主选择。感谢那些容忍着我的任性的伙伴,而我执着于自己想法的同时,也回报了周遭的人。...

大批量动画模型的优化

最近和公司一个开发团队探讨了一下他们正在开发的游戏中遇到的性能问题,看看应该如何优化。这个游戏的战斗场景想模仿亿万僵尸(They are billions)的场景。在亿万僵尸中,场景中描绘了上万的僵尸潮,但我们这个游戏,超过 500 个僵尸就遇到了性能问题。固然,手机的硬件性能比不上 PC ,但 500 这个数量级还是略低于预期。 对于游戏中大量类似的动画物体,肯定有方法可以优化。我们来看看渲染这些动画可行的优化方向: 常见的方式是把僵尸先预渲染成图片,而动画自然就是多个图片帧。对于亿万僵尸这个游戏来说,它本身就是基于 2D 渲染引擎的,这么做无可厚非。...

死亡

早上上班的路上,在必经的一条马路,看到一个蓝衣人趴在路中间隔离带的水泥桩上。车流比较大,一晃就开过去了。我问坐在副驾驶的老婆:刚才那个人好奇怪啊。她说是啊,那个人怎么了?我说,昨天你没看到吗?他保持那个姿势已经一整天了,感觉连手指头都没动过。 说到这里,我赶紧把车靠边停下来打了 110 ,附近的派出所联系了我,说马上派人过去看看。我的心情久久不能平静。走在路上,我喜欢观察四周的细节,其实昨天就感觉不对了。路上没有血迹,我以为他/她(看不到脸)是在翻越隔离带时身体不舒服想休息一下。但一个人保持那种姿势几分钟而不动肯定不正常。如果昨天这个时候就报警或许更好呢?...

Ant Engine 的一些优化

最近一段时间都在公司内寻找项目可以合作推进 Ant Engine 的使用。我觉得自研引擎的一个重要优势在于我们可以针对具体游戏更好的做性能优化。在目标设备硬件性能允许的范畴内,把画面质量和交互体验做到更好。而同样的优化手段,在通用商业引擎上面做会困难的多,甚至无法顺利完成。 我们用 Ant Engine 制作的第一款游戏 Red Frontier 在一年前是性能完全不达标的。它在 iPhone 8 上甚至都达不到 30fps ,无法流畅游戏。很多性能问题是已知问题,比如我们用 Lua 搭建了整个引擎,一开始只考虑了引擎结构和正确性,把性能搁置在一边待后面再处理。 优化方案是一开始就想好的:借助 lua ecs 框架,把数据结构放在 C 内存中,必要时可以绕过 Lua 代码,直接用 C 代码控制核心数据。我们花了大约 3 个多月的时间将核心渲染系统用 C 重写后,就把性能提高了 1 个数量级以上。这个过程可以说是一直掌握在手中,按计划推进。 但即使可以让游戏运行在 60fps 下,优化的目标也远远没有达到。这是因为对于手机设备来说,用户更容易产生电量焦虑。在固定座位上插着电玩主机或 PC 游戏,玩家不会去想游戏机耗了多少电;即使把 switch...

重构 ltask 的任务调度器

ltask 是 Ant engine 的基础设施之一,在对 Ant engine profile 的过程中,我们发现了 ltask 的一些值得提升的地方。 我们希望尽可能的提升游戏帧率,缩短渲染每一帧的的时间。因为 Ant engine 是由很多并行任务构成的,任务调度器的策略会直接影响单帧需要的时间。 ltask 虽然和 skynet 想解决的问题是一样的:管理 m 个线程(任务/服务),让它们运行在 n 个 cpu 核心上。而它们的应用场景不同,ltask 目前用在游戏客户端,它由一两个重负荷任务和若干低负荷任务构成,优化目标是低延迟;而 skynet 主要用在服务器上,由数以千计的类似负荷的任务构成,优化目标是高负载。...

以非阻塞方式执行一个函数

在 skynet 中,服务之间并行运行,而每个服务自身的业务都是串行的。一个服务由开发者自行切分成多个时间片,每个时间片串行运行在不同的工作线程上。最常见的做法是在每个服务中运行一个 Lua 虚拟机,用 coroutine 切分时间片,这样从编写代码的角度看,任务是连续的。 这个设计的目的是,让开发者轻松享受到多核带来的并发性能优势,同时减轻编写多线程程序带来的心智负担。 用过 skynet 的应该都碰到过:当我们在服务中不小心调用了一个长时间运行而不返回的 C 函数,会独占一个工作线程。同时,这个被阻塞的服务也无法处理新的消息。一旦这种情况发生,看似是无解的。我们通常认为,是设计问题导致了这种情况发生。skynet 的框架在监测到这种情况发生时,会输出 maybe in an endless loop 。 如果是 Lua 函数产生的死循环,可以通过发送 signal 打断正在运行运行的 Lua 虚拟机,但如果是陷入 C 函数中,只能事后追查 bug 了。...