Sumi Mahjong 的技术选型围绕一个原则展开:能在本地完成的事情就不要交给服务器。游戏进度、主题解锁状态、设置和统计都属于本地数据,网络不是默认能力。

界面层使用 SwiftUI,数据持久化走系统能力,购买边界收束到 StoreKit 2。这样做的好处是工程结构更清楚:玩法引擎只关心牌、规则和局面,购买模块只关心主题解锁,页面只负责表达状态。

这种架构也降低了隐私政策和审核解释成本。没有账号、没有广告 SDK、没有第三方分析,也就不会为了一个小游戏引入复杂的数据收集说明。

真正需要重点保护的是玩法核心:匹配规则、局面生成、提示和洗牌逻辑要尽量独立,方便测试,也避免 UI 改动影响游戏判定。一个轻量产品越小,越需要把核心模块边界分清楚。

这篇开发日记可以拆成一节实战课:如何在立项阶段把“不联网”的产品承诺翻译成模块边界、测试范围和商店审核材料。

开发细节补充:这篇记录放在 Sumi Mahjong 禅艺麻将 的产品日记里,不是为了把一个功能包装成故事,而是把“06 · 技术选择:为什么用 SwiftUI 而不是游戏框架”放回真实项目推进中看。它要同时回答三件事:用户为什么需要这个点,开发时哪些边界必须先定住,以及这个选择会怎样影响上架、推广和后续课程复盘。平台口径是 iPhone / iOS / 游戏,当前公开状态是 App Store / 无广告 / 无追踪,所以文案不能脱离真实发布进度。

对应的 docs 线索主要来自 ZenMahjong 产品策略、玩法算法与判定、牌面资产和动效记录、完成审计与本地化上架文档。公开页面不会照搬内部工作记录,而是把可公开、可学习、不会泄露私密路径和账号信息的事实整理出来。ZenMahjong docs 覆盖开发哲学、痛点功能清单、命名品牌、UI 结构、主题美术、定价 IAP 和本地化上架。 开发计划记录了玩法算法、两折线判定、周 1 开发日志、动效粒子、开源布局参考、随机布局策略和牌面生成流程。 完成审计把玩法、隐私、无广告、StoreKit、素材和上架说明合在一起,让游戏不是只停留在可玩 Demo。 公开文章要说明为什么小游戏也需要不做清单:无广告、无账号、无体力、无排行榜,都是架构和商业化选择。

从产品功能看,Sumi Mahjong 禅艺麻将 关联的能力包括:144 张手调水墨麻将牌、经典两折线连接规则、撤销、提示、洗牌、无广告 SDK、无账号、无第三方追踪。写这类日记时,不能只说“做了什么”,还要说明为什么先做这些、为什么暂时不做另一些。比如一个按钮、一个导入流程、一个本地模型开关或一段截图文案,放在代码里只是小改动,放在产品里却会影响用户理解、审核员复现和后续推广素材。

从工程推进看,这篇日记对应的检查点是:轻量游戏的上架、IAP 和隐私边界;产品页如何表达安静体验。真实开发最容易失真的是中间过程,因为最后页面看起来只有一个结果,但实际会经历方案取舍、权限确认、素材准备、测试设备、审核备注和发布节奏。把这些过程写下来,后面做同类产品时才不会重新踩同一个坑。

从隐私和合规看,当前约束是:正常游玩不需要网络;付费解锁通过 Apple StoreKit 完成。这类信息必须前置到开发日记里,因为独立产品的可信度不是靠口号建立的,而是靠数据在哪里处理、用户能不能退出、功能是否离线可用、商店页怎么承诺、隐私政策是否与实现一致这些小事实积累出来的。

从课程和复用看,这篇内容可以沉淀到 iOS 小游戏、StoreKit 2、无广告产品、多语言上架。它的价值不只是给访问者看一个产品,而是展示一个独立开发者怎样把想法转成可验证的产品:先收窄场景,再选技术路径,再做体验最小闭环,最后把审核、推广、运营数据和失败教训都纳入下一次迭代。

