superpowers:一个浏览器里的轻量级多人协作开源游戏引擎

发布时间:2026/10/29 22:56:00
superpowers:一个浏览器里的轻量级多人协作开源游戏引擎

1. 为什么我想聊superpowers这个项目

不知道你第一次听到"superpowers"这个词是在什么场合。我最早是在一个独立游戏开发者社群里看到的,当时有人在问"有人用过superpowers做多人协作开发吗",底下讨论还挺热闹。后来我去翻了一下这个开源项目,才发现它是一套基于浏览器的可视化游戏开发环境,而且它的定位很有意思:不是要跟Unity、Godot这些重型引擎抢市场,而是想让你用打开网页的方式,快速把一个小游戏的原型做出来,同时把多人实时协作这个能力做成默认功能。

这篇文章写给谁?主要是有过一点游戏开发想法但被工具门槛劝退的人,还有已经用Godot或Unity写过脚本、想找一个更轻量的协作原型工具的人。内容涵盖superpowers的安装启动、工作界面、脚本写法、多人协作玩法以及我踩过的坑,尽量把能直接抄作业的部分都写清楚。

先说我的结论:superpowers不是一个能直接替代成熟引擎的工业化工具,但它在"快速验证玩法""多人同屏改场景""现场教学演示"这几个场景里非常顺手。如果你是靠直觉做游戏、不想被资产管线绑住手脚的人,它值得你花十分钟试一次。

我实测下来,从下载到能在浏览器里打开编辑器,五分钟以内就能完成,整个开发界面就是在一个web页面上跑的,不需要装一堆IDE、SDK、构建工具链。这种低门槛本身就是它最大的特点。

2. 核心设计思路拆解:它为什么敢叫"超能力"

要理解superpowers,得先接受一个前提:它把游戏引擎拆成了"服务器 + 浏览器客户端"这套结构。

2.1 它跟传统本地引擎最大的区别

传统做法是引擎装在你的电脑里,项目文件放在本地磁盘,你要发给别人就得打包上传,别人改完再传回来。这个流程在一个人开发的时候没问题,但一旦两个人想同时改一个场景,就非常麻烦。

superpowers的做法是把项目托管在一个本地服务器进程上,所有开发者用浏览器连到这个服务器来编辑。你改场景、改脚本、拖动一个模型,这些操作不是写入本地文件,而是通过WebSocket实时同步到服务器,再广播给所有连着这个项目的客户端。

我用一个生活化的例子来解释:Unity就像每个人自己在家做饭,做好端到饭桌上拼菜;superpowers更像一群人围着一个灶台做菜,你放盐、我加糖,旁边的人立刻就能看见锅里变成什么样。它把"协作"从"事后合并"变成了"现场直播"。

2.2 为什么选择"浏览器即编辑器"这条路

很多人一开始会怀疑:浏览器跑编辑器,性能行吗?界面会不会很简陋?我实际用下来,superpowers的编辑器确实不如Unity Editor那样重度复杂,但它做了一些很有意思的取舍。

它内置的编辑器是直接在浏览器里渲染3D场景的,用的是Three.js这一套。也就是说,你的场景编辑器本身就是一个小型3D应用。你在编辑器里看到的画面跟最终游戏里的画面,本质上跑的是同一套渲染栈,不会出现"编辑器里很漂亮、导出来变了个样"的割裂感。

这对做原型来说是一个巨大的优势:所见即所得。

另外,脚本系统也直接在浏览器里运行和调试。写脚本的时候可以打开浏览器的开发者工具,console跟游戏运行时的console是同一个,什么变量没定义、什么组件找不到,直接看浏览器控制台就能定位。

2.3 它的脚本模型:不是"组件"而是"混合体"

如果你熟悉Unity,你脑子里大概会浮现GameObject、Component、Inspector、Prefab这些概念。superpowers的做法有所不同:它里面最小的单位叫Actor,Actor可以挂上一堆行为能力,这些行为能力在官方文档里叫mixins,你可以理解成"能力的混合块"。

从实际使用的感受来看,一个Actor不是一个空壳,它更像是"加载了一组能力的对象"。你可以给一个Actor添加"模型渲染"能力、添加"刚体"能力、添加"自定义脚本"能力,这些能力组合在一起,这个Actor就变成了一个可以在场景里移动的实体。

