尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

iOS 存钱罐 App 开发实录:SpriteKit 物理引擎做硬币掉落动画,30 枚同屏帧率踩坑与解决方案

iOS 存钱罐 App 开发实录:SpriteKit 物理引擎做硬币掉落动画,30 枚同屏帧率踩坑与解决方案 前言做了一个带物理动画的存钱记录 App去年底我想做一个纯本地的存钱记录工具。调研了一圈市面上的产品发现存钱这个动作基本就是输入数字、点确认存完没什么感觉。我想要的效果是每次存钱时屏幕上有硬币哗哗掉进罐子里带物理碰撞和堆叠效果给「存钱」这个动作加一点正反馈。App 叫「聚沙攒钱」iOS 版目前迭代到 1.9。这篇主要聊硬币动画的技术实现、帧率踩坑过程以及储蓄系统的架构设计思路。为什么选 SpriteKit 做硬币掉落动画一开始考虑过用 Core Animation 手写弹跳曲线试了两天放弃了——硬币之间需要碰撞堆叠效果多个刚体互相挤压的物理模拟手写贝塞尔曲线根本搞不定。最后引入了 SpriteKit。说实话在工具类 App 里用游戏引擎有点重但SKPhysicsBody天然支持重力和碰撞检测省了我自己造轮子。核心代码如下funcdropCoin(at position:CGPoint){letcoinSKSpriteNode(imageNamed:coin_gold)coin.sizeCGSize(width:28,height:28)coin.positionCGPoint(x:position.x,y:frame.maxY20)coin.physicsBodySKPhysicsBody(circleOfRadius:14)coin.physicsBody?.restitution0.3coin.physicsBody?.friction0.4coin.physicsBody?.linearDamping0.1addChild(coin)} 几个参数说明-restitution弹性系数调到0.3是反复试出来的——0.5以上硬币落地像橡皮球一样蹦视觉上很假0.1以下又完全没弹性像石头砸地上--friction0.4保证硬币堆叠时不会滑得到处都是--linearDamping0.1给一点空气阻力让下落过程更自然 ##30枚硬币同屏的帧率崩溃问题 存一笔大金额时我会根据金额映射生成多枚硬币上限30枚。第一版实现是一次性全部 addChild结果在 iPhoneSE上帧率直接掉到 40fps 以下肉眼可见的卡顿。**原因分析**30个刚体同一帧开始做碰撞检测物理引擎计算量瞬间拉满。SpriteKit的物理模拟是逐帧计算的当同一帧突然涌入大量需要碰撞检测的节点时单帧计算时间会远超16.6ms。**解决方案**加一个延迟队列每枚硬币间隔0.08秒生成。视觉上反而更像「哗哗倒进去」的感觉比一坨同时出现要自然得多。iPhoneSE上稳定 60fps问题解决。 这是整个项目里最典型的一个教训**物理引擎不怕节点多怕的是同一帧突然涌入大量碰撞计算。**分帧生成是最简单有效的优化策略。 ## 储蓄系统架构双模式设计 储蓄逻辑上我分了两种模式对应 GoalMode 枚举的两个值-**.wish愿望模式**设定目标金额比如攒8000买 iPad按 weekly/biweekly/monthly 的策略生成定期计划App计算需要多少期、每期多少钱到期提醒执行--**.free自由模式**不设目标不设周期纯粹当个零钱罐随手存随手记 swiftstructGoal{letmode:GoalMode// .wish 目标驱动 | .free 自由存入letstrategy:Strategy// .weekly / .biweekly / .monthly仅 wish 模式lettargetAmount:Int64// wish 模式的目标金额free 模式为 0letcurrentAmount:Int64lettotalPeriods:Int// 计划总期数free 模式为 0letnextDueDate:Date?// 下次应存日期free 模式为 nil} .free 模式是后来根据用户反馈补的——有人说「我就想随手记一笔不想被目标和倒计时绑着」。并不是所有人都适合目标驱动型的存钱方式这个需求很合理。 ## 成就徽章系统 为了维持打卡动力做了16枚成就徽章。每个徽章的解锁条件绑定一个闭包接收用户统计数据进行判定 每次打开成就页面遍历所有徽章定义把当前用户的统计数据传进去跑一遍条件。不需要额外的状态机或解锁记录表——徽章数量少16个统计数据是预聚合好的遍历一遍几乎无开销。 设计徽章的难点不在代码在于**门槛怎么定**。连续7天大概30%用户能达到365天挑战就是给极少数人的荣誉勋章。门槛太低没成就感太高让人直接放弃。 ## 几个小功能的实现思路**提醒通知**默认每天20:15推一条本地通知提醒存钱。这个时间点是我自己定的——晚饭后睡前大部分人比较放松愿意花10秒操作一下。用户可以自定义时间但实际改的人很少。 有个问题一直困扰我本地通知不像推送服务有送达回执UNUserNotificationCenter 的 delegate 方法只在用户点击通知时触发。如果用户看到了但没点我这边完全是个黑盒不知道实际打开率。**隐私遮罩**App进后台时自动遮住金额内容防止多任务切换被人瞥到。需求来源就是我自己——有次在公司切任务时同事正好看到我的存钱目标虽然不是什么秘密但确实有点尴尬。监听 scenePhase 变化即可实现简单但体验上确实需要。 ## 目前状况和一些思考 说实话数据很一般近一周下载量基本是零。没做过付费推广ASO也处于裸奔状态。 技术上我对SpriteKit动画的效果挺满意徽章系统的扩展性也够用。但「做得出来」和「有人用」完全是两码事。做独立开发的应该都深有体会——技术实现往往只占整件事的30%剩下的都是运营和增长的问题。 如果你也在做工具类App开发或者对SpriteKit在非游戏场景的应用感兴趣欢迎评论区交流。特别是关于每日提醒通知的点击率问题——如果你有实际数据很想听听经验。
返回列表