CHUAN2 DEV ENGINE
996 正版授权研发中心 · 360 授权合作教学中心 · 抖音传奇直播合作授权 · 快手推广运营商授权
OFFICIAL LICENSED ACADEMY 查验官方授权证书 →
// 威海旷世互娱教学基地 · 技术文章
进阶实战游戏功能996引擎

镜面:架起镜墙,它的弹道原样画回去

2026-10-01 07:56 作者:996 技术组 996引擎Lua教程传奇脚本进阶实战游戏功能996引擎

【游戏功能】

防御技的两个流派:金身把伤害归零但自己也停了,铁壁把伤害减半但人还在挨。镜面走了第三条路:竖一面镜墙三秒——弹道撞上镜面原样画回去,威力不减、方向反转,它打你多少它自己挨多少。弹道撞上镜面原样画回去,威力不减、方向反转,它打你多少它自己挨多少——镜墙的反射不加不减,弹道的账面走了一个来回还是那笔原账。它打你多少它自己挨多少。镜墙三秒的寿命对它两秒的弹道节拍——三秒里能反一到两发,一到两发的二十二就是这面墙的全部产出。这篇的核心代码照引擎技能脚本的全规格写:配置表、镜墙构件、弹道反转、定时器、调试按钮。

一、效果演示:一道镜墙,弹道自己回家

演示场点「镜面!」:一面半透明的镜墙在两座之间拔地而起——它的弹道射过来,撞上镜面原路折返,扎进它自己身上二十二点。它的弹道射过来,撞上镜面原路折返,扎进它自己身上二十二点——弹道画回去的那道白光是从镜面到它胸口的直线,去和回的路线一模一样。三秒里它的每一发弹道都变成了它自己的伤——你站在墙后一刀刀安心点它。墙化之后它的弹道恢复实价——但三秒的弹道回声已经把它的血线削掉了一截。三秒的弹道回声已经把它的血线削掉了一截——镜子立得越早,它的弹道替你输出的越多。三秒的弹道回声已经把它的血线削掉了一截——镜子立得越早,它的弹道替你输出的越多。墙的位置落在两座中点是地理的公平——贴着怪立等于贴脸盾,贴着自己立等于玩家专属,中点才是两边的公共地带。演示里注意两处:弹道撞镜的那一帧白光一闪——闪光的位置就是弹道原路折返的折点;回程的弹道颜色变了——去的红、回的白,颜色的差就是归属的变。

demo
 fx-mirrorwall

二、底层原理:一道纵向拦截带加一份弹道反转

模块的机关是一对搭档。拦截带:镜墙是一条纵向的区间带,弹道的横坐标穿过带的横坐标时触发反转——带的纵宽决定"哪一段高度能拦",弹道从墙上飞过去的就不算。反转:弹道的速度取反、方向标置真、去向改写为发射者——反转的弹道走独立的结算口,扎回怪身上二十二。镜墙三秒到期自动化——化的瞬间还在回程途中的弹道继续飞完,不因为镜墙消失而中途蒸发。和弹反镜的分野在形态上:弹反是举在身前的半秒镜面、人工掐时机,镜墙是立在半场的三秒墙、立了就全自动。

三、核心代码:完整模块(上·骨架)

lua
--------------------------------------------------------------------------------
-- @file        MirrorWall.lua
-- @brief       镜面 —— 镜墙立三秒,弹道原样画回
--              客户端表现模块:配置表 / 镜墙构件 / 弹道反转 / 定时器
--------------------------------------------------------------------------------

local MirrorWall = {}

--------------------------------------------------------------------------------
-- 配置与常量
--------------------------------------------------------------------------------
local CONST = {
    WALL_LIFE     = 3.0,        -- 镜墙三秒
    WALL_CD       = 6.0,        -- 镜墙冷却
    WALL_RANGE    = 160,        -- 镜墙落在两座中点
    REFLECT_DMG   = 22,         -- 回弹二十二
    BOLT_DMG      = 22,         -- 它的弹道二十二
    BOLT_SPEED    = 250,        -- 弹速二百五

    -- 颜色
    COLOR_MIRROR  = "#c8d8e8",  -- 镜白
    COLOR_DEEP    = "#2a3a5e",  -- 深镜
    COLOR_GHOST   = "#f0f8ff",  -- 反弹白

    ZORDER_GROUND = 118,
    ZORDER_WALL   = 127,
    ZORDER_EFFECT = 135,

    AUTOINC_BASE  = 964000,
}