轻量游戏也可以成为完整产品案例:规则、手感、美术、IAP、审核和推广都能拆开复用。 这也是为什么每篇产品日记都要写到足够长:不是为了凑字数,而是为了把“证据、决策、实现、边界、复盘”都放在同一页,让读者看到一个判断是怎样被逐步验证出来的。最难的是让麻将消除既安静又耐玩,同时避免广告化和过度游戏化破坏产品气质。

所以这篇日记的结论不是“功能已经写完”,而是把一个阶段的判断公开化:哪些证据足够支撑继续推进,哪些资料还需要回到源码、商店材料、公开文案或运营观察里补齐。这样的记录会比单纯的发布公告更慢,但也更真实,能让产品页、发布记录和课程内容保持同一条事实线。

验收时我会把它拆成四个层次:第一层是用户路径能不能走通,第二层是异常状态有没有被诚实处理,第三层是页面上的按钮、状态、截图和文案是否对应真实发布渠道,第四层是公开证据能否支撑这个判断。只要其中一层对不上,产品看起来再完整,也不能算真正进入下一个阶段。

交接时也要保留边界:源码、构建、测试、商店元数据、公开文案、平台反馈和运营观察分别保存原始资料。产品日记只把这些事实翻译成读者能理解的过程,不替任何私有记录保存原始材料。

把这些内容公开出来,还有一个很现实的原因:AI 教程如果只展示成功结果,很容易让人误以为产品是一次生成出来的。真实情况恰好相反,真正可学习的是一次次收窄、验证、失败、补证据和重新提交。日记越具体,后续读者越能看到判断的脉络,而不是只看到一个漂亮的截图。

为什么选择系统框架

Sumi Mahjong 的技术栈故意很朴素:SwiftUI 负责界面,SwiftData 负责本地状态,StoreKit 2 负责一次性购买。这里没有第三方分析、付费 SDK、广告 SDK,也不把小产品过早复杂化。

这不是保守,而是和产品承诺一致。一个强调离线、无账号、无广告的小游戏,如果一开始就塞进一堆外部 SDK,后面隐私说明、审核解释、崩溃排查和用户信任都会变重。

为什么不先上游戏框架

Sumi Mahjong 的主要难点不是实时物理、碰撞、角色动画或联网对战,而是牌堆布局、可选牌判定、提示可信度、主题资产和上架表达。用 SwiftUI 足够完成首发,并且能更快接入系统设置、StoreKit 和本地化。

SpriteKit 或其它游戏框架不是被否定,而是放在边界清楚的位置:如果后续消除粒子、棋盘渲染或大量动画真的成为性能瓶颈,再把 VFX 层局部替换;不要为了“像游戏开发”而提前把整个项目复杂化。

模块边界怎么拆

核心拆法是把游戏引擎和界面分开。引擎只处理牌、位置、匹配、提示、洗牌和局面生成;视图层只处理点击、选中状态、动画和页面流转;购买模块只暴露主题是否解锁。

这种拆法让后续维护简单很多。比如要改主题选择页,不应该影响匹配规则;要改购买卡片,不应该让游戏引擎知道商品信息;要改动画,也不应该改变一对牌能不能消除。

最难的不是写页面,而是防止边界被打穿

小项目常见问题是越写越随手:某个 View 直接读购买状态,某个按钮直接改游戏数组,某个提示功能又复制一份匹配逻辑。短期能跑,长期就会出现规则不一致。

所以这里需要一条工程纪律:提示必须复用真实匹配函数,洗牌必须保留剩余牌分布,主题解锁必须只通过购买模块判断,局中不能弹出销售卡片。规则只有一份,入口可以有多个。

审核和隐私也受架构影响

当架构确定为本地优先,隐私政策就可以非常清楚:不收集数据、不追踪、不需要账号、不提供服务器功能。审核说明也能直接解释产品为什么没有登录、为什么没有网络能力。

这也是个人站产品页要承接的内容:不是只放下载按钮,还要把产品边界、支持入口、隐私政策和开发思路讲清楚。技术架构最后会变成用户能看懂的信任表达。