【游戏功能】
安全巡检扫出一笔可疑的挂账:玩家的"周围单位结算"列表里,同一只怪每零点八秒出现一次,可战斗记录里玩家根本没出过手——追了两轮日志才发现是剑环:三柄飞剑绕着玩家转,剑锋扫到谁,谁就在列表里挂一次号。剑环不出手,出手的是绕着你的刀。今天这篇按引擎技能脚本的全规格把剑环拆开:配置表、飞剑构件、环绕结算、定时器、调试按钮。
一、效果演示:三柄飞剑,一圈削皮
演示场点「剑环!」:三柄青白色的小剑从鞘中跃出,绕着玩家高速旋转——剑环的轨道是一圈淡青的椭圆线,三柄剑首尾相追。往前顶一步,剑环扫到怪身上:一贴一刀九,青色的小数字一跳一跳,贴得越近跳得越勤;你退开半步,剑环空转,怪也喘一口气。十秒后三柄剑齐齐归鞘,下一环等冷却。演示里试着把站位从远到近推三次:远处的怪毫发无伤,中距离偶尔挨一刀,贴身的那只被削得嗷嗷叫——剑环的价值全在你敢不敢往前顶——顶一步是每秒十一点的贴身账,退一步就是三柄剑的白转。
fx-swordring
二、底层原理:一条环绕轨道加一份贴身结算
模块的机关是一对搭档。轨道侧:三柄剑的极角相差一百二十度、随模块节拍匀速推进——剑的位置永远是极坐标换算的即时值,不存坐标副本。结算侧:贴身判定独立于轨道——怪的横坐标离玩家小于轨道半径加三十,即进入剑锋的扫掠带;扫掠带内的结算按零点八秒一跳、一跳九点,跳与轨道的转速互不挂钩——转速是视觉的圆舞,结算是一板一眼的记账,两套时钟并存才不会把伤害跳成抽搐。归鞘是单向的:十秒一到三剑齐收,环期不做续杯,冷却十二秒从头再攒。
三、核心代码:完整模块(上·骨架)
--------------------------------------------------------------------------------
-- @file SwordRing.lua
-- @brief 剑环 —— 三柄飞剑绕着转,贴身就挨削
-- 客户端表现模块:配置表 / 飞剑构件 / 环绕结算 / 定时器
--------------------------------------------------------------------------------
local SwordRing = {}
--------------------------------------------------------------------------------
-- 配置与常量
--------------------------------------------------------------------------------
local CONST = {
RING_LIFE = 10.0, -- 剑环十秒
RING_CD = 12.0, -- 冷却十二秒
RING_RADIUS = 62, -- 轨道半径六十二
RING_SPEED = 3.2, -- 每秒转三点二弧度
SWORD_COUNT = 3, -- 三柄飞剑
HIT_GAP = 0.8, -- 结算零点八秒一跳
HIT_DMG = 9, -- 一跳九
HIT_BAND = 30, -- 扫掠带外扩三十
-- 颜色
COLOR_BLADE = "#e6edf3", -- 剑白
COLOR_DEEP = "#1f6f5f", -- 深青
COLOR_GHOST = "#64d8b8", -- 剑青
ZORDER_GROUND = 118,
ZORDER_SWORD = 133,
ZORDER_EFFECT = 135,
AUTOINC_BASE = 937000,
}
--------------------------------------------------------------------------------
-- 模块内部状态
--------------------------------------------------------------------------------
local _ringT = 0 -- 环期余时
local _orbit = 0 -- 轨道相位
local _hitT = 0 -- 结算节拍
local _cdLeft = 0
local _scheduler = nil
local _autoInc = 0
local m_cos = math.cos
local m_sin = math.sin
--------------------------------------------------------------------------------
-- 辅助函数
--------------------------------------------------------------------------------
local function GenID(prefix)
_autoInc = _autoInc + 1
return string.format("%s_%d", prefix or "SWR", CONST.AUTOINC_BASE + _autoInc)
end
local function GetMyPos()
local x = SL:GetValue("ACTOR_POSITION_X", SL:GetValue("USER_ID"))
local y = SL:GetValue("ACTOR_POSITION_Y", SL:GetValue("USER_ID"))
if not x or not y then return nil end
return { x = x, y = y }
end
local function SafeRemove(node)
if node and not GUI:Widget_IsNull(node) then
GUI:removeFromParent(node)
end
end
local function ShowTip(msg)
if msg and msg ~= "" then SL:ShowSystemTips(msg) end
end
---飞剑构件:菱形剑身加脊线
local function CreateSwordNode()
local node = GUI:Layout_Create(GUI:Attach_SceneF(), GenID("Swd"), 0, 0, 0, 0, false)
GUI:setLocalZOrder(node, CONST.ZORDER_SWORD)
GUI:DrawLine_Create(node, "edge_l", 0, 0, 3, 0, -13, -4, 0, CONST.COLOR_BLADE, 240)
GUI:DrawLine_Create(node, "edge_r", 0, 0, 3, 0, -13, 4, 0, CONST.COLOR_BLADE, 240)
GUI:DrawLine_Create(node, "spine", 0, 0, 2, 0, -8, 0, 9, CONST.COLOR_GHOST, 240)
return node
end
骨架的三处立规。_orbit 只存相位不存剑的坐标——三柄剑的位置由相位加偏移角即时换算,坐标副本一存,转速一调三柄剑就散架。飞剑构件四笔线画一个菱形加一道脊——剑的形越简,转起来越快,细节堆多了转速跟不上就成了一坨。三柄剑的相位差一百二十度写死在分布里——三剑追尾重叠的版本,剑环看上去只有一柄剑在转。HIT_BAND 是轨道半径的外扩量——剑有长度,剑锋扫掠的范围比轨道大一圈,结算带必须比轨道宽。
四、核心代码:完整模块(下·定时器与环绕结算)
--------------------------------------------------------------------------------
-- 开环与归鞘
--------------------------------------------------------------------------------
function SwordRing.Cast()
if _cdLeft > 0 or _ringT > 0 then return end
_cdLeft = CONST.RING_CD
_ringT = CONST.RING_LIFE
ShowTip("剑出了鞘——往前顶,让剑环贴着它削")
end
--------------------------------------------------------------------------------
-- 定时器:轨道推进与贴身结算
--------------------------------------------------------------------------------
if not _scheduler then
_scheduler = SL:Schedule(function(dt)
_cdLeft = math.max(0, _cdLeft - dt)
if _ringT <= 0 then return end
_ringT = _ringT - dt
_orbit = _orbit + CONST.RING_SPEED * dt
local mp = GetMyPos()
if not mp then return end
for s = 0, CONST.SWORD_COUNT - 1 do
local a = _orbit + s * (6.28 / CONST.SWORD_COUNT)
local sx = mp.x + m_cos(a) * CONST.RING_RADIUS
local sy = mp.y - 46 + m_sin(a) * CONST.RING_RADIUS * 0.4
SL:DrawSword(s, sx, sy, a)
end
_hitT = _hitT + dt
if _hitT >= CONST.HIT_GAP then
_hitT = _hitT - CONST.HIT_GAP
local tid = SL:GetValue("MARK_TARGET_ID")
local tp = tid and SL:GetValue("ACTOR_POSITION_X", tid)
if tp and math.abs(tp - mp.x) <= CONST.RING_RADIUS + CONST.HIT_BAND then
SL:ActorHurt(tid, CONST.HIT_DMG)
SL:TipAbove(tid, "-" .. CONST.HIT_DMG)
end
end
if _ringT <= 0 then
ShowTip("剑归鞘了——下一环跟上")
end
end, 0.02)
end
SL:RegisterLUAEvent(LUA_EVENT_SCENE_CLEAR, "SWR_Clear", function()
_ringT = 0
for s = 0, CONST.SWORD_COUNT - 1 do
SL:DrawSword(s, -999, -999, 0)
end
end)
SL:ScheduleOnce(function()
ShowTip("技能已加载: 剑环 (调试按钮触发)")
end, 1.0)
return SwordRing
下半场的两本账分得清清楚楚。轨道侧每帧推进相位、按极坐标画出三柄剑——画剑走的是纯视觉,圆舞再快也不产生一滴伤害。结算侧零点八秒一拍、按扫掠带点名——伤害只认带宽不认剑的位置,哪怕剑恰好转到背面,带内的怪照样挨削:视觉是圆舞,账本是节拍器,剑环的飘逸全靠这两本账各走各的。场景清空时把三柄剑画到屏幕外——归鞘的剑不留残影,残影会挂在下一场仗的起步位。剑环期的普攻出手要和剑的转速错开——两把刀一个拍子,视觉上就糊成一把宽刀。
五、调参指南与商业服怎么用
调参三笔账。三剑零点八秒一跳九点是每秒十一点的贴身产值——产值对玩家普攻的四成上下是甜区,剑环是副刀不是主刀;每秒超过十五点,近战职业的普攻就沦为剑环的充电动作。轨道半径六十二对扫掠带外扩三十——带宽决定剑环的"脾气",带宽越宽越像范围光环,越窄越考验顶位的胆量。环期十秒对冷却十二秒留两秒真空——真空里近战要用真空手接敌,这两秒的落差是剑环手感的骨头。常见坑三个:结算带用点到点距离而特效画椭圆,看得见的剑和管用的剑两个半径;相位推进乘了帧率的系数,高帧率的剑转出残影低帧率的剑瞬移;归鞘时结算没停,最后一拍在怪死后还扣了尸体的血。
商业服里剑环是"近战美学"的变现口:剑环的剑皮肤按周目卖——青虹、赤霄、霜刃,绕着玩家转的每一柄剑都是行走的活广告。副本里它是"顶位奖励"的具象:敢往前顶的近战白拿一层削皮输出,站位的价值第一次被数字承认——顶位的胆子越大,剑环的账面越厚。变体做成剑环共鸣:双人剑环半径重叠时合鸣,削皮翻倍——配合的化学反应写在轨道的几何里。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。
写完留一句给做环绕系的同学:剑环卖的是"随身的安全区"——轨道转得越稳,玩家往前顶的每一步越有底气。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 if _shadowT 0 then spd = noShadow and 12 or 24 end ——一行…
【游戏功能】 魂卫的全机制就一句:杀掉小怪化一盏魂火跟着你走,每盏魂火两秒自动劈最近的大怪一口八点,至多三盏——「引魂!」按…
【游戏功能】 一道咒飞过来,硬吃是四秒里一秒十的钝疼——有没有第三条路?纸人替灾给的就是第三条路:贴一个纸人在身后,八秒里头…
【游戏功能】 挨打还能赚钱?水镜式的答案是:挨的刀七成存进镜里不扣血、三成照常疼,六秒后点「还镜」,存量乘一点五放成水炮——…
【游戏功能】 if _mirrorT 0 then SL:TipAboveMe("免疫") return end ——一道写…
【游戏功能】 远近战的矛盾怎么解?远战的答案是把怪挡在射程外,近战的答案是把人拖进射程内——缩地阵给的第三个答案最蛮横:圈只…