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

缩地阵:圈越缩越小,逼它和你贴身

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

【游戏功能】

远近战的矛盾怎么解?远战的答案是把怪挡在射程外,近战的答案是把人拖进射程内——缩地阵给的第三个答案最蛮横:圈只锁怪不锁你,圈从一百五十步缩到四十步,它出不了边、你随便进出,缩到头就是贴身肉搏——它的腿和你的刀,被同一个圈赶进了同一个身位,谁也退不出去。缩到头就是贴身肉搏——它的腿和你的刀,被同一个圈赶进了同一个身位,谁也退不出去。圈心的落点也有讲究:落在两者中点,圈缩到头正好是半途相逢;落在怪的身后,圈缩的每一寸,都在把它往你怀里推。这篇的核心代码照引擎技能脚本的全规格写:配置表、缩圈构件、挤压弹回、定时器、调试按钮。

一、效果演示:一圈缩到底,逼出一场贴身

演示场点「缩地阵!」:一圈金色的符纹把玩家和怪一起罩进去,圈沿的虚线开始一圈一圈往里收——一百五、一百二、九十……怪在圈里往外冲,撞上圈沿被挤回来,头顶蹦出"被挤"的小字;怪在圈里往外冲,撞上圈沿被挤回来,头顶蹦出"被挤"的小字——挤的力度刚好把它的脚按在圈沿内侧,一次都不放行;你往圈里一站,普攻当场加三成——十二变十五,金色的刀光。圈缩到四十步的时候,你和你之间只剩一个身位,贴身肉搏不可避免。演示里故意站着不动看圈收完,再看一次边收边打——两种收法,怪的血线差出一大截。

demo
 fx-shrinkfield

二、底层原理:一条收缩曲线加一份单向弹回

模块的机关是一对不对等的规则。收缩侧:圈的半径是时间的线性函数——一百五十步匀速缩到四十步、十秒收完,半径每帧重算、圈沿每帧重画。弹回侧:只对怪生效——怪的横坐标离阵心超过当前半径,立刻按回圈沿,头顶"被挤";玩家的横坐标不受任何约束,进出自由。单向是全套机制的灵魂:同一个圈对两边两套规则,玩家享受圈内加成和进出自由,怪承担强制向心和出界弹回——不对等就是缩地阵的全部威力。圈内加成是第三条规则:玩家在圈内时攻击乘一点三,缩圈的过程就是把战斗往"你的主场"里赶。

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

lua
--------------------------------------------------------------------------------
-- @file        ShrinkField.lua
-- @brief       缩地阵 —— 圈越缩越小,逼它和你贴身
--              客户端表现模块:配置表 / 缩圈构件 / 单向弹回 / 定时器
--------------------------------------------------------------------------------

local ShrinkField = {}

--------------------------------------------------------------------------------
-- 配置与常量
--------------------------------------------------------------------------------
local CONST = {
    FIELD_LIFE    = 10.0,       -- 阵开十秒
    FIELD_CD      = 12.0,       -- 冷却十二秒
    RADIUS_START  = 150,        -- 起始一百五
    RADIUS_END    = 40,         -- 缩到四十
    IN_AMP        = 1.3,        -- 圈内加三成

    -- 颜色
    COLOR_FIELD   = "#d4b06a",  -- 缩地金
    COLOR_DEEP    = "#6b5a2b",  -- 深褐
    COLOR_GHOST   = "#efe0b8",  -- 阵白

    ZORDER_GROUND = 118,
    ZORDER_FIELD  = 128,
    ZORDER_EFFECT = 135,

    AUTOINC_BASE  = 938000,
}

--------------------------------------------------------------------------------
-- 模块内部状态
--------------------------------------------------------------------------------
local _fieldT    = 0              -- 阵的余时
local _fieldX    = 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 "SHF", 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 CreateFieldNode(x, y)
    local node = GUI:Layout_Create(GUI:Attach_SceneF(), GenID("Fld"), x, y - 20, 0, 0, false)
    GUI:setLocalZOrder(node, CONST.ZORDER_FIELD)
    for i = 1, 48 do
        local a1 = (i - 1) / 48 * 6.28
        local a2 = i / 48 * 6.28
        GUI:DrawLine_Create(node, string.format("c_%d", i), 0, 0, 2.5,
            m_cos(a1) * CONST.RADIUS_START, m_sin(a1) * CONST.RADIUS_START * 0.36,
            m_cos(a2) * CONST.RADIUS_START, m_sin(a2) * CONST.RADIUS_START * 0.36,
            CONST.COLOR_FIELD, 200)
    end
    return node
end

骨架的三处立规。圈的纵轴用零点三六压扁——贴地的阵才是阵,正圆的阵浮空像护罩。RADIUS_START 与 RADIUS_END 两个常量把收缩区间钉死——收缩曲线是两者之间的线性插值,改区间不改节奏。改区间不改节奏,节奏是十秒的钟摆。阵心取落阵时两者的中点——阵心钉在地点,玩家挪步圈不跟,地理的公平就在这一行。

四、核心代码:完整模块(下·定时器与单向弹回)

lua
--------------------------------------------------------------------------------
-- 半径曲线与圈内判定
--------------------------------------------------------------------------------
local function CurRadius()
    local k = math.min(1, _fieldT / CONST.FIELD_LIFE)
    return CONST.RADIUS_END + (CONST.RADIUS_START - CONST.RADIUS_END) * k
end

local function PlayerInField()
    if _fieldT <= 0 then return false end
    local mp = GetActorPos(SL:GetValue("USER_ID"))
    return mp and math.abs(mp.x - _fieldX) <= CurRadius()
