【游戏功能】
一、一个盖住脸的圈
冰霜新星的第一版被测试打回来的理由很清奇:"怪被冻住之后看不见怪了"。检查发现新星特效的扩散环和地面寒雾全部画在了角色层之上,半径一百五十像素的半透明蓝雾正好糊在怪脸上,冻住的目标成了蓝雾里的一团影子。没有报错、没有崩溃,就是"看不见"——层级错了。地面系的范围特效,必须老老实实躺在地面层,哪怕它再漂亮。
二、机制原理:地面层与角色层
冰霜新星的全部表现都应该发生在脚下:范围圈是地面上的虚线椭圆,绽开的双环压着地皮扩张,碎冰晶散落在圈内随机位置,寒气粒子低空横飘。绘制顺序上这些全在角色之前完成,角色永远踩在冰面上而不是被冰面糊住。唯一盖在角色身上的只有受冻目标身上那层半透明冰壳——那是状态标记不是场景特效。范围判定与视觉范围严格同源:椭圆横向半径、纵向压扁到零点五五,判定和画图用同一组参数,玩家看到多大的圈,圈就冻多大的范围。
fx-nova
三、正确写法:地面层新星(引擎侧)
local NOVA_FLAT = 0.55 -- 纵向压扁比: 判定与绘制同源
function CastFrostNova(caster, radius)
-- 施法动作 + 出手帧触发
caster:PlayAction(global.MMO.ANIM_SKILL)
local hitFrame = caster:GetHitFrame()
OnFrameReached(hitFrame, function()
local ground = GetGroundLayer() -- 地面层: 永远在角色之下
ground:AddChild(CreateNovaRings(caster, radius, NOVA_FLAT))
ground:AddChild(CreateFrostShards(caster, radius, NOVA_FLAT, 26))
local frozen = 0
for _, m in ipairs(GetMonstersAround(caster, radius, NOVA_FLAT)) do
m:ApplyFrozen(2.6) -- 冻结 + 播受击
frozen = frozen + 1
end
if frozen == 0 then ShowSystemTips("没有冻到任何目标") end
end)
end
function GetMonstersAround(center, radius, flat)
local out = {}
for _, m in ipairs(scene:GetMonsters()) do
local dx, dy = m:GetX() - center.x, m:GetY() - center.y
if math.sqrt(dx * dx + (dy / flat) * (dy / flat)) <= radius then
table.insert(out, m) -- 椭圆判定: y 除压扁比还原
end
end
return out
end
四、四个必须钉死的细节
五、心法:特效先问画在哪层
写任何特效前先回答一个问题:它属于哪一层?地面层、角色层、状态层、界面层,四层从下到上各有主人。放错层的特效不报错,只会被测试用"看不见""挡住了""怎么飘到界面上了"这种模糊语言打回来。层级和坐标、锚点一样是特效的先天属性,出生时就定好,别等出了问题再挪。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 一、先抛一个坑 同样是"放一片技能特效",为什么有的游戏炸二十个火球丝般顺滑,有的游戏炸五个就掉帧?直觉答案"…
【游戏功能】 一、一个职业选手的操作拆解 看高手第一视角录像,最费解的操作是:他打一下、退两步、再打一下,全程像在跳一支排练…
【游戏功能】 一、一个被浪费的冰冻 组里新人做了个冰法连招:冰冻命中后立刻接大火球,理论伤害翻倍。试玩却怪怪的——冰冻刚套上…
【游戏功能】 一、一次吓到自己的召唤 召唤兽系统的内测录像里有个名场面:道士按下召唤,屏幕上"啪"地多出一只金毛巨狼,没有地…
【游戏功能】 一、先抛一个坑 领域类技能最怕做成"一次性特效放完拉倒":冰环扩一圈、冻一下、结束——站在领域里的怪第二秒解冻…
【游戏功能】 一、一次只有挨打没有还手的守势 守势类技能首版的哀嚎最一致:"金环弹开了围攻,然后呢?"——然后没有然后。格挡…