--------------------------------------------------------------------------------
-- 模块内部状态
--------------------------------------------------------------------------------
local _wallT      = 0              -- 镜墙余时
local _wallX      = 0              -- 镜墙横坐标
local _cdLeft     = 0
local _bolts      = {}             -- 弹道表
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 "MRW", 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 CreateWallNode(x)
    local node = GUI:Layout_Create(GUI:Attach_SceneF(), GenID("Wall"), x, 0, 0, 0, false)
    GUI:setLocalZOrder(node, CONST.ZORDER_WALL)
    for row = 0, 18 do
        GUI:DrawLine_Create(node, "col_" .. row, 0, 0, 16,
            -8, -row * 4.2, 8, -row * 4.2,
            row % 2 == 0 and CONST.COLOR_MIRROR or CONST.COLOR_DEEP, 210)
    end
    return node
end

骨架的三处立规。镜墙构件用横线叠渐变——墙的层理从横纹里长出来,竖纹的墙像栅栏。WALL_RANGE 一百六十步写在 Cast 的落点计算里——镜墙落在两座的中点,两边的弹道都能被拦。镜墙落在两座之间的中点,两边的弹道都能被拦到。墙的纵高也要够——七十六步的纵高盖住怪的弹道射高,弹道从墙上飞过去的版本拦了个寂寞。弹道表 _bolts 的元素带 back 方向标——去程和回程是两条命,回程的结算口独立写。

四、核心代码:完整模块(下·定时器与弹道反转)

lua
--------------------------------------------------------------------------------
-- 立镜
--------------------------------------------------------------------------------
function MirrorWall.Cast()
    if _cdLeft > 0 or _wallT > 0 then return end
    _cdLeft = CONST.WALL_CD
    _wallT = CONST.WALL_LIFE
    local mp = GetActorPos(SL:GetValue("USER_ID"))
    local tp = GetActorPos(SL:GetValue("MARK_TARGET_ID"))
    if mp and tp then
        _wallX = (mp.x + tp.x) / 2
        CreateWallNode(_wallX)
        ShowTip("镜墙立了——三秒,弹道来了就画回去")
    end
end

--------------------------------------------------------------------------------
-- 弹道的推进与反转
--------------------------------------------------------------------------------
local function Bolt_Update(b, dt)
    b.x = b.x + b.vx * dt
    if not b.back and _wallT > 0 and math.abs(b.x - _wallX) <= 14 then
        b.vx = -b.vx
        b.back = true
        SL:PlayReflectFx(b.x, b.y)
        ShowTip("弹道画回去了——原样,威力不减")
        return true
    end
    if b.back then
        local tp = GetActorPos(SL:GetValue("MARK_TARGET_ID"))
        if tp and math.abs(b.x - tp.x) < 20 then
            SL:ActorHurt(SL:GetValue("MARK_TARGET_ID"), CONST.REFLECT_DMG)
            SL:TipAbove(SL:GetValue("MARK_TARGET_ID"), "-" .. CONST.REFLECT_DMG)
            return false
        end
    else
        local mp = GetActorPos(SL:GetValue("USER_ID"))
        if mp and math.abs(b.x - mp.x) < 20 and _wallT <= 0 then
            SL:PlayerHurt(CONST.BOLT_DMG)
            return false
        end
    end
    return b.x > -20 and b.x < 700
end

--------------------------------------------------------------------------------
-- 定时器
--------------------------------------------------------------------------------
if not _scheduler then
    _scheduler = SL:Schedule(function(dt)
        _cdLeft = math.max(0, _cdLeft - dt)
        if _wallT > 0 then
            _wallT = _wallT - dt
            if _wallT <= 0 then
                ShowTip("镜墙化了——三秒的账它自己结完了")
            end
        end
        for i = #_bolts, 1, -1 do
            if not Bolt_Update(_bolts[i], dt) then
                table.remove(_bolts, i)
            end
        end
    end, 0.02)
end

SL:RegisterLUAEvent(LUA_EVENT_MONSTER_SHOOT, "MRW_Shoot", function(data)
    if data and data.fromX then
        table.insert(_bolts, { x = data.fromX, vx = -CONST.BOLT_SPEED, back = false })
    end
end)

