云风的 BLOG - RSS Feed

思绪来得快去得也快,偶尔会在这里停留

Latest articles

Tag set 的数据结构优化

在最近实现的 ECS 库中,Tag 是一种非常重要的数据结构。它是一类特殊的 Component ,不携带数据,但会关联到同一 Entity ,最重要的用途是用于筛选。我在设计 Comonent 的数据结构时,采用了一种简单的数据结构 。它采用连续内存储存的数组,按 Entity id 有序排列。并在查询算法上做了一些优化,可以使得大部分查询时间小于 Log(N),接近常量时间。 但是,这样做的代价是插入和删除操作都是 O(n) 的。为了避免大量的插入删除操作堆积在一起时,整体的时间复杂度变成 O(n^2) ,我禁止 Component 的删除,而删除 Entity 改为标记,待一帧结束后一起删除。这样,可以让批量删除保持在 O(n) 的复杂度。 标记操作实质上就是打...

ECS 模型下的处理模式

最近在公司内做了一次两小时的分享,介绍了一下我最近几年对 ECS 模型的一些想法以及最近在项目中的应用心得。 我分享的主题不叫 ECS ,而用了一个更宽泛的名字 Data oriented design 。因为我不想局限在 Entity Component System 这些具体名词上。从 wikipedia 上看 ,DOD 的提出是源于游戏软件对性能的追求, 它主要围绕的都是其数据在内存中的组织形式不同。和 C++ 这类可以直接控制对象内存布局的 OOP 的语言的默认布局相比,DOD/ECS 的数据布局对 CPU Cache 更好友一些,从而可以获得更好的性能。 如果从这个角度看,如果不是用 C/C++ 这些可以直接控制数据内存布局的语言,采用 ECS 的意义很小。 但是,我觉得...

带猜测的二分查找算法

我想用 C 实现一个内存紧凑的 ECS 框架,希望数据结构足够的简单,且能管理海量的对象。所以我让每个 component 就是一个不包含任何引用的 struct ,并带有一个 32bit 的 id 。并把这样的一个数据结构放在一块连续内存中。 这个 id 没有对外暴露的 API (不是 entity id ),可以在运行过程中调整。如果两个不同类型的 component 有相同的 id ,即认为它们同属一个 entity 。id 的作用是管理 component 的生命期,以及在遍历 component 时,可以找到同个 entity 上其它的组件。 对于我的应用场合来说,最多的操作是遍历单类 component 的集合。这种操作在这个数据结构下特别简单,就是 for 循环遍历一个简单的数组。但有些系统会需要在处理一个...

缓存在 Lua 中的配置表

最近在尝试做一个类似异星工厂的游戏原型。由于最终希望在内存有限的手机上运行,所以不得不考虑内存如何有效利用的问题。 这是因为,我在玩异星工厂(加上一些 mod )时,发现 PC 内存能占到 10G 以上,且这些内存大部分都不是图像资源,是实打实的逻辑数据。我稍微估算了一下,在一些内容丰富的 mod 中,游戏内的对象能够达到数十万,甚至上百万之多。用传统方法使用的内存势必以 G 计算。 如果希望同样的逻辑跑在手机上,我希望把逻辑数据控制在 500M 之下。除了从游戏玩法做做一些限制外,还需要对逻辑占用的内存精打细算。 在 C 中实现一个 ECS 模型是一个不错的选择。 每个 Entity 仅包括必须持久保存的数据。很多数据都只在同一个 tick 计算中间使用,并不需要一直保存在对象中。...

ANSI escape code 及 Lua 封装

