【游戏功能】
一、一个被风卷走的判空
龙卷风聚怪技能首测,最灵异的 bug:怪被吸到风眼附近后集体"抽搐"——坐标每帧在风眼两侧来回横跳。排查发现吸力计算把向心速度和切向速度都直接加在坐标上,两股力量每帧打架,合位移路径变成锯齿。龙卷风的运动学是"向心加切向"的双螺旋:向心分量负责吸拢,切向分量负责绕圈,两股速度正交合成,怪才会沿螺旋线优雅地卷进风眼。
二、机制原理:向心加切向的螺旋吸入
龙卷风的吸入模型是两个速度分量的合成:向心分量把目标往风眼拉,大小随距离衰减(越近吸力越弱,避免过冲抖动);切向分量让目标绕风眼公转,方向统一(顺时针或逆时针),大小恒定。两分量合成的结果是一条半径不断缩小的螺旋线——怪被卷进去的过程自带旋转的视觉,根本不用给怪单独做旋转动画。旋风本体的视觉是三层椭圆虚线环反向旋转,配合碎屑点绕圈,风的"形"就立住了。
fx-tornado
三、正确写法:双分量螺旋吸入(幂尔版)
local Tornado = {}
local CONST = { MSG_ID = 12330, KEY = "Tornado", PULL = 100, TANGENT = 90, DURATION = 5 }
function Tornado.Cast(casterID, eyeX, eyeY)
Tornado._eye = { x = eyeX, y = eyeY }
Tornado._left = CONST.DURATION
Tornado._sched = SL:Schedule(function(dt)
Tornado:Update(dt)
end, 0.02)
end
function Tornado:Update(dt)
self._left = self._left - dt
if self._left <= 0 then
SL:UnSchedule(self._sched)
self._sched = nil
return
end
for _, id in ipairs(SL:GetValue("FIND_IN_VIEW_MONSTER_LIST") or {}) do
local mx = SL:GetValue("ACTOR_POSITION_X", id)
local my = SL:GetValue("ACTOR_POSITION_Y", id)
local dx, dy = self._eye.x - mx, self._eye.y - my
local dist = math.sqrt(dx * dx + dy * dy)
if dist > 40 then -- 风眼内不再吸
local pull = CONST.PULL * math.min(1, dist / 230)
-- 向心 + 切向: 两个正交分量合成螺旋
SL:SetActorVelocity(id,
dx / dist * pull - dy / dist * CONST.TANGENT,
dy / dist * pull + dx / dist * CONST.TANGENT)
end
end
end
return Tornado
四、四个必须钉死的细节
五、心法:力出来了,表现就自己长出来了
龙卷风没有一个"特效函数"——螺旋吸入是运动规则,怪被卷得转圈是运动的自然结果,旋风虚线环只是运动的可视化注脚。这类"力驱动表现"的写法比"逐帧摆位置"高明得多:规则恒定,表现无限。风、水流、磁场、引力井,全是同一套双分量合成的换皮。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 摸一下才一层寒,摸三下怎么就冻成冰雕了?冰霜之触的答案是叠:掌风每摸它一下,身上多一层寒气——一层微凉、两层发…
【游戏功能】 治疗符的全部机制就这一行:一张黄符贴在身上,每秒回八点血——但符有三条耐久,每挨一爪撕掉一角,撕满三张符碎血停…
【游戏功能】 一粒火种扔在它脚边,为什么等了一秒才炸?火莲绽放的答案开在花瓣里:火种落地生根,四瓣火莲缓缓张开——花开到极致…
【游戏功能】 箭明明钉在胸口了,狼怪为什么走得越来越慢?寒冰箭的账分两页:第一页是箭伤,小小的三十二点;第二页是寒气——箭杆…
【游戏功能】 一声唿哨,天上真的会掉一只鹰?神鹰俯冲的浪漫就在这:战士仰天长哨,一只金鹰从画面外盘旋而下,双爪直取狼怪天灵盖…
【游戏功能】 弓都拉满了为什么还不放?落日弓的答案写在弧线上:它等的不是时机,是 满弓 ——弓开如落日,箭去似流星,一秒的凝…