SL:ScheduleOnce(function()
    ShowTip("技能已加载: 镜面 (调试按钮触发)")
end, 1.0)

return MirrorWall

下半场的反转写在 Bolt_Update 的三段判里:第一段查镜墙——弹道横坐标进了镜墙带、镜墙还在,反转;第二段查回程落点——回程弹扎中发射者,结算二十二;第三段查无墙时的玩家命中——墙不在的时候弹道才落回原路的账。三段判定的顺序就是优先级:镜墙在最前,反弹次之,原路最后。

五、调参指南与商业服怎么用

调参三笔账。镜墙三秒对怪两秒一射是"一到两发被反"的窗口——窗口太长怪的输出全变自伤,太短来不及反一发。回弹二十二对原弹二十二是一比一的诚实——回弹加倍的版本镜墙成了无敌盾,回弹减半它就不疼了。镜墙落在两座中点是地理的公平——贴着怪立等于贴脸盾,贴着自己立等于玩家专属。常见坑三个:弹道的反转没有把 方向标置真,同一发弹来回穿镜无限反弹;镜墙化掉的瞬间还有回程弹在飞,回程弹被提前清表;墙的纵高不够弹道从头顶飞过,拦了个寂寞。

商业服里镜面是"防御流派"的颜值顶配:镜墙的材质做成品级——水镜、冰镜、琉璃镜,弹道画回去的那一道白光就是流派的名片。比武场里它是弹道职业的照妖镜:远程的每一发都在教对手"打有镜面的人要先想清楚"。弹道职业的照妖镜:远程的每一发都在教对手"打有镜面的人要先想清楚"。镜墙的冷却六秒对墙寿三秒留三秒真空——真空里远程弹道恢复威胁,三秒的弹道反制就是这门机制的产出窗口。变体做成镜面蓄能:反射的弹道不消失而是存进镜面,三秒后全部一次性射回——攒弹的镜墙是防御转进攻的终极形态。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。

写完留一句给做反射系的同学:镜面卖的是"原样奉还"——不加不减不变形,它的弹道就是它的罪证,镜墙只是替天把弹道画了回去。

作者履历与出处

本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理。团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与商业版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。

← 返回文章地图返回研学路径

幂尔框架 · 实战干货 · 接口调用

LATEST ARTICLES

全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →

进阶实战游戏功能

影锁:影锁绑你绑它,锁期拼刀

【游戏功能】 控制技能的镜像问题是:锁住了怪,自己是不是也闲着?影锁把这道两难摆上台面:影锁四秒,它动不了、你也动不了——它…

2026-10-01 10:00 996 技术组
进阶实战游戏功能

震魂:震魂入体叠加出招自损

【游戏功能】 打断为什么只有"清读条"一种?震魂偏要反过来——不清招、不断势,打在它读条半途的那一劲顺着招震进腑——中劲十秒…

2026-10-01 10:00 996 技术组
进阶实战游戏功能

蜂王:喂小怪蜂王进化,三阶蜂王蜇翻全场

【游戏功能】 蜂群为什么总是一只一只出?蜂王偏要让它们进化:放一只蜂王出来,杀掉小怪喂它——喂三只升一阶,三阶蜂王的毒刺一秒…

2026-10-01 10:00 996 技术组
进阶实战游戏功能

血刃:每刀扣血换吸血,血刀双刃

【游戏功能】 技能为什么总是不扣自己的血?血刃偏要反着来:开着血刃的每一刀先扣自己二血、命中回三血——净赚一但要打得中,空刀…

2026-10-01 10:00 996 技术组
进阶实战游戏功能

破军旗:旗立三秒圈内加攻,旗倒攻散

【游戏功能】 bn.t = bn.t - dt ——一行旗面倒计时的代码,撑起了破军旗全部的紧迫感:旗立三秒、圈内加攻三成,…

2026-10-01 10:00 996 技术组
进阶实战游戏功能

淬毒刃:淬毒三刀叠一层,一层毒过一秒六

【游戏功能】 淬毒为什么要一毒到底?淬毒刃偏要一层一层叠:一刀淬一层毒、毒层一秒六地烂,六层封顶之后一刀下去毒伤三十六——叠…

2026-10-01 10:00 996 技术组