这种模型对做原型的人来说非常友好。你不需要去理解复杂的生命周期回调,也不需要被组件间数据传递的各种约定束缚,你只需要想清楚:"这个东西应该具备哪些能力?"然后把对应的能力加上去。

3. 安装与启动:一次成功的"零障碍"体验

接下来直接进入实操环节。我把安装步骤整理成一套可以照着做的流程。

3.1 第一步:确认你的电脑环境

superpowers本质上是一个Node.js应用,所以前提是你机器上有Node.js环境。不过有意思的是,项目也提供了不需要预装Node.js的便捷模式,你可以直接下载打包好的桌面客户端,内置了运行环境。

我自己的测试环境是Windows 11,Node版本是18 LTS,浏览器用的是Chrome,全程没有碰到兼容性问题。如果你是macOS或者Linux,一般来说也没有区别,因为最终操作都是在浏览器里完成的。

安装方式有两种,我分别说一下。

3.2 方式一:使用npm全局安装(适合Node用户)

如果你本机已经有Node.js环境,直接在终端里跑这行命令:

npm install -g superpowers

装完之后启动超级简单的服务器:

superpowers

启动成功后终端会显示一个网址,通常是这样:

http://localhost:8080

用浏览器打开这个地址,你就进入了superpowers的启动页。第一次启动会要求你设置管理员账号和密码,这个账号是用于管理项目和创建项目的,记好它,后面协作登录也会用得到。

3.3 方式二:下载桌面版(适合零基础用户)

如果你不想跟Node环境打交道,直接去superpowers官网下载对应你操作系统的桌面版压缩包。解压后运行里面的可执行文件,它会在后台自动启动一个本地服务,同时自动打开浏览器进入启动页。

桌面版的好处是省去了环境配置,而且更新的频率相对稳定。它的内部机制跟npm版是一样的,都是起了一个本地web服务,只不过这个服务被封装成了一个小程序。

3.4 添加项目成员与设置共享

superpowers的多人协作并不需要每个协作者都装环境,他们只需要能访问到你机器上的服务端口就够。

如果你跟队友在同一个局域网,你只要把本机的局域网IP告诉队友,队友直接在浏览器里访问:

http://你的IP:8080

比如我机器的局域网IP是192.168.31.31,队友访问的就是http://192.168.31.31:8080。

如果是远程协作,需要你自己做一次端口映射或内网穿透,把8080端口暴露出去。考虑到安全底线,我在这里不展开讲具体工具,只提醒一句:暴露开发服务器有安全风险,临时用一下记得关闭。

进入启动页之后,管理员在后台添加成员的邮箱地址,生成登录口令,成员就能用浏览器直接开干了。这个协作模型非常简单,不需要复杂的账号体系,重心全放在"谁能连到你的服务器"上。

4. 核心界面操作:第一次进入项目后的关键认知

当你创建好项目、进入编辑器,第一眼可能会有一种"熟悉又陌生"的感觉:左边是场景层级列表,中间是3D视图,右边是属性面板,底部有资源管理器。这跟主流引擎的布局很像,但细节上有很多不同。

4.1 场景树与Actor的层级结构

superpowers的场景树里,每个条目对应一个Actor。Actor之间可以是父子关系,父Actor移动,子Actor跟着动,这个跟Unity的Transform层级是一样的逻辑。

但superpowers有一个我个人很喜欢的交互:你直接在3D视图里选中一个模型,左侧场景树会自动定位到对应的Actor上;反过来,你在场景树里点选,右侧属性面板会显示这个Actor当前拥有的所有能力。

层级结构在设计角色、关卡部件拆分时非常好用。我习惯的做法是:建一个空Actor作为"根",下面再挂角色模型、灯光、相机、触发器这些子Actor。这样挪动整个关卡部件的时候,只需拖动根Actor即可。

4.2 属性面板:考验你对"能力"的理解

右侧属性面板展示的内容取决于当前Actor挂载了哪些能力。

如果你给一个Actor添加了"Model"能力,属性面板里就会有模型的URL、缩放、旋转这些参数。如果你添加了"Point light"能力,面板里就会多出颜色、强度、光照范围等参数。