这两天想给一个想法做个简单的原型,因为涉及人机交互,需要在屏幕上绘制一些简单的交互元素。当然,现在有很多工具可供利用。过去遇到这种事情,我会尝试用已有的各种开源游戏引擎(我尤其推荐 PICO-8),或是直接在浏览器中用 css/javascript 写等等。 最近几年我玩了大量 RogueLike ,想尝试一下在 console 下用 ascii 字符来拼凑画面。这很有趣,能让我回忆起小时候 Apple ][ 上花掉的大把时光。同时我想用 Lua 来做开发,却不想引入 ncurses 这样的第三方库。最好能用几分钟就可以从零搭建起开发环境。 最好的选择当然是用 ANSI escape code 通过标准输出在 console 界面上作画了。 需要用到的是 CSI...

构建工具从 Make 到 Ninja

最近,我们把自研游戏引擎的构建工具从 GNU Make 迁移到了 Ninja 。 迁移动机是这样的: 我为引擎编写了最初的 Makefile ,它可以很好的工作在 MinGW / MacOSX / iOS 平台。把基本框架搭好以后,用起来也比较方便。但是,参与开发的同事一直有用 MSVC 开发的需求,而我们迟迟没有在 Makefile 的框架里增加 MSVC 的支持。用 MSVC 的同事一直在手工维护一个 MSVC 的项目。 渐渐的,同时维护 Makefile 和 MSVC 的工程成了一个负担。 实际上,现在惯用的方法都是用一个高阶的语言去描述项目构建流程,再翻译成不同平台下的构建脚本。即使用 GNU Make ,通常我们也是先用 Make 本身设计一个框架,在这个框架下去描述构建脚本,再让...

扩展 Lua 的常量类型

最近有点关于 Lua 不成熟的想法。 Lua 目前函数原型的常量表只支持了布尔、数字和字符串类型的常量。而 table function 这些是不会存在于常量表中的。 我想,如果常量如果不限于前三种类型,可能会更好一些。比如,一个惯用法是在代码前面写上 local pairs = pairs 这个惯用法是基于 local 变量比全局变量少一次 hash 表查询,性能可能会高一点。 但实际上,往往差距并不大。而这种写法还会给其它应用 pairs 的函数增加额外的 upvalue ,很有可能得不偿失。 但我们真正需要的是让 pairs 这个 light C function 是一个像 1,2,3 这样的常量。不必增加额外的 upvalue 的负担。...

选择开源项目的几点原则

本周末,阿里集团会在中南大学做校招。我作为校友,被邀请面向应届毕业生做一次技术分享。我想谈谈开源的问题。 由于技术分享的时间很短,我想在现场不太可能展开谈。所以在 blog 上先写一篇相关的子话题:在选择使用开源项目时,我的依据是什么? 我们在开发软件的过程中,总有一些模块的需求是普遍的,除了自己开发,使用一个具备合适的 License 的开源项目也是个不错的选择。 在一个程序员的职业生涯中,总会有那么一个阶段,不太愿意使用别人开发的代码。如果不是受项目进度压力所迫,宁愿自己实现。这并非是因为相信自己总能做得更好,而是希望少受牵制,能够自由发挥。而且,写代码往往比理解代码更简单。整合多块不同团队开发的代码也更难保证项目各个部分的一致性。 如果渡过了这个阶段,不那么执着于自己造轮子,选哪一个轮子必然会接受自己挑剔的眼光。毕竟,按捺了自己实现的冲动,要选也要选个合适的。...

服务的创建和退出问题

TL;DR 系统中每个和系统活得一样久的单元(服务),都应该提供一个关闭接口,而不是释放接口。关闭只做必要操作,不必释放资源,不必和其它单元协调。整个系统退出时,只需要命令所有单元关闭,然后让世界戛然而止。 最近在和同事一起完善 ltask 。这个项目可以看成是对 skynet 的一个回顾。我们打算把它用在客户端引擎中。 在 ltask 中,原来在 skynet 里用 C 实现的 timer network 等线程都被移到了 lua 中实现。它们被成为 exclusive service ,会独占一个操作系统线程,但之外的部分和普通服务并没有太大区别。 因为这样一些基础服务也挪到了 lua 中实现,以前在 skynet 中天然而成的层级被模糊了。在 skynet...

fbx 到 gltf 转换问题

我们的游戏引擎采用的资源格式是 gltf 2.0 。 gltf 在这几年发展很迅猛,我认为是 3d 文件格式中标准化做的最好的一个。可惜,游戏行业中,美术创作人员常用的 max maya 等工具对其支持还有瑕疵。Autodesk 在 2019 年作为 contributor 成员加入了 Khronos 组织,在 max maya 这些 Autodesk 工具中看到官方的 gltf 支持应该不会等太久。来自官方的消息 ,‎在 2020 的 3 月底,gltf 加入官方支持已经处于 Under Review 状态。希望今年内可以看到。 因为 Unity 的流行,fbx 是游戏行业目前的实施标准。但 fbx 是一个私有格式,并没有任何公开的标准文档。而且其格式设计有很多历史包袱,甚至连字段名都因为有...

Discover, share and read the best on the web

Subscribe to RSS Feeds, Blogs, Podcasts, Twitter searches, Facebook pages, even Email Newsletters! Get unfiltered news feeds or filter them to your liking.

Get Inoreader
Inoreader - Subscribe to RSS Feeds, Blogs, Podcasts, Twitter searches, Facebook pages, even Email Newsletters!