跑酷游戏最没意思的地方在哪?你跑得再远,排行榜上那个数字也没人验证得了。Initializr 新上线的第二个游戏模板 Dash 想解决的就是这件事——它把真实街道变成关卡,还让服务器把每一局重新跑一遍。

打开网易新闻 查看精彩图片

先说 Dash 是什么。它是一个无尽跑酷模板:角色在分车道的赛道上冲刺,跨栏、滑铲、在车流间变道。今天就能从 Initializr 生成,挂你自己的名字和包名,源码采用 MIT-0 协议。

它背后的框架是 Codename One,一个开源框架,用同一套 Java 或 Kotlin 代码库构建原生 iOS、Android、桌面和网页应用。

一个关卡,两种视角

Dash 里最讨巧的设计,是关卡可以在中途从横版卷轴变成 3D 跑酷。Neon Causeway 的第一段看起来就是个平面平台游戏:一排跨栏和障碍,从侧面看过去。

跑到 300 米处,镜头转到角色身后,车道展开,剩下的就是追尾视角的跑酷。

这背后并没有两个游戏。模拟层始终只有车道、高度和距离,跨栏从哪个角度看都是同一种跨法。关卡只携带镜头提示,角色到达提示点时渲染器在两种取景之间做混合。规则层从不看镜头,所以关卡可以在任何位置切换视角,而不影响谁赢。

跑你自己的那条街

这是最值得演示的部分。点“Run your city”,在真实街道地图上选起点和终点,这条路线就变成一个关卡。每条街是一段赛道,每个转弯按它实际拐的方向变成弯道,下一条街的名字会在你到达前被念出来。沿途的地标,比如车站或博物馆,会以广告牌的形式出现在赛道旁。

地图用的是 Codename One 的 MapView,它在每个平台上自行绘制 OpenStreetMap 数据,路线则来自 Routing。应用把路线化简成街道和转弯,交给规则层:

  • CityRoute route = new CityRoute("Old Harbour")
  • .leg(420, CityRoute.STRAIGHT, "Quay Street")
  • .leg(310, CityRoute.LEFT, "Rope Walk")
  • LevelDef level = route.level()

level() 是确定性的,所以服务器不需要地图。它从编码后的路线重建出同一个关卡,再拿你的跑动去核对。关卡的 id 是路线的哈希值,每条路线因此有自己的排行榜,也没人能把一条难路线裁成简单版还留在同一张榜上。

能信的排行榜

一局成绩从来不是以数字形式上报的。应用发送的是种子和输入日志,几百个字节,服务器用应用运行的同一个 Java 规则模块把它重放一遍。手输的分数,或者为了躲开实际撞上的障碍而改过的日志,都复现不出来。规则层不使用浮点数,也不读时钟,所以手机、服务器和回放查看器逐位一致。

每个关卡都有全时段、周、日、好友和战队榜。你打破好友的最好成绩,对方会收到一条推送,点开就是该关卡的排行榜。

和好友同场竞速

开一个房间,分享链接,所有人在同一时刻跑同一条赛道。服务器以锁步方式运行比赛:每台手机发送自己的输入,房间把每一帧的输入广播给每个座位,服务器自己那份比赛副本决定名次。客户端状态若与服务器漂移,会被它每秒发送的哈希抓出来。

跑的时候还能说话。语音走 Codename One 的 WebRTC API,玩家两两之间点对点,信令由游戏自己的 socket 承载,服务器从不接触音频。

自己做关卡

赛道编辑器就在应用里,每个平台都有。关卡是一条你可以涂画的条带:点某条车道放下跨栏或金币,点最上面一行放下横跨所有车道的障碍,在需要换视角的位置放镜头提示。试玩会用真实规则跑一遍草稿。发布前要求机器人能通关,所以没人能发布一个打不过的关卡。已发布的关卡包可以被评分、竞速、改编,并在管理后台接受审核。

如果你一直想发一款游戏,却卡在游戏之外的所有事情上,这部分就是最值得抄的。登录、好友、推送、商店、审核,以及一个会重放每一局的服务器都已经做好了,你花的那一周时间全在好玩的部分上。