这种"按需展示"的交互比Unity的Inspector更像一个抽屉柜:你装了什么工具进去,打开抽屉就能看到什么。你不需要在一堆无关参数里翻找,也不会被引擎默认的几百项设置淹没。

我实测下来的体验是,做一个简单角色控制Demo,需要改动的主要参数其实就集中在模型选择、平移速度、跳跃力度这几项上。整个编程心智负担远小于传统引擎。

4.3 怎么添加一个新Actor

在场景树面板的空白处,或者通过顶部菜单栏,你可以创建一个新的Actor。创建出来的默认Actor是空的,它只带一个"Transform"能力,负责位置、旋转、缩放。

要让这个Actor"看得见",你需要给它添加"Model"能力,然后在能力里选一个模型素材。superpowers内置素材库里有一些基础的几何体和几个示例模型,做实验足够了。当然你也可以在资源管理器里上传自己的3D模型文件。

这个操作思路跟"搭积木"很像:先有骨架(Actor),再往骨架上挂功能块(能力),最后在属性面板里调参数。

5. 核心玩法实现:动手做一个"跳方块"场景

纸上谈兵没意思,我带着你亲手做一个能在场景里移动、跳跃的小方块,把superpowers脚本系统最核心的部分过一遍。

5.1 想清楚我们要拆成哪几步

做一个最小可玩的第三人称控制Demo,我们需要四样东西:一个玩家Actor、一个地面Actor、一个相机、一个控制脚本。

这个拆解过程本身就是游戏策划的最小颗粒:明确对象、明确交互、明确反馈。superpowers的项目结构看似松散,但你只要脑子里先有这个拆解,实现起来流程是非常线性的。

5.2 创建场景骨架

第一步,创建一个空项目"JumpDemo",进入后先等待编辑器左侧资源视图加载完毕。然后依次创建:

  • 一个空Actor,改名为"Player"
  • 一个立方体模型Actor,改名为"Ground"
  • 一个立方体模型Actor,作为"Player"的子级,改名为"Body"

操作路径:在场景树面板右键,选择"创建Actor",然后在属性面板的"Add mixin"里选"Model"。

地面呢,把它的Scale调到(5, 0.2, 5),这样它就变成了一块扁平的板子。玩家方块调到(0.5, 0.5, 0.5),然后给它一个初始坐标,让它悬浮在地面上方。

5.3 添加刚体能力

superpowers的物理逻辑基于一整套物理引擎,作为初次试验我们只需要关注两个处理器:Cannon.js的刚体组件和碰撞器。

选中Player,在属性面板添加"Rigidbody"能力,再添加一个"Box collider"能力。刚体的质量调成1,碰撞器的尺寸会自动匹配模型大小。

地面的处理方式则是静态碰撞:添加"Rigidbody"但把质量调成0,或者换成"Static collider"类型的合理配置,让它不参与物理计算,只提供碰撞表面。

这一步的关键点是:如果不加刚体,你的角色就是一个穿过一切的幽灵;如果把地面当成动态刚体,那么角色一跳,地面可能就被"顶"飞了。所以静态和动态物理体的区分必须在一开始就想明白。

5.4 写一个移动跳跃脚本

现在到了最有意思的一步:在superpowers里给Player添加"Script"能力,然后编辑脚本。

superpowers的脚本用TypeScript编写,运行在浏览器里,基于实体组件系统。你可以直接在编辑器里打开脚本编辑页,保存后立即生效,不需要重新编译整个项目。

我这里给出一个最精简的控制脚本,以superpowers脚本API为蓝本:

const { Actor } = require("superpowers"); let actor: Actor = this.actor; let speed: number = 8; let jumpForce: number = 5; let grounded: boolean = true; let body: Actor | null = null; this.actor.getChildren().forEach(child => { if (child.getName() === "Body") { body = child; } }); this.actor.on("physicsStep", (event: any) => { const rigidbody = actor.getRigidbody(); if (!rigidbody) return; let moveX = 0; let moveZ = 0; if (this.input.isKeyDown("ArrowLeft") || this.input.isKeyDown("KeyA")) moveX -= 1; if (this.input.isKeyDown("ArrowRight") || this.input.isKeyDown("KeyD")) moveX += 1; if (this.input.isKeyDown("ArrowUp") || this.input.isKeyDown("KeyW")) moveZ -= 1; if (this.input.isKeyDown("ArrowDown") || this.input.isKeyDown("KeyS")) moveZ += 1; const velocity = rigidbody.getLinearVelocity(); velocity.x = moveX * speed; velocity.z = moveZ * speed; if (this.input.isKeyDown("Space") && grounded) { velocity.y = jumpForce; grounded = false; } rigidbody.setLinearVelocity(velocity); }); this.actor.on("collision", (event: any) => { if (event.otherActor === this.getScene().findActorByName("Ground")) { grounded = true; } });

