这个游戏项目最值得关注的点,是把“追踪”这件事从传统游戏里的虚拟坐标,挪到了你手里的真实 GPS 坐标上。Run With Zombies 是一款免费的浏览器游戏,核心玩法是:你的真实位置会同步到游戏地图里,僵尸会沿着 GPS 坐标向你靠近,你只有靠真实世界的移动才能甩开它们。适合谁看?想尝试户外玩法的玩家、对浏览器定位能力感兴趣的前端开发者,以及想用低成本方式验证“LBS+游戏”创意的产品爱好者。最值得研究的地方有两个:一是它证明了浏览器页面也能承载实时位置互动,二是在户外场景下,GPS 精度、地图刷新和游戏节奏之间的取舍,远比想象中复杂。
下面我会先从玩家视角拆解这个游戏的玩法,再从技术实现角度分析浏览器里怎么做 GPS 定位、僵尸追击和地图刷新,最后给出手机端实测时要注意的权限、安全、耗电和排查细节。如果你只是想玩,可以直接跳去第 3 部分;如果你是想做同类游戏,建议从头看。
1. 先搞懂 Run With Zombies 到底在玩什么
1.1 核心玩法:僵尸不是从屏幕里跳出来的,而是跟着你的 GPS 走
传统跑酷游戏里,僵尸从屏幕前方或后方出现,你通过方向键、滑动或跳跃来躲避。Run With Zombies 不一样,它的敌人模型是基于你的真实地理位置建立的。游戏会读取你设备的 GPS 定位,并把你的位置画到浏览器地图上。僵尸会在你周围某个半径内生成,然后持续向你的实时位置移动。
这意味着,你不能靠“原地跳一下”来躲避,必须真的跑起来,拉开与僵尸之间的物理距离。一旦僵尸进入设定的追捕范围,视觉得到反馈,游戏会出现警告或追击状态;如果你被僵尸追上,这一轮就结束了。你可以继续开始下一轮,但新的僵尸会再次基于你当前的位置生成。
这种玩法的即时感很强,因为它把“游戏状态”和“现实位移”做了绑定。你坐在家里通过模拟位置是玩不了的,必须走出去,或者至少让设备获取到真实坐标。
1.2 为什么“免费浏览器游戏”这一点很重要
常见的位置类游戏,比如基于现实地图的收集或占领玩法,大多需要下载 App。Run With Zombies 选择了纯浏览器方案,这意味着它绕过了应用商店的下载流程,你打开网页、授权位置权限、就可以直接开始。
从技术意义上说,这代表 Web 的能力边界已经够到实时 GPS 游戏了。浏览器端常用的 Geolocation API 能够获取经纬度,配合地图瓦片服务和 Canvas/WebGL 渲染,可以在页面上实现“玩家移动、僵尸追击、地图变化”这一整套逻辑。虽然它在后台运行、锁屏持久化、电池优化方面不如原生 App,但作为一款免费户外娱乐项目,门槛低已经是最大的优势。
从玩家角度看,不需要安装包、不需要注册复杂账号、不占手机存储空间,拿来即玩,这非常符合“轻量户外游戏”的定位。
1.3 和传统跑酷、密室逃脱游戏的核心差异
传统跑酷游戏的核心是“反应速度”,它在固定屏幕内考验操作精度。密室逃脱类游戏的核心是“观察与推理”,它靠场景线索推进。Run With Zombies 的核心则是“物理移动和路线选择”。
玩这个游戏时,你要考虑的东西会变成:
- 前面是死胡同,要不要现在就转向?
- 僵尸从东边过来,我往南跑有没有足够的开阔空间?
- 我现在的速度是走还是跑?僵尸的追击速度是多少?
所以它更接近“真实跑步 + 轻度策略”的结合。你不仅要比僵尸快,还要规划路线,不能跑进死角。
2. 浏览器里怎么实现“GPS 僵尸追着你跑”
这一部分写给对实现感兴趣的读者。你不用完全理解所有细节,但知道原理后,遇到定位不准、游戏卡顿、僵尸瞬移这类问题,至少能判断出大概原因。
2.1 浏览器定位能力:Geolocation API 的基本原理
浏览器里获取 GPS 位置,主要靠 Geolocation API。代码上,最基础的一行是:
navigator.geolocation.getCurrentPosition( (position) => { const lat = position.coords.latitude; const lng = position.coords.longitude; console.log("当前位置:", lat, lng); }, (error) => { console.log("定位失败:", error.code, error.message); } );如果要做持续追踪,一般不会只调用一次,而是用watchPosition持续订阅位置变化:
const watchId = navigator.geolocation.watchPosition( (position) => { updatePlayerPosition(position.coords.latitude, position.coords.longitude); }, (error) => { handleLocationError(error); }, { enableHighAccuracy: true, maximumAge: 1000, timeout: 5000 } );这里有几个关键参数:
enableHighAccuracy: true:让浏览器尽量使用 GPS 模块而不是基站或者 WiFi 粗略定位。游戏类应用必须开启。maximumAge:允许使用多久之前的缓存位置。户外游戏场景建议小于 1 秒,否则画面上的你会“瞬移”。timeout:每次定位的等待时间。设太短容易频繁失败,设太长又会感觉卡顿。5000 毫秒是一个相对稳妥的起点。
注意,Geolocation API 访问的是“设备提供的定位能力”,在手机上通常由 GPS、WiFi、基站共同决定最终坐标。单纯说“用 GPS”,其实未必拿到的就是纯卫星定位数据。
2.2 地图显示和实时位置更新
拿到经纬度后,接下来要把坐标画到地图上。常见的做法有两种:
第一种,使用 Leaflet + OpenStreetMap 这类纯前端地图方案。你只需要在地图上放置一个“玩家”标记,然后根据 GPS 回调更新标记位置:
const playerMarker = L.marker([lat, lng]).addTo(map); watchPosition((coords) => { playerMarker.setLatLng([coords.latitude, coords.longitude]); map.setView([coords.latitude, coords.longitude]); });第二种,使用 WebGL 渲染一张自绘的俯视图或等距视角画面,然后把 GPS 坐标映射到游戏坐标系里。这种方式视觉表现力更强,但地图数据、道路、建筑信息都需要额外处理,工作量比直接使用地图库大很多。
Run With Zombies 这类轻量浏览器游戏,大概率采用了地图库加 Marker 标记的方案,因为它的核心互动是“玩家位置 vs 僵尸位置”的距离关系,而不是复杂的建筑内部渲染。
2.3 游戏逻辑:僵尸的追击模型如何设计
僵尸追击的核心,其实是两点之间距离的动态计算。每次玩家位置更新时,游戏要计算所有僵尸与自己之间的距离,并让僵尸朝玩家的方向移动。
伪逻辑大概是这样:
# 用经纬度计算两点距离(简化示意) def distance_to_player(zombie, player): return haversine(zombie.lat, zombie.lng, player.lat, player.lng) # 每个游戏循环 tick 中 for zombie in zombies: dist = distance_to_player(zombie, player) if dist < catch_radius: game_over() elif dist < chase_radius: move_towards(zombie, player, zombie_speed)设计追击模型时,需要平衡几个问题:
- 僵尸速度比玩家走路慢,还是比玩家慢跑快?
- 玩家停下时,僵尸会一直逼近吗?
- 僵尸之间会重叠吗?要不要做碰撞偏移?
这些参数直接决定游戏难度。如果僵尸速度太快,玩家会失去“还能跑掉”的希望;如果太慢,又没有紧张感。比较好的起点是让僵尸速度略慢于玩家正常步行速度,但追击范围足够大,逼着玩家必须持续移动。
3. 手机上怎么开始玩:环境、权限和操作流程
3.1 先确认设备和浏览器支持
Run With Zombies 依赖 GPS 和浏览器定位能力,所以设备选择有讲究。
比较稳的配置是:
- 一台支持 GPS 的安卓机或 iPhone。
- 系统浏览器使用 Chrome、Edge、Safari 或 Firefox 的较新版本。
- 手机开启“定位服务”或“位置信息”总开关。
- 游戏页面需要网络连接,因为地图瓦片、游戏资源都要加载。户外移动网络需要注意信号。
如果你的设备是只有 WiFi 的平板,或者定位模块很弱的入门机,可能会出现完全不刷新、定位漂移、僵尸乱跳的现象。这不是游戏 Bug,更多是设备定位能力不够。
3.2 权限设置和隐私保护
打开游戏页面后,浏览器会弹出位置权限请求。你需要点击“允许”,并且最好选择“访问时允许”或“使用应用时允许”,而不是“仅本次”。
需要注意,权限弹窗出现的位置不够醒目,很容易被误点“拒绝”。如果不小心拒绝了,需要在浏览器设置或系统设置里重新开启位置权限。以常见安卓浏览器为例,路径一般是:浏览器设置 -> 网站设置 -> 定位权限 -> 找到 Run With Zombies -> 改成允许。
隐私方面,这个游戏只需要拿到你的经纬度,并不需要你的真实姓名、手机号或社交账号。但你必须接受一个事实:GPS 信息本质上属于敏感个人位置数据。如果你对隐私敏感,可以选一个空旷的区域玩,或者使用手机的“大致位置”授权。不过“大致位置”精度可能不够,游戏会出现定位不准的问题。这里建议按个人安全需求来决定是否开启精确定位。
3.3 单次体验流程:从打开页面到被僵尸追赶
我第一次测试时,按下面这个流程走,整体比较顺:
- 打开浏览器,访问游戏页面。
- 等页面加载完成,允许位置权限。
- 看手机上显示的地图,确认代表你的圆点是不是在正确位置。
- 点击开始游戏,等待僵尸在自己周围生成。
- 观察屏幕上的僵尸图标和距离提示。
- 移动一段距离,确认自己的位置会跟着变化。
- 站着不动几秒钟,观察僵尸是不是开始靠近。
- 跑动一段距离,确认僵尸追击方向和速度是否合理。
这里有一个很重要的建议:第一次玩,不要直接跑。先站着不动,让游戏完成初始定位和僵尸生成,确认你的位置和地图显示一致,再开始移动。如果一开始就边跑边看,遇到定位不准时你很难判断到底是手机问题、权限问题,还是游戏逻辑问题。
4. 实际体验中的定位精度和延迟问题
4.1 影响 GPS 定位精度的因素
户外开阔环境下,GPS 定位精度通常能到 3 到 10 米。但在实际测试中,你会遇到以下几种情况:
- 阴天、雨天、在高楼林立的街道上,卫星信号变弱,坐标点会跳。
- 手机放在口袋里和拿在手上,定位更新频率不一样。
- 开启“省电模式”或“低电量模式”后,系统会限制 GPS 刷新频率,导致你的位置不是实时更新。
- 浏览器在后台运行时会挂起定位回调,所以锁屏后再打开可能出现位置跳跃。
这些现象游戏的开发者无法完全控制,因为浏览器定位能力受到操作系统和设备硬件的限制。
4.2 不同环境下适合玩的场地
从安全角度和游戏体验角度,我建议优先选这类场地:
- 学校操场或田径场。
- 公园里较开阔的步道或草地。
- 小区内部道路、非车辆通行的广场。
- 城市里的滨河步道、绿道。
尽量避免以下场景:
- 车流量大的公路旁。
- 自己不熟悉的野外区域。
- 门口、台阶、坡道、施工工地附近。
- 人流特别密集的商业街,跑起来容易撞到人。
这是很关键的边界:这个游戏有趣的前提是“安全地跑”,而不是“跑进危险区域”。
4.3 定位误差和游戏公平性如何取舍
GPS 精度只有几米到十几米,但僵尸的抓捕判定如果也按几米算,玩家会觉得自己“明明不在那里却被追上了”。所以设计游戏时一般会采用一个比坐标精度略大的判定范围。
从玩家视角,你也要接受一个现实:地图上你的圆点不一定完全等于你的物理位置,可能存在几米的偏移。遇到“僵尸追上了但我觉得它没碰到我”的情况,可以先看看地图上你的图标是否已经漂移。很多时候是定位漂移,而不是游戏判定错误。
这里给玩家和开发者各留一个建议:
- 玩家:不要在“差一点就甩掉”时着急回头,走位尽量离僵尸的判定边缘远一点。
- 开发者:在设计抓捕距离时,至少设置成 GPS 精度的 1.5 到 2 倍,否则玩家会产生严重挫败感。
5. 如果自己要开发类似的 GPS 浏览器游戏
5.1 最小技术栈选型
如果你被 Run With Zombies 的创意启发,也想做一个“真实位置 + 追逐玩法”的浏览器游戏,不需要一开始就上重型框架。最小技术栈可以这样配:
- 前端页面:HTML + CSS + JavaScript 或 TypeScript。
- 地图渲染:Leaflet 搭配 OpenStreetMap 免费瓦片。
- 定位能力:浏览器 Geolocation API。
- 游戏循环:requestAnimationFrame 或 setInterval。
- 状态管理:一个简单的游戏状态对象,记录玩家坐标、僵尸列表、开始结束状态。
- 后端(如果要求多人):Node.js + WebSocket。
如果你只想做单机版,也就是僵尸由游戏逻辑生成、只追你自己,连后端都可以省掉。
5.2 核心代码思路:位置更新与僵尸生成
单机版核心逻辑可以拆成三个模块:
位置更新:
navigator.geolocation.watchPosition( (pos) => { player.lat = pos.coords.latitude; player.lng = pos.coords.longitude; playerMarker.setLatLng([player.lat, player.lng]); }, (err) => console.error(err), { enableHighAccuracy: true, maximumAge: 1000, timeout: 5000 } );僵尸生成:
function spawnZombie(centerLat, centerLng, radiusMeters) { // 在地图中心附近生成一个随机偏移点 const latOffset = (Math.random() - 0.5) * radiusMeters / 111320; const lngOffset = (Math.random() - 0.5) * radiusMeters / (111320 * Math.cos(centerLat * Math.PI / 180)); return { lat: centerLat + latOffset, lng: centerLng + lngOffset, speed: 1.2, // 僵尸移动速度 marker: L.marker([centerLat + latOffset, centerLng + lngOffset]).addTo(map) }; }每帧更新僵尸位置:
function gameLoop() { zombies.forEach((zombie) => { const bearing = calculateBearing(zombie.lat, zombie.lng, player.lat, player.lng); zombie.lat += updateLatitude(zombie.lat, bearing, zombie.speed, dt); zombie.lng += updateLongitude(zombie.lat, bearing, zombie.speed, dt); zombie.marker.setLatLng([zombie.lat, zombie.lng]); if (distanceBetween(zombie, player) < catchRadius) { endGame(); } }); requestAnimationFrame(gameLoop); }这里最容易出错的是坐标系运算。经纬度和米不是一个单位,不能直接把僵尸的移动速度当“像素”去加。你必须先把距离换算成经纬度变化量,或者用现成的地理计算库处理。否则在高纬度地区,整个追击逻辑都会变形。
5.3 多人同步和实时数据流
如果要升级成多人版,玩家之间能看到彼此的实体,就需要后端配合。大致流程如下:
- 每个玩家通过 watchPosition 把经纬度发送到服务端。
- 服务端维护一个房间内的玩家位置列表。
- 服务端通过 WebSocket 广播位置给其他客户端。
- 其他客户端收到消息后,更新对应玩家的地图标记。
这种模式下,网络延迟、位置上报频率、视野范围裁剪都是需要处理的点。建议先用 1 秒上报一次的频率起步,不要追求 100ms 实时同步,因为浏览器 GPS 本身就不是高频率定位设备。
5.4 测试环境怎么模拟 GPS 位置
开发调试时,不可能每次都跑到户外。浏览器开发者工具里有传感器面板,可以手动模拟经纬度。以常见浏览器为例,打开开发者工具,找到 Sensors 或“传感器”面板,就可以输入经纬度坐标来模拟位置变化。
不过这种模拟也有问题:你手动输入的位置是离散的,不是连续位移,跑不出“玩家在移动、僵尸在追击”的动态效果。更接近真实体验的做法是,写一个简单的模拟脚本,每隔几百毫秒给 watchPosition 的回调喂一组连续变化的坐标,模拟玩家以某个速度沿直线或折线运动。配合自动移动的僵尸,就能在办公位上完成大部分逻辑测试。
6. 户外安全、耗电和常见问题排查
6.1 户外玩之前必须确认的安全事项
这是整个游戏里最重要的一部分,比任何技术细节都值得记住:
- 不要边跑边盯着地图。跑动时眼睛要看路面,只在停下来或慢走时看屏幕。
- 不要戴降噪耳机。你至少需要能听到周围的车辆、自行车和人声。
- 不要深夜在陌生区域玩。
- 不要为了躲僵尸跑到机动车道上。
- 不要因为看到“僵尸接近”就突然加速,尤其是在有台阶或湿滑路面的地方。
这个游戏本质上是一种户外跑步的变形玩法,前提是安全第一。
6.2 耗电量、流量和发热问题
GPS 持续定位、屏幕常亮、地图瓦片加载,这三件事同时进行,耗电速度非常快。实测玩 20 到 30 分钟,手机电量下降会很明显,机身也会发热。
建议:
- 玩之前把电量充满,或者至少到 80% 以上。
- 关闭不必要的后台应用。
- 不要把屏幕亮度调到最高,室外能看清就行。
- 如果只是测试,跑 5 分钟就够了,不需要长时间挂机。
流量方面,地图瓦片是流量的主要消耗。第一次进入游戏加载地图,可能消耗几 MB 流量。后续每次位置刷新,地图不一定会重新加载,但如果你不断移动,地图会持续加载新区域。建议在套餐流量充足的情况下玩。
6.3 常见问题和排查顺序
碰到游戏不工作,不要急着怀疑游戏有问题,先按下面这个顺序排查:
| 现象 | 先检查什么 | 再检查什么 |
|---|---|---|
| 地图一直显示“定位中” | 浏览器位置权限是否允许 | 系统定位服务是否开启 |
| 玩家标记不移动 | 是否处于室内或信号遮挡区 | 是否开启了省电模式 |
| 僵尸不追击 | 是否站着没动 | 游戏是否处于开始状态 |
| 位置乱跳 | 是否走到高楼或桥梁附近 | 是否手持方式导致天线被遮挡 |
| 游戏卡顿 | 地图瓦片是否加载完成 | 手机发热是否降频 |
| 浏览器直接白屏 | 是否有广告拦截或安全插件 | 是否浏览器版本过旧 |
排查时最忌讳一上来就改游戏参数。先确定输入,也就是 GPS 坐标是否正常;再确定表现层,也就是地图标记是否刷新;最后才轮到游戏逻辑和参数调整。
还有一个容易被忽略的问题:如果电脑浏览器和手机浏览器同时登录同一个游戏页面,手机像素、屏幕尺寸、浏览器对定位权限的交互方式不同,体验会差别很大。这个游戏场景几乎完全面向手机用户,建议直接用手机做终端测试,不要在开发者工具模拟模式下判断整体体验好坏。
7. 从玩家和开发者两个视角看这类游戏的边界
7.1 玩家视角:适合什么样的人玩
Run With Zombies 不是那种可以躺在床上玩一整天的游戏。它最合适的场景是:
- 你想出去跑步,但觉得单纯跑步无聊。
- 你想带孩子或朋友在公园里做点有运动量的互动。
- 你想在短时间里体验一下“被追逐”的紧张感。
- 你正在研究手机浏览器的定位能力,想找一个轻量化的体验入口。
如果你期待的是精致的画面、复杂的成长系统、多人竞技排位,那么这个游戏大概率满足不了。它提供的核心价值是极简的追逐体验和户外运动动机。
7.2 开发者视角:这个创意值得复制的点
从开发角度看,这个项目的价值不是“画面好”,而是它做出了一个极简且完整的闭环:
- 输入:GPS 坐标。
- 表现:地图上的玩家标记。
- 对抗:僵尸追踪模型。
- 反馈:距离接近、被抓判定、重新开始。
这个闭环可以在学校里做课程设计,也可以作为 Web GIS 教学的趣味案例,还可以延伸成城市定向越野的玩法原型。如果你想在这个方向继续扩展,可以考虑几个方向:
- 增加虚拟道具,比如“烟雾弹”可以暂时屏蔽僵尸视野。
- 增加多人合作模式,比如两个玩家需要同时到达某一点才能开启安全区。
- 增加路线记录和跑步数据统计。
- 加入历史最高成绩和本地排行榜。
但要记住,每增加一个功能,都会让定位、同步和交互的难度上升一个台阶。建议从单机、少僵尸、单目标这个最简单版本开始验证。
7.3 这个项目最容易被低估和容易高估的地方
容易被低估的是真实跑动带来的沉浸感。虽然画面简单,但当你知道僵尸是根据自己真实位置移动时,紧张的体感会明显高于普通手机游戏。
容易高估的是 GPS 定位的稳定程度。很多人以为手机定位就是“很准、很快、一直在线”,实际体验会发现它受环境影响非常大,而且在浏览器里,不同手机、不同系统、不同浏览器对位置权限和后台回调的管理方式差异很大。想做一个稳定流畅的 GPS 网页游戏,难点不在“调用 API”,而是在环境差异下保持体验一致。
我个人的判断是:Run With Zombies 作为一款免费浏览器游戏,已经把一个很小的创意做成了一个可以跑起来的成品。它的价值不只是让你玩一次,而是让你意识到,浏览器里的“真实世界游戏”已经不再是纸面概念。如果你感兴趣,不妨找个开阔安全的场地,先跑一轮,再决定是自己把僵尸甩开,还是打开开发者工具研究怎么写出一个属于自己的追击模型。