ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Superpowers实战:用浏览器和TypeScript快速开发HTML5游戏

Superpowers实战:用浏览器和TypeScript快速开发HTML5游戏 1. 先搞清楚Superpowers 是什么解决了什么问题第一次听到 Superpowers 这个名字我还以为是哪个励志课程的营销词。直到我在一个线下开源活动上看到有人用它实时改游戏浏览器里的 3D 场景随着代码保存自动刷新旁边两个开发者守着同一个 Web 页面各自拖拽着场景里的模型我才意识到这是一个可以被“安装”的工具而且它解决的是我在做 HTML5 游戏时最头疼的一堆老毛病。如果你和我一样也搜过“想要安装 Superpowers”大概率是被这个不装不行又不太出名的名字带了进来。简单说Superpowers 是一个基于浏览器的开源 HTML5 游戏开发平台。它把代码编辑器、资源管理器、场景编辑器、可视化脚本组件和实时多人协作全部塞进了一个 Web 环境里。你不用像用 Unity 或者 Godot 一样安装一个巨大客户端也不用因为团队里有人改了一个资源导致本地同步半天。一切都在浏览器里完成代码一保存场景立刻刷新队友的状态几乎同步可见。它的核心逻辑听起来很反直觉既然要做游戏为什么要用浏览器但你细想就明白了HTML5 游戏的最终产物本身就跑在浏览器里开发环境也放在浏览器里天然省掉了“桌面引擎到 Web 产物”之间那层格式转换和配置摩擦。尤其在做小体量 2D 游戏、Node RPG、桌面小物件交互这类项目时Superpowers 相当顺手。适合三类人一是独立开发者想快速验证玩法原型二是编程老师想在教室里带学生集体做小游戏不用挨个装环境三是 Game Jam 里想要实时协作、避免版本冲突的临时小组。对零基础的同学它也足够友好。我见过第一次接触的同学打开界面后十分钟就搞明白左边是资源列表中间是场景编辑视口右边是属性面板下面还能拉出一个代码编辑器。几乎没有传统游戏引擎那种“不知道去哪点”的学习曲线。这个工具最打动我的地方是它把“做游戏”变成了类似写文档和共享表格一样的协同体验这在传统的 git 引擎工作流里是做不到的。当然它也有自己的脾气。后文我会把从安装到实际做第一个小项目包括踩过的坑一条龙晒出来。2. 安装前的设计思路拆解为什么你要理解它的架构2.1 “浏览器即 IDE”是如何运作的Superpowers 本身并不是一个完全运行在浏览器里的纯前端项目。它的架构是一个本地服务端基于 Node.js负责文件读写、资源编译、项目管理和数据同步浏览器只是客户端渲染界面。你打开浏览器输入地址看到的是一个通过 WebSocket 与本地服务端保持长连接的 Web IDE。你做的每个操作比如拖一个精灵图进场景、改一行代码都会实时发送到服务端服务端再把变更广播给所有连接了同一个项目的客户端。这也是为什么它敢说“实时协作”。它相当于每个参与者在同一台共享电脑上进行软件开发只是这台电脑变成了服务端进程。所有客户端看到的其实都是同一份项目状态不存在传统 git 分支合并那一套流程。理解了这一点你使用时就不会犯常识性错误所有成员最好都在同一个局域网内或者都能访问到同一台机器的服务端。如果你想跨互联网协作还需要考虑内网穿透或者部署到公网服务器这个后头细说。2.2 用 TypeScript 而不是自创脚本语言传统游戏引擎喜欢搞一套自家的脚本语言比如 Unity 的 C#、Godot 的 GDScript都有一定的学习门槛。Superpowers 选择了 TypeScript 作为主要脚本语言这一点我觉得非常聪明。TypeScript 本身就是 JavaScript 的超集有类型检查写起来不容易犯错而且可以直接跑在任何现代浏览器里。更关键的是它背后带了一个可选的“可视化编写脚本”能力你可以通过拖拽组件来拼逻辑但本质上生成的都是 TypeScript 代码。对新手来说这样过渡很平滑你先用拖拽的方式理解“组件”和“消息”再慢慢打开代码面板读生成的代码逐渐就能自己写了。对老手来说TypeScript 让你可以写类、接口、枚举甚至使用 npm 生态里的某些库。整个项目编译后的输出就是一个标准的 HTML5 游戏包部署方式非常简单扔到任何静态 Web 服务器都能跑。2.3 为什么不用传统桌面引擎而用 Superpowers这里没有“谁更好”的绝对答案但有明确的使用场景差异。桌面引擎的优势在于大型项目、重度美术管线、复杂物理和光照计算缺点是每次打开一个项目都要加载好几 GB 的素材而且多人协作全靠插件或者自己搭服务器。Superpowers 的定位恰好是轻量原型、快速迭代和教学演示。它不擅长做大型 3A 项目但它让你在十几分钟之内就做完一个能玩的 2D 小游戏这对创意验证和头脑风暴价值极高。我常打的比方是Unity 像是一个正规装修队水电木工各方面都能干Superpowers 更像是一把瑞士军刀急救开罐头削木头都能干但你不能指望用它盖别墅。你要是非拿它做大型多人 3D 网游那是在难为它。真想清楚了这一点你才知道“想要安装 Superpowers”的动机到底是跟风尝鲜还是真的需要一个小而美的协同开发武器。3. 新手必看Superpowers 的安装与首次启动3.1 准备运行环境因为 Superpowers 的服务端是 Node.js 应用所以第一步是安装 Node.js。建议安装 LTS 版本不要装最新的 odd/even testing 版本。你可以打开终端执行node -v和npm -v如果能输出版本号说明环境没问题。如果没有去 Node.js 官网下载对应你系统的安装包一路下一步即可。Windows 用户还需要注意一点不要装在带空格的默认路径下后续可能出现奇怪的权限问题。Mac 用户建议用 Homebrew 安装命令是brew install node这样可以避免某些 npm 全局安装时的写入权限问题。Linux 用户最省事直接用系统自带的软件包管理装 nodejs 和 npm但版本可能偏旧如果启动后报错可以再升级到 Node.js 16 以上。装好之后最好把 npm 的全局安装目录权限处理一下。很多新手装全局包时会遇到EACCES: permission denied这是因为 npm 默认写到系统目录普通用户没有写权限。我建议不要用sudo npm install -g来绕过因为 sudo 装出来的文件归属 root后面用起来会非常别扭。更好的办法是给 npm 设置一个当前用户的全局目录具体做法在官方文档里有我就不重复粘贴了但这一步值得先做完。3.2 使用 npm 安装 Superpowers 命令行工具环境准备好之后在终端执行npm install -g superpowers这里补充说明一下不同时期这个包名可能有所变化如果未来某天官方改成superpowers/cli之类的新名字你在安装时会遇到 404 错误。最好的习惯是先去 npm 官网搜一下superpowers确认包名和最新版本再执行安装。我这个教学时代用的命令是上面这条实测下来稳得很。安装完成后验证一下superpowers --version能输出版本号就说明命令行工具已经就位。如果提示找不到命令最常见的原因是 npm 全局目录没有加入系统 PATH。Windows 下重开一个终端通常就解决了Mac/Linux 下要检查一下~/.bashrc或者~/.zshrc里的 PATH 设置。3.3 启动 Superpowers 服务在终端里面直接运行superpowers第一次启动时它会在当前用户目录里初始化一个数据目录用来存储项目配置。如果你喜欢干净整洁可以先建立一个工作目录比如mkdir ~/superpowers-projects然后cd进去再启动。这样项目文件就集中放在一个地方后续备份非常方便。启动成功后终端会打印一段提示通常包括一个本地访问地址形如http://localhost:4237不同版本端口可能不一样以你实际看到的为准。这时别关终端新开一个浏览器访问这个地址就能看到 Superpowers 的欢迎页面。首次进入一般会要求你创建一个本地管理账号主要目的是防止其他人通过局域网连上你的服务之后随便改项目。用户名和密码记简单点就行这只是一个本地管控令牌不涉及复杂安全策略。创建完之后你会看到项目列表界面这时候“安装 superpowers”这一步才算真正完成。3.4 安装过程中最常见的三个坑第一个坑是安装超时或者红字报错。国内网络环境访问 npm 官方仓库有时候很慢稳妥的做法是配置镜像源。你可以执行npm config set registry https://registry.npmmirror.com然后重新安装速度会快很多。注意不要全局把 npm 源改成不可信的第三方源安全风险不可控。第二个坑是启动后浏览器白屏。多半是 Node.js 版本与 Superpowers 要求的 WebSocket 库不兼容或者端口被防火墙挡住。Node.js 版本太旧的话建议升级到 LTS端口被占用的话可以先用命令查一下是哪个进程占了端口一般杀掉那个进程或者配置 Superpowers 换端口就能解决。第三个坑是 Windows 系统下路径带空格导致资源文件无法写入。如果你的系统用户名恰好叫 “my name” 这种带空格的账户而 Superpowers 默认把数据目录放在用户目录下就很容易触发 Node.js 某些旧模块的解析 bug。解决办法是把数据目录手动改到纯英文无空格路径具体在启动时可以通过参数指定比如superpowers --user-data-dirD:/spdata版本不同参数名可能略有不同看帮助信息即可。4. 实际操作从零创建一个可运行的小游戏项目4.1 创建项目并理解目录结构进入 Superpowers 的界面后点击创建新项目。通常会让你选择模板空白项目Blank、2D 游戏2D Game、3D 游戏3D Game、平台游戏Platformer等。新手我建议直接选 Blank自己动手搭一遍这样你对结构理解得最透。创建完成后你会看到左侧资源树。以我的经验一个典型项目至少有这几个部分assets存放你导入的图片、音频、字体等scenes保存场景文件scripts保存所有 TypeScript 脚本components则用来挂载自定义组件。如果你是从 Unity 转过来可以把它类比成 Assets 文件夹和 Scripts 文件夹只是这里没有.meta文件到处乱飞清爽很多。这个平台的“场景”概念也很有意思它不是一个二进制文件而是一串可读的 JSON 描述。所以你在一个空场景里摆了几个物体保存后本质上是在更新一个 JSON 结构。这让人很安心因为就算场景崩了用文本编辑器打开也能看到出问题的对象是哪一个。4.2 导入素材并搭建场景我要做一个非常简单的“小球吃金币”演示一个蓝色方块一个金色小球用方向键移动蓝色方块去碰金币碰到的瞬间金币消失。素材不需要自己画你可以先用系统自带的绘图工具生成两张 PNG一张 64×64 的蓝色方块一张 64×64 的金色圆形。或者直接在 Superpowers 自带资源生成器里创建基础图形有些版本支持内置生成实体形状省去外部素材的麻烦。把两张图拖进资源树的assets文件夹系统会自动生成对应的 sprite 资源。这时候你可以在场景里创建一个 “Player” 实体添加一个 SpriteRenderer 组件把蓝色方块图片拖进 texture 槽里一个带图像的物体就出现在场景中了。同样的操作再创建一个名为 “Coin” 的实体使用金色圆形图片。位置先随便放在场景中间后面再用代码控制。这里有个需要注意的细节图片的锚点和对齐方式会影响旋转。我们做的这个 demo 不旋转所以可以忽略但如果以后做角色动画一定要理解 Sprite 的 anchor 参数不然角色转个身就像在绕着一个莫名其妙的点打转。4.3 写第一个脚本让物体响应键盘选中 Player 实体在右侧属性面板里点“添加组件”找到 “Behavior”——这是 Superpowers 里绑定脚本的组件。它默认会生成一个新脚本你点击脚本就能打开内置代码编辑器。接下来我们用 TypeScript 让 Player 可以移动。下面这个脚本是我基于当前版本常见 API 写的如果你的版本略有差异以官方示例为准import Sup from sup; Component() export class PlayerBehavior extends Sup.Behavior { private speed: number 3; update() { let delta Sup.Clock.deltaTime(); let dirX 0; let dirY 0; if (Sup.Input.isKeyDown(LEFT)) dirX -1; if (Sup.Input.isKeyDown(RIGHT)) dirX 1; if (Sup.Input.isKeyDown(UP)) dirY 1; if (Sup.Input.isKeyDown(DOWN)) dirY -1; this.actor.moveX(dirX * speed * delta); this.actor.moveY(dirY * speed * delta); } }这段代码的思路很直白读取每帧的 delta time根据键盘输入方向调整 actor 的位置。每个实体在 Superpowers 里都叫 actor而this.actor指向当前挂载脚本的实体。按下方向键时dirX 和 dirY 产生变化乘以移动速度再乘以 delta time就得到这一帧要移动的距离。之所以乘 delta time是为了让移动速度与帧率无关否则 30 帧环境和 60 帧环境下同一个游戏会跑出完全不同的速度。保存脚本后切到场景预览按上下左右键蓝色方块应该就能动起来了。如果动不了先检查 Input 的按键名称是否对应键盘映射表不同版本对方向键的命名可能不同有的叫Left有的叫ArrowLeft。我个人倾向于用Sup.Input.getAxis这样的更标准化接口但 demo 里写清楚 isKeyDown 更好理解。4.4 实现金币拾取和实时协作体验接下来让金币在被碰到时消失。给 Coin 实体也添加一个 Behavior脚本内容如下Component() export class CoinBehavior extends Sup.Behavior { start() { Sup.Channel.connect(game, this); } onCollide(player: any) { if (player.getComponent(PlayerBehavior)) { this.actor.destroy(); } } }但严格说在 Superpowers 里检测碰撞一般需要用到物理组件或者手动计算距离。为了让 demo 不过度复杂我换一种方法在 PlayerBehavior 的 update 里获取 Coin 实体的位置计算两个 actor 的距离如果小于某个阈值就销毁金币实体。代码大概是这样let coin this.actor.getScene().findActor(Coin); let distance Sup.Math.distance(this.actor.getPosition(), coin.getPosition()); if (distance 0.8) { coin.destroy(); }你需要先给 Coin 实体设置一个名称比如就叫 “Coin”这样 findActor 才能找到。阈值的经验值是看起来两个物体已经贴在一起根据你的 sprite 大小和场景单位调0.8 在 64 像素缩放到 1 单位的情况下差不多。保存后再运行你就能用方向键控制蓝色方块去碰金币了。整个过程里如果你的浏览器开了另一个标签页登录同一个服务后也能看到场景并且你能看到它在实时同步你的移动。这一点对教学特别有用让学生看到“原来代码改了伙伴那边也会变”。4.5 热重载的魔法与陷阱Superpowers 最让我喜欢的功能就是热重载。你改脚本保存的一瞬间运行中的游戏并不会完全重启而是尽量保留现场状态。这对调试动画、角色位置和变量数值是救命级的体验。比如你的人物走到一半发现攻击力数值设置错了改一个数字保存继续跑而不是像传统引擎那样从头加载场景再自动走一圈。但热重载也有陷阱如果脚本里定义了类的静态变量或者使用了全局状态保存重载时这些状态可能不会重置导致游戏出现“改了一行代码数值却像是叠加了两次”的状况。我的经验是尽量把可变状态放在实体组件内部不要在模块顶层声明变量。另外如果你在某次热重载之后发现逻辑跟预期不一致先手动停止预览再重新播放就能排除热重载带来的脏状态干扰了。4.6 发布与导出让游戏真正跑在别人的浏览器里做好了游戏下一步是发布。Superpowers 菜单里一般有“Build/Export”选项导出时会问你选择目标平台比如 Desktop 或 Web。对于 Web 模式它会生成一个包含了完整 HTML、CSS 和 JS 的目录。你只需要把这个目录放到任意静态网站服务器上别人就可以用浏览器访问你的游戏。如果你只在本机导出想先测试一下最简单的办法是安装一个静态服务器工具比如npx serve然后在导出目录里运行npx serve它会在本地开一个端口你就能通过浏览器访问。注意不要直接用 file:// 协议打开 HTML因为很多浏览器会限制本地文件的懒加载和音频请求导致明明导出了却白屏。这属于“代码没写错但打开姿势不对”的典型。5. 常见问题与排查技巧实录5.1 端口被占用或者想换端口怎么办我在一次 Game Jam 里遇到启动报错提示端口 4237 被占用。当时是因为别人启动了一个本地调试服务占了同一个端口。最简单的解决办法是去终端查看端口 PID杀掉进程lsof -i :4237 # Mac/Linux 下查看占用进程 # Windows 下用 netstat -ano | findstr 4237但如果你反而想让 Superpowers 在固定端口上运行方便团队记忆可以在启动时加上环境变量或者参数指定端口具体参数查看帮助文档。我个人的习惯是使用约定配置让所有成员固定访问一个端口避免每次启动地址变化后群里反复发新链接。5.2 多人协作连不上大家在同一个局域网A 启动服务B 访问http://192.168.x.x:4237却打不开。这种情况九成是系统防火墙拦住了入站连接还有一成是 A 的电脑网络配置文件设置了公共网络默认禁止入站。Mac 用户还要在“系统偏好设置”的共享选项里确认是否允许来自本地网络的服务。Windows 用户可以直接在防火墙允许应用列表里手动添加上 Node.js。如果你们不在同一局域网也不要灰心。你可以将 Superpowers 服务部署到一台拥有公网 IP 的云服务器上按同样的方式启动然后通过 HTTP 访问。考虑到安全性至少设置一个强管理员密码并且只开放你真正需要的端口。它本身支持多项目隔离所以做线上工作室也是可行的。5.3 资源导入乱码或者图片显示为默认方块这问题我在教学时遇到过两次。第一种情况是图片本身有透明通道但 Superpowers 把它当成不透明纹理处理了导致图层叠加后看起来怪怪的。这时候检查纹理导入设置把透明模式的参数改为 premultiplied alpha。第二种情况是文件名里包含中文或特殊符号某些版本对文件路径的 UTF-8 支持还不够完善。稳妥的做法是素材文件名一律用英文小写加下划线比如player_blue.png不要用玩家-蓝色.png。这不是排外而是为了跨平台兼容。5.4 JSON 场景文件冲突了既然多人协作是实时的理论上不会出现 git 冲突但偶尔因为网络断线重连客户端本地缓存和服务端最新状态不同步你可能会看到场景里出现两个重复物体或某个物体属性丢失。这种情况的处理方法不是去手动编辑 JSON而是先关闭这个场景不保存再重新打开一次让服务端重新推一份最新的场景状态。如果问题依旧让所有人退出项目把项目文件复制一份备份然后把场景内容用文本方式替换掉问题描述里的可疑字段。不过说实话我用了这么久真正需要手动改 JSON 的次数一个手指头数得过来。5.5 游戏卡顿/性能优化第一课Superpowers 的引擎跑 HTML5 游戏性能肯定不能和原生引擎比。如果场景中同时出现几十个带光照和阴影的 3D 物体帧率会明显下降。我的经验是先把光影效果关掉再减少实时反射和实时阴影改成预先烘焙的贴图。2D 游戏的话尽量使用 Sprite Atlas也就是把所有小图合并成一张大纹理减少绘制调用次数。另外不要每帧都对所有实体做距离检测这个计算量会随实体数量平方增长。一般用空间划分或者粗略的网格检测来控制开销。记住一个原则原型阶段跑得动就行优化放到玩法确认之后再做别一上来就死磕性能。5.6 学习资料哪里找官方文档是首选里面有 API 参考和示例项目。还可以去它的官网或者社区频道看别人做的开包即用项目下载下来在本地 Superpowers 里打开对照代码学习。我建议新手不要看太宏大的作品容易打击信心就看那些“只有几 KB 的迷你游戏”模仿里面的做法进步最快。遇到问题用搜索引擎搜英文关键词 superpowers外网老哥的问答质量很高早年这个中文圈资料确实少但已经有越来越多中文教程冒出来了。6. 我的一些个人体会和调整建议如果你还在犹豫要不要用 Superpowers或者刚装好不知道该拿它做什么我的建议很明确先定一个极小的目标比如“今天内做一个点击小球就变颜色的交互页面”。不要一上来就想着复刻塞尔达你一晚上只会被几百个细节淹没。我最早用它时花了半小时在摆弄背景音乐的资源导入上结果一个玩法都没写出来。后来换了思路所有美术资源先用纯色方块代替音效先用系统提示音代替先把玩法跑通。等核心玩法确定之后再回来慢慢填优质的素材和声音这时的状态完全不同。关于团队协作我也有一点主动踩坑换来的心得。虽然 Superpowers 支持实时协作但不代表你们每个人可以毫无约束地在同一场景里乱摆。最好先从项目结构上分工A 负责场景和美术资源B 负责核心脚本C 负责 UI 层。每个人都专注自己的模块实时协作的体验才真正顺畅。全员同时在一个场景里拖实体哪怕网络再好也容易因为误触碰而产生不必要的回滚操作。你可以把它当作共享文档一个人改文字另一个人改格式没问题但如果两个人都同时改同一段落那还是会乱。最后想分享一个小技巧导出 Web 版本后你可以用手机浏览器访问同一地址。Superpowers 导出的是一个响应式布局的游戏外壳虽然你可以让游戏横屏运行但如果能顺手把虚拟摇杆加进去手机体验会提升一个量级。我自己做小游戏时总习惯把键盘控制逻辑先封装成一个InputManager在桌面测试时读键盘在手机运行时自动切换为虚拟摇杆这样同一个游戏在两种设备上都能玩。装好一个工具不是为了“拥有超能力”而是为了把脑子里的创意快速变成别人能玩的东西。Superpowers 对我来说就是那条通畅的产线。不管你是想带着学生做一个课堂互动小游戏还是和队友在 Hackathon 里 48 小时出作品只要按摩按到它的脾气它完全担得起“超能力”这个名字。
返回列表