【游戏功能】
一、一个不报错的吞箱事故
开箱功能上线第三天收到投诉:动画播完了,东西没弹出来,宝箱像吞了玩家的装备。日志干净得很——没有报错,没有崩溃。复现路径是手快的玩家:开箱动画播放中直接按 ESC 关掉了奖励预览面板,动画结束回调里操作的那个卡片节点早随面板一起销毁了,回调里 tolua.isnull 判空直接 return,静默得像什么都没发生过。静默失败比崩溃可恶十倍:崩溃有人修,静默失败只有玩家在替你数钱。
二、机制原理:动画段串联与回调防御
一次开箱在表现上是四段串联的状态机:摇箱(一点二秒左右晃动,蓄期待感)→ 开盖(盖子弹开的小爆发)→ 光柱(颜色由稀有度决定,冲天零点七秒)→ 物品弹出(卡片从箱口飞出并轻微回弹)。每段由定时器或动作回调推进到下一段,任何一段的回调都可能在你意料之外的时刻晚到——界面已关闭、场景已切换、甚至角色已下线。所以每个回调的第一件事都是防御:节点还在不在、面板还开着没、状态还匹配吗。
open-box
三、正确写法:开箱状态机
local OpenBoxView = class("OpenBoxView")
function OpenBoxView:OnClickBox()
if self._phase ~= "idle" and self._phase ~= "done" then
return -- 播放中禁点, 防连点错乱
end
self._phase = "shake"
self._boxBody:runAction(cc.Sequence:create(
self:BuildShakeAction(1.1), -- 摇箱: 衰减的左右摆
cc.CallFunc:create(function() self:OnShakeDone() end)
))
end
function OpenBoxView:OnShakeDone()
if tolua.isnull(self._boxBody) then return end -- 界面已关: 全链静默退出
self._phase = "burst"
self._boxLid:runAction(cc.Sequence:create(
cc.RotateTo:create(0.15, -52),
cc.CallFunc:create(function() self:OnBurstDone() end)
))
end
function OpenBoxView:OnBurstDone()
if tolua.isnull(self._boxLid) or self._phase ~= "burst" then return end
self._phase = "beam"
local beam = CreateBeamEffect(self._dropData.grade) -- 稀有度决定光柱颜色
self:addChild(beam)
PerformWithDelayGlobal(function()
if tolua.isnull(beam) then return end
beam:removeFromParent()
self:ShowDropCard() -- 物品卡片弹出
end, 0.7)
end
function OpenBoxView:ShowDropCard()
if self._phase ~= "beam" then return end
self._phase = "done"
-- 卡片飞出 + 回弹 + 稀有度描边
end
四、四个必须钉死的细节
五、心法:每段动画都要能独自谢幕
串联动画的工程本质是多个异步回调在时间上排队,而回调的宿主随时可能消失。写任何演出链之前先写好退场协议:界面关闭时把状态机打死、在途定时器全部注销、残余特效清干净。开箱如此,技能演出如此,新手引导的每一步高亮也如此——能干净退场的才叫状态机,退不了场的都叫定时炸弹。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【语法算法】 闭包工厂的本质就这一行: 外层函数接收配置,返回一个闭包——闭包捕获配置,后续调用使用捕获的配置——闭包工厂的…
【语法算法】 闭包工厂的本质就这一行: 外层函数接收配置,返回一个闭包——闭包捕获配置,后续调用使用捕获的配置——闭包工厂的…
【语法算法】 泛型 for 的四种形态就这两行: 泛型 for 的四种形态覆盖了 Lua 所有的遍历需求——从无序遍历到有序…
【语法算法】 string.find 的起始偏移就这一行: 第三个参数 init 是搜索的起始偏移——从字符串的第 init…
【语法算法】 CPU 时间和墙钟时间的分界就这两行: os.clock 返回 CPU 时间——程序实际占用处理器的秒数——o…
【语法算法】 元方法 __unm 的触发就这一行: 对带 __unm 的表做一元负号操作 -t 时,Lua 调用 __unm…