独立开发一款「行走占领地图」的像素风App,聊聊8×8格子征服+热力衰减的实现思路
计步App的数字增长为什么没有成就感这个问题困扰了我很久。看着步数从3000涨到8000心里毫无波澜。后来我想明白了——数字是抽象的地图是具象的。“我今天走了8000步和我今天又占了三个街区”后者的心理反馈强烈得多。于是我做了「像素征途」一款iOS App。核心机制把地图按经纬度切成像素格用户真实行走点亮格子逐步占领城市版图。目前App Store评分5分版本1.12还在冷启动阶段。地图怎么切8×8区域格的设计抉择整套游戏化系统的基础是地图分割。我把地图划分成固定大小的Zone每个Zone内部切成8×864个Tile。用户GPS轨迹经过哪个Tile就点亮哪个。enumTerritoryRules{staticletzoneSideCount8staticletzonePerfectTileThresholdzoneSideCount*zoneSideCount// 64staticletzoneConqueredTileThreshold58}staticfuncevaluate(litTiles:Int,conqueredThreshold:Int,perfectThreshold:Int)-ZoneConquestEvaluation{returnZoneConquestEvaluation(isConquered:litTilesconqueredThreshold,isPerfect:litTilesperfectThreshold)} 这里有个设计取舍——征服一个Zone不要求64格全走到58格即可。原因很现实有些格子在河道上、高架中间、封闭小区内部物理上走不到。强制100%只会让人烦躁放弃。但真全点亮了会给Perfect标记给强迫症玩家额外满足感。58这个阈值我试了三版。最早设50太容易没征服感62太难河边住的用户永远完不成58大概是90%覆盖率体感对了。 ## 连击倍率让人想连续出门 光点亮格子不够。连续天数的奖励倍率是留存的关键 连续走3天碎片产出×1.55天以上×2.0。每天碎片产出上限50个防止挂GPS或开车刷分。断了一天有1天的grace period不清零但断两天倍率重置。 这套数值我参考了游戏签到系统的常见设计但加了grace period是因为——说实话刮风下雨那天出不了门倍率直接清零体验太差了。 ## 热力衰减制造领地在消失的紧迫感 这是我觉得最有意思的一个设计。走过的路线和格子不是永远高亮的它们会随时间褪色-路线轨迹4天开始柔和衰减7天明显变淡--Zone强调效果14天后消退--格子残影30天后降到12%透明度 swiftenumMapHeatRules{staticletrouteGlowSoftDecayDay4staticletrouteGlowDecayDay7staticletzoneEmphasisDecayDay14staticlettileResidualDecayDay30staticlettileResidualOpacity0.12}// 渲染时计算当前opacityletdaysSinceVisitCalendar.current.dateComponents([.day],from:lastVisitDate,to:.now).day??0letopacitydaysSinceVisittileResidualDecayDay?tileResidualOpacity:1.0-(1.0-tileResidualOpacity)*Double(daysSinceVisit)/Double(tileResidualDecayDay) 目前衰减曲线是线性的。已探索区域不会真正丢失——格子状态永远保留只是视觉热度降低。效果是打开地图时最近活跃区域色彩鲜明几周没去的地方暗淡下去。制造了一种我的领地在消失的紧迫感驱动用户继续出门。 我对这个线性衰减方案不太满意。现实感觉中褪色应该是前几天不明显、后面加速变暗类似指数衰减。但指数衰减在视觉上中间段的变化太微妙用户感知不到差异。这个我还在琢磨。 ## 踩过的几个坑**CoreLocation功耗问题**。最早用 kCLLocationAccuracyBest有用户反馈一天掉30%电。后来改成混合策略移动状态下用 kCLLocationAccuracyNearestTenMeters10米精度检测到静止2分钟后自动切换到 kCLLocationAccuracyHundredMeters100米精度再长时间静止直接停止更新。功耗降了大概60%格子判定精度影响不大——反正一个格子本身就有几十米宽。**格子渲染性能**。重度用户积累几万个已点亮格子全量渲染MapKitoverlay直接卡。解决方案是视口裁剪——只渲染当前屏幕可见区域外扩20%范围内的格子其余走内存缓存滑动地图时增量加载。**首次打开的默认位置**。GPS定位需要时间这几秒地图显示哪里我按设备locale做了fallback——CN区默认上海陆家嘴121.47,31.23JP区东京站US区旧金山。小细节但第一印象差别挺大总比显示大西洋强。 ## 用户怎么说 有人评价和世界迷雾一样好玩解锁成就有人说像素风很戳我UI经典。目前被提最多的需求是历史照片GPS导入的年份限制——现在只回溯近3年更早的照片位置没法导入。这涉及照片库全量扫描加地理编码的性能问题几万张照片批量请求CLGeocoder会触发rate limit还在想方案。 ## 一个没想好的问题 热力衰减目前是线性插值opacity1.0-(1.0-0.12)*(daysSince/30)。效果凑合但不理想——前几天衰减太快用户昨天走的路今天看着就暗了一截。 我考虑过用 ease-out 曲线前期慢后期快或者分段设计7天内不衰减、7-30天加速衰减。如果你做过类似的时间衰减可视化什么曲线体感最好评论区聊聊。