这个脚本解决了两件事:读取键盘输入、把输入映射到刚体速度;监听碰撞事件来重置跳跃状态。

解释几个常见疑惑:

  • 为什么把速度直接赋值给线性速度而不是施加冲量?因为这种"直接改速度"的方式在原型里手感最稳,不需要调累积力参数。
  • 为什么用on("physicsStep")而不是每帧更新?因为物理步进和渲染帧率并不一致。你如果在renderFrame里改刚体位置,会遇到莫名其妙的抖动。

这个脚本保存后,点击顶部运行按钮(或按F8),浏览器就会进入一个独立的运行页面。此时你应该能用WASD控制方块移动,按空格跳跃,碰到地面后可以再次起跳。整个过程其实就是一套完整的"输入 -> 物理 -> 碰撞反馈"循环。

5.5 相机跟随:让角色不跑出屏幕

这时候你会发现一个问题:角色移动时,相机是固定不动的,没走几步方块就跑出了视线。我们需要让相机跟着玩家走。

这里我建议不要用"直接把相机制作成Player的子Actor"这种粗暴做法,因为那样相机就会跟着玩家旋转,视角会非常眩晕。

我采用的方式是写一个极简的跟随脚本,挂到相机Actor上:

const player = this.getScene().findActorByName("Player"); if (player) { const playerPos = player.getPosition(); const cameraPos = this.actor.getPosition(); this.actor.setPosition(playerPos.x, playerPos.y + 5, playerPos.z - 5); }

当然这个脚本放在每帧更新或physicsStep里。简单来说,每次更新都拿到玩家当前坐标,然后把相机固定放在"玩家上方5个单位、后方5个单位"的位置。这个方法虽然朴素,但作为原型已经非常够用。

更进阶的做法是用平滑插值,比如lerp,让相机移动带一点阻尼感。但那是后期打磨手感的事,原型阶段先保证"不丢目标"。

6. 多人协作实战:两个人同时改一个场景是什么体验

前面说了superpowers把协作做成了默认能力,接下来我讲一次真实协作过程,把我看到的一些细节说出来。

6.1 开启一个共享项目

管理员在启动页后台创建好项目之后,把项目地址和登录口令发给协作者。协作者在浏览器打开http://你的IP:8080,输入账号进入项目列表,找到对应项目点击进入。注意,协作者并不需要安装任何Node环境,也不需要下载superpowers本体,整个编辑器的代码是实时从服务器加载到浏览器里的。

我测试的场景是这样的:我在我自己的电脑上控制角色移动脚本,另一个朋友在他的电脑上往场景里拖模型、调光照。我们同时操作同一个场景文件,我在他的屏幕上能看到我正在拖动的Actor实时移动位置,他新增的模型也会立刻出现在我的场景树里。

6.2 冲突到底怎么处理

多人协作最怕的就是文件冲突。superpowers处理冲突的理念是"实时合并":因为它传输的不是文件级差异,而是每个操作的具体变更,所以两个人同时修改不同Actor基本不会有冲突;如果恰好同时改同一个Actor的同一个参数,后提交的覆盖先提交的,但不会造成整个项目损坏。

这跟Git那种"基于快照的版本控制"不同。Git是定期持久化一个快照,superpowers更像是一张永远在演进的画布——所有人都直接在这张画布上画画。个人经验是:分组协作时,比如你负责贴近地面的物理玩法,队友负责远处的美术场景,大家改的是不同Actor,全程完全不用沟通锁文件,这在项目原型期非常舒服。

6.3 适合多人协作的场景

我目前认为最适合superpowers的场景有两个。

一个是Game Jam类的限时开发。两天时间里,团队不需要花半天时间统一环境,只需要一个人起好服务,所有人打开浏览器就能动工。美术和程序可以同时操作同一个场景,程序调脚本、美术摆场景,互相之间几乎零摩擦。

