【游戏功能】
挨打还能赚钱?水镜式的答案是:挨的刀七成存进镜里不扣血、三成照常疼,六秒后点「还镜」,存量乘一点五放成水炮——连本带利,它自己出的力。这篇的核心代码照引擎技能脚本的全规格写:配置表、水镜构件、存储队列、释放清算、定时器、调试按钮。
一、效果演示:六秒存账,一炮清账
演示场点「水镜!」:一圈水色的光环把玩家罩住,头顶亮出"镜 六秒 · 存 零"。大怪的两秒一刀照常拍过来:三十点的刀当场只掉九——灰色小字,另外二十一并进头顶的"存"读数,水环跟着亮一格——存字一跳,玩家就知道这一刀没白挨。水环跟着亮一格——存字一跳,玩家就知道这一刀没白挨。存储读数叠到封顶的那一刻要有提醒——镜满之后挨的刀全是实价,满仓不提示的版本玩家白挨三刀才发现。「还镜!」一点:水炮轰出去,存量乘一点五——存六十还九十,深青色的水柱连底带顶贯穿它。水柱连底带顶贯穿它——水炮的动画要和普攻的刀光彻底分家,一炮一清账。演示里试两条路:挨满六秒自动还,和存到六十提前还——前者的账厚、后者的拍子准,两种还法都是这门镜的用法。
fx-watermirror
二、底层原理:一份拆账入口加一个存储读数
模块的账本是一对分账器。入账侧:扣血入口的钩子把每一刀拆成两半——三成当场结、七成压进存储读数,存储封顶一百二,防爆仓。出账侧:「还镜」或者镜到期自动清算,存储乘一点五一次放出去,读数清零。拆账的分寸是全套机制的性格:当场三成让玩家"仍会疼",七成入镜让玩家"值得挨"——两成的当场份额再低,玩家就成了无敌的充电桩;七成的存储再高,镜就变成永动炮台。两成的当场份额再低,玩家就成了无敌的充电桩;七成的存储再高,镜就变成永动炮台。提前还镜的价值在"掐拍":怪的蓄力大招落地前抢先放一炮,伤害与打断的双重收益只有会算账的玩家拿得到。到期自动还是保底清算:六秒到了不管存多少(满二十起还)都自动出膛,攒着不还的玩家不会被利息拖死。攒着不还的玩家不会被利息拖死。水炮的射程也要写清——还镜的水柱打的是当前目标,目标切了水炮跟着切,瞄着谁存就冲着谁放。
三、核心代码:完整模块(上·骨架)
--------------------------------------------------------------------------------
-- @file WaterMirror.lua
-- @brief 水镜式 —— 挨的刀存进镜里,连本带利还回去
-- 客户端表现模块:配置表 / 水镜构件 / 存储读数 / 定时器
--------------------------------------------------------------------------------
local WaterMirror = {}
--------------------------------------------------------------------------------
-- 配置与常量
--------------------------------------------------------------------------------
local CONST = {
MIRROR_LIFE = 6.0, -- 镜开六秒
MIRROR_CD = 10.0, -- 冷却十秒
NOW_CUT = 0.3, -- 当场三成
STORE_CAP = 120, -- 存储封顶一百二
RELEASE_MIN = 20, -- 二十起还
RELEASE_RATE = 1.5, -- 还镜乘一点五
-- 颜色
COLOR_WATER = "#5ab8d8", -- 水青
COLOR_DEEP = "#1a4a5e", -- 深青
COLOR_GHOST = "#c5ecf5", -- 水白
ZORDER_GROUND = 118,
ZORDER_MIRROR = 134,
ZORDER_EFFECT = 135,
AUTOINC_BASE = 940000,
}
--------------------------------------------------------------------------------
-- 模块内部状态
--------------------------------------------------------------------------------
local _mirrorT = 0 -- 镜的余时
local _stored = 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 "WTM", CONST.AUTOINC_BASE + _autoInc)
end
local function GetActorPos(actorID)
if not actorID then return nil end
local x = SL:GetValue("ACTOR_POSITION_X", actorID)
local y = SL:GetValue("ACTOR_POSITION_Y", actorID)
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 CreateMirrorNode()
local mp = GetActorPos(SL:GetValue("USER_ID"))
if not mp then return end
local node = GUI:Layout_Create(GUI:Attach_SceneF(), GenID("Mir"),
mp.x, mp.y - 46, 0, 0, false)
GUI:setLocalZOrder(node, CONST.ZORDER_MIRROR)
for i = 1, 26 do
local a1 = (i - 1) / 26 * 6.28
local a2 = i / 26 * 6.28
GUI:DrawLine_Create(node, string.format("m_%d", i), 0, 0, 2,
m_cos(a1) * 26, m_sin(a1) * 46, m_cos(a2) * 26, m_sin(a2) * 46,
CONST.COLOR_WATER, 190)
end
return node
end
骨架的三处立规。存储读数 _stored 是数字不是表——拆账只进不出,一笔总数就够,逐笔明细是化劲那类分期机制才需要的东西。STORE_CAP 一百二封顶防爆仓——六秒里挨四刀就满,满仓后继续挨的刀按实价扣,玩家立刻明白该还镜了。玩家立刻明白该还镜了,还镜的按钮这时候也该亮起来。水环构件椭圆纵轴比横轴长——罩人的镜是竖着的环,贴地的阵才是扁的。
四、核心代码:完整模块(下·定时器与存储清算)
--------------------------------------------------------------------------------
-- 拆账入口:七成存三成疼
--------------------------------------------------------------------------------
local function Hurt_Split(raw)
local store = math.round(raw * 0.7)
local now = raw - store
_stored = math.min(CONST.STORE_CAP, _stored + store)
SL:PlayerHurt(now)
SL:TipAboveMe("存" .. store)
end
--------------------------------------------------------------------------------
-- 还镜清算
--------------------------------------------------------------------------------
local function Mirror_Release(targetID)
if _stored < CONST.RELEASE_MIN then
ShowTip("镜里才" .. _stored .. "点——二十起还")
return
end
local vd = math.round(_stored * CONST.RELEASE_RATE)
_stored = 0
SL:WaterBlast(targetID, vd)
SL:TipAbove(targetID, "-" .. vd)
_mirrorT = math.min(_mirrorT, 0.5)
end
--------------------------------------------------------------------------------
-- 画镜与到期
--------------------------------------------------------------------------------
function WaterMirror.Cast()
if _cdLeft > 0 or _mirrorT > 0 then return end
_cdLeft = CONST.MIRROR_CD
_mirrorT = CONST.MIRROR_LIFE
_stored = 0
CreateMirrorNode()
ShowTip("镜开了——六秒里挨的刀七成存镜")
end
--------------------------------------------------------------------------------
-- 定时器:镜寿、拆账与自动清算
--------------------------------------------------------------------------------
if not _scheduler then
_scheduler = SL:Schedule(function(dt)
_cdLeft = math.max(0, _cdLeft - dt)
if _mirrorT <= 0 then return end
_mirrorT = _mirrorT - dt
if _mirrorT <= 0 then
local tid = SL:GetValue("MARK_TARGET_ID")
if tid and _stored >= CONST.RELEASE_MIN then
Mirror_Release(tid)
ShowTip("镜到时自动还了")
else
ShowTip("镜散了——存得太少,白开")
end
end
end, 0.02)
end
SL:RegisterLUAEvent(LUA_EVENT_LOCAL_HURT, "WTM_Hurt", function(data)
if data and data.raw and _mirrorT > 0 then
Hurt_Split(data.raw)
end
end)
SL:ScheduleOnce(function()
ShowTip("技能已加载: 水镜式 (调试按钮触发)")
end, 1.0)
return WaterMirror
下半场的两处见功夫。拆账钩子的第一行先查镜开着没有——镜散后挨的刀走实价,这条写在事件订阅的过滤里,拆账函数自身不必重复判断。到期自动清算时 _stored 不足二十的处理是礼貌——存得太少的自动还反而是浪费,提示一句"白开"让玩家下次学乖;清算完 _mirrorT 清零,镜与读数同时归零,账面永远只有一份真相。
五、调参指南与商业服怎么用
调参三笔账。当场三成对存储七成是"疼但不致命"的分账线——当场份额超过五成,玩家挨刀照样掉血如流水,存镜的意义减半;低于两成,坦克玩家开着镜站在怪堆里当充电宝。释放乘一点五是利息线——利息高过普攻的两倍,玩家会故意挨打刷镜,机制变成自虐换伤害的算术游戏;一点五上下是安全区。镜寿六秒对冷却十秒留四秒真空——真空里玩家裸挨,这段裸挨的疼就是学会掐镜期的学费。常见坑三个:拆账钩子把治疗也拆了,奶一口存半口;存储满仓后的实价刀没有提示,玩家不知道镜满了;自动清算的目标在镜开之后切换,水炮打向了旧目标。
商业服里水镜式是"坦克流"的第二春:开镜站桩挨打、关镜一炮清场的循环,坦克玩家第一次有了自己的输出循环。比武场里它是心理战的镜像:对手打你越狠,还回去的越疼——收着打怕你存、放开打怕炸,两难的对手最有意思。变体做成水镜传承:还镜的水炮溅射治疗队友——挨打的价值再翻一层,坦克的勋章挂在队友的血条上。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。
写完留一句给做存储系的同学:存储机制卖的是"忍的回报"——利息写进乘法里,玩家挨的每一刀都成了投资。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 怪的仇恨为什么永远追着你?因为它看得见你。迷魂香把"看得见"这三个字没收了:一炉香落在它脚下,烟圈六秒——圈里…
【游戏功能】 连击值攒着有什么用?多数战斗的答案是攒个伤害加成——气势给了第二个答案:攒的是一支军队的士气。每一刀涨十二点、…
【游戏功能】 一道割裂挂上去,一秒一跳——它站着跳四,追你的时候崩成八:伤口一动就崩,跑得越快掉得越凶。崩血把"放风筝"从走…
【游戏功能】 突进出去了,回不回得来?多数突进的答案是"不回"——人留在怪堆里听天由命。燕回式给突进装了归途:穿身而过去时一…
【游戏功能】 读条变红的那一秒,全世界都在等一个决定。破招式把这一秒做成整场战斗的心跳:怪交替出红劈和蓝刺,红劈读条时按下破…
【游戏功能】 出招的顺序算不算伤害?大多数战斗里不算——三招乱按和按谱出,账面一个样。连招谱把顺序变成了伤害本身:「劈→撩→…