一个进程,四个游戏,一套账号。入口:game.zxtweb.fun。

为什么挤在一个端口里

四个模块共用同一个服务端(Express + Colyseus 的房间服务):/ 是大厅,/chem、/maze、/arena3d 各挂一个模块。

好处很实在:登录一次,全站通用。账号、JWT、房间列表都在同一层,不需要为每个游戏单独做一套注册登录,也不需要跨域传 token。代价是所有模块共享同一个进程的寿命——某个模块把进程搞崩,四个一起下线。

四个模块

化学对决 game.zxtweb.fun/chem
化学式配平抢答。出题、抢答、计分,带连击和团队赛制。判定逻辑全在服务端,客户端只负责显示题目和收结果。

迷宫战场 game.zxtweb.fun/maze
俯视角射击。特点是子弹会在迷宫里反弹,所以弹道是可预测但难算的;两种弹种、可引爆的炸药桶,最多 5v5。

3D 竞技场 game.zxtweb.fun/arena3d
第一人称多人射击。服务端 30Hz 做权威判定,客户端只做预测和插值,手机浏览器也能操作。

像素小镇 town.zxtweb.fun
另一个端口,规则不一样:没有输赢,一个与现实时间同步的小镇,居民按时间表各自走动。可以拖动视角、点居民看他在做什么。它更像是「有个地方可以去看看」,而不是一局游戏。

后台 game.zxtweb.fun/admin

上传和删除游戏模块、重启房间服务、看账号。模块是可热插拔的:新模块丢进去不用重启进程,但已经加载过的模块改房间代码需要重启才能生效。

踩过的坑(写给自己看)

  • **删模块后访问 ENOENT**:路由在挂载时就把文件路径固定下来了,模块删掉路径还在。改成每次请求时解析。
  • 删模块导致 Colyseus 崩溃:房间类型正在被使用时注销,会直接炸。解决办法是不注销房间类型,改成加一层守卫类 + 主动断开房间。
  • 客户端「文件不完整」:路径解析到了模块目录本身,而不是模块下的 public/。