另一个是教学演示。我在给朋友讲"刚体、碰撞、输入事件"这些概念的时候,直接开着superpowers现场改参数,方块的跳跃力度调大调小,重力系数改来改去,所有效果实时可见,比我画PPT讲十遍都有用。

7. 遇到的坑和排查方法

工具虽轻,坑也不少。我把实际踩过的问题整理成几个类型。

7.1 端口占用导致启动失败

装完执行superpowers后提示端口被占用,这是我第一次启动就碰到的情况。

排查方式很简单:

netstat -ano | findstr :8080

找到占用8080端口的进程PID,要么关掉它,要么给superpowers换个端口。换端口的方式是在启动命令里带上端口参数,或者查看配置文件里的server端口设置。

7.2 浏览器缓存导致脚本不更新

开发时你改了一版脚本,保存后运行,发现浏览器里还是旧行为。这不是你脚本写错了,多半是浏览器缓存了旧的JS文件。

解决办法:在运行页面按Ctrl+Shift+R强制刷新,或者在编辑器里修改脚本后等一两秒再运行,给资源同步留一点时间。如果项目里引用了很多外部模型素材,也建议养成"先确认资源管理器里文件已上传完毕再保存运行"的习惯。

7.3 刚体掉了但碰撞不触发

脚本里监听collision事件,但角色落地后完全不触发。这个问题的常见原因是:你的"Ground"只添加了刚体,但没有添加碰撞体;或者碰撞体的尺寸跟模型不匹配。

检查顺序:先看Ground有没有Collider能力,再看碰撞体的包围盒是否正确。你可以在运行页面的右上角打开物理调试绘制,把碰撞体可视化出来,一眼就能看出碰撞盒是不是比模型大出一截或者小到看不见。

7.4 协作者的登录界面打不开

如果你把IP发给了队友,队友访问时浏览器一直转圈或提示无法连接。先确认你的Windows防火墙是否放行了8080端口的入站连接。这个问题很容易被忽略:本机能打开不代表局域网其他机器能访问。

另外,如果你的电脑启用了多个网络适配器(比如有线+无线+虚拟机网卡),启动日志上显示的地址可能不是你想要的局域网IP,需要手动确认一下本机的真实局域网IP。

7.5 中文路径导致素材加载失败

在Windows上我用过一个放在中文目录下的项目路径,结果模型贴图加载不正常,浏览器控制台报404。排查了很久才发现是路径编码问题。这里提醒一下:项目路径尽量用纯英文,包含中文字符的路径容易在本地静态资源服务里踩坑。

8. 一些个人心得和扩展想法

讲完这些实操内容,最后说一点我对superpowers的定位判断。

我做游戏原型的时候用过Unity、Godot,也试过一些在线协作工具。superpowers给我的感觉是它把"轻量"和"协作"这两个词做到了很纯粹的融合。它不适合作一个商业化大项目的终极引擎,因为它的资源管线和构建发布能力跟主流引擎还有差距;但在"快速试错"这件事上,它比我用过的任何工具都顺手。

如果你想拿它做一个完整的2D或3D小游戏,可以做的事情已经很多:内置支持Sprite和Tilemap,能做平台跳跃游戏;支持模型上传和骨骼动画,能玩一些简单的角色表现;当然它也能构建Web导出包,把游戏发布到支持Web的平台上。

如果你正好有一台闲置的电脑,可以把它当团队开发服务器:项目放在那台机器上,大家用浏览器连着写代码,你会发现"团队一起做游戏"这件事,远没有想象中那么重。

我个人的建议是:放下"必须用大引擎做大作"的思维惯性,试着在superpowers里花一个周末做一个小玩法。很多时候卡住你的不是创意,而是第一行代码跑起来的门槛。superpowers把这个门槛降到了"打开浏览器"这一步,剩下的就看你是否愿意动手了。

最后再分享一个小技巧:superpowers的脚本API在上手初期不用全文档通读,你在脚本编辑器里输入this.actor.的瞬间会自动弹出可用的方法提示,这个自动补全列表就是我一开始最好的API手册。照着提示逐项试,很快就能摸清整个对象的交互面。祝你在superpowers里玩得开心。