end

--------------------------------------------------------------------------------
-- 画阵
--------------------------------------------------------------------------------
function ShrinkField.Cast()
    if _cdLeft > 0 or _fieldT > 0 then return end
    _cdLeft = CONST.FIELD_CD
    _fieldT = CONST.FIELD_LIFE
    local mp = GetActorPos(SL:GetValue("USER_ID"))
    local tp = GetActorPos(SL:GetValue("MARK_TARGET_ID"))
    _fieldX = mp and tp and (mp.x + tp.x) / 2 or (mp and mp.x or 0)
    CreateFieldNode(_fieldX, 0)
    ShowTip("阵开了——圈只缩不休,进圈加三成")
end

--------------------------------------------------------------------------------
-- 定时器:收缩、挤压与加成
--------------------------------------------------------------------------------
if not _scheduler then
    _scheduler = SL:Schedule(function(dt)
        _cdLeft = math.max(0, _cdLeft - dt)
        if _fieldT > 0 then
            _fieldT = _fieldT - dt
            if _fieldT <= 0 then
                ShowTip("阵收完了——它和你贴了个满怀")
                return
            end
            local r = CurRadius()
            local tid = SL:GetValue("MARK_TARGET_ID")
            local tp = tid and GetActorPos(tid)
            if tp then
                local d = math.abs(tp.x - _fieldX)
                if d > r - 24 then
                    local dir = tp.x > _fieldX and -1 or 1
                    SL:PushActor(tid, dir * (d - (r - 24)))
                    SL:TipAbove(tid, "被挤")
                end
            end
        end
        SL:SetNextAttackAmp(PlayerInField() and CONST.IN_AMP or 1.0)
    end, 0.02)
end

SL:RegisterLUAEvent(LUA_EVENT_SCENE_CLEAR, "SHF_Clear", function()
    _fieldT = 0
    SL:SetNextAttackAmp(1.0)
end)

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

return ShrinkField

下半场的两处要害。挤压的推距是"超出多少推多少"——d - (r - 24) 算出差额定向推回,怪的脚永远贴着圈沿内侧,推多推少都精确;玩家的加成每帧重查一次圈内判定、直接写进下一刀的系数——走出圈的瞬间加成即断,进出自由四 个字才立得住。阵收完的收尾把加成一起清——阵散加成还在的版本,贴身肉搏就成了永久外挂。阵散加成还在的版本,贴身肉搏就成了永久外挂。挤压的提示"被挤"别连成串——怪贴着圈沿跑动会每帧触发,提示加个半拍的冷却,眼睛才不吵。

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

调参三笔账。收缩十秒对一百五十到四十的区间是每秒十一步的收缩速度——速度低于八步,怪有充足时间绕到玩家背后拖时间;高于十四步,圈收完前战斗根本没展开。圈内加成三成是"进圈的诱惑"——低于两成玩家懒得进圈,高于四成圈外的远程怪反而成了白给的靶子。挤压保留二十四步的身位——这个余量是"贴身"而不是"重叠",零距离的挤压会把怪的模型挤进玩家的模型里穿帮。常见坑三个:玩家出圈后加成没断,下一刀还是乘一点三;怪被挤在圈沿时攻击判定失效,白挨打不还手;阵散时圈的视觉先没、挤压后散,两帧的错位就是投诉。

商业服里缩地阵是"近战复兴"的旗帜:近战职业带阵进组,远程的走位优势被一圈收走,组队市场上近战的身价第一次抬头。攻城战里它是巷战的发令枪——缩地阵推进到哪,哪条街就是绞肉机。变体做成双向缩:圈的加成随半径衰减——圈越大加成越低、缩到最小加成翻倍,耐心成了新的操作维度。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。

写完留一句给做领域系的同学:不对等是这个阵的全部性格——同一道圈沿,它撞上是墙,你穿过是门。

作者履历与出处

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

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

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

LATEST ARTICLES

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

进阶实战游戏功能

迷魂香:一炉香点着,圈里的怪掉头打转

【游戏功能】 怪的仇恨为什么永远追着你?因为它看得见你。迷魂香把"看得见"这三个字没收了:一炉香落在它脚下,烟圈六秒——圈里…

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

气势:连击涨势 挨打掉势 提气回血五十

【游戏功能】 连击值攒着有什么用?多数战斗的答案是攒个伤害加成——气势给了第二个答案:攒的是一支军队的士气。每一刀涨十二点、…

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

崩血:伤口一动就崩,跑得越快掉血越凶

【游戏功能】 一道割裂挂上去,一秒一跳——它站着跳四,追你的时候崩成八:伤口一动就崩,跑得越快掉得越凶。崩血把"放风筝"从走…

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

燕回式:突进穿它一遭,原路飞回起手点

【游戏功能】 突进出去了,回不回得来?多数突进的答案是"不回"——人留在怪堆里听天由命。燕回式给突进装了归途:穿身而过去时一…

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

破招式:它抡重刀你抢半拍,招克招

【游戏功能】 读条变红的那一秒,全世界都在等一个决定。破招式把这一秒做成整场战斗的心跳:怪交替出红劈和蓝刺,红劈读条时按下破…

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

连招谱:三招按谱出,谱尾一击翻倍

【游戏功能】 出招的顺序算不算伤害?大多数战斗里不算——三招乱按和按谱出,账面一个样。连招谱把顺序变成了伤害本身:「劈→撩→…

2026-10-01 06:32 996 技术组