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

Lua引力球:丢出去把怪吸过来

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

【语法算法】

先抛一个坑:怎么把散在四处的怪聚到一起打?逐个拉是笨办法,一个范围技又只能打一片——引力球的答案是一个会动的吸力源:丢出去之后原地发光,周围的怪自己被拉过来。这篇把引力球整套写法拆开:配置表、球体创建、吸力推进、消散判定、定时器、调试按钮,一段一段照抄能跑。

一、效果演示:丢出去把怪吸过来

演示场三只怪散在右侧。点「丢球!」:一颗青蓝色的球落在场中央——外围一圈引力波纹一鼓一鼓的。三只怪同时朝球的方向挪——吸力按距离衰减,离球越近拉得越快。三秒后球消散,怪停在球周围——聚成一坨等着挨打。演示里试两笔账:被吸到球边的三只怪和你追着三只打的输出效率——聚了打是一发范围技的事,散着打是三发单体的事。引力球教的是聚拢:不追怪,让怪来。

mermaid
flowchart TD
A[丢球落地] --> B[球体激活 计时开始]
B --> C[逐拍扫周围的怪]
C --> D{怪在吸力范围内}
D -- 是 --> E[朝球方向推进]
D -- 否 --> F[不受力 原地不动]
E --> G{计时归零}
F --> G
G -- 是 --> H[球消散 怪停]
demo
 fx-gravityball

二、底层原理:一次球体激活加一次吸力推进

模块的机关是一对搭档。球体激活:丢球的那一拍在指定坐标生成一颗发光的球——球是吸力源,三秒的寿命就是吸力的持续期。吸力推进:每一拍扫描周围的怪,按距离差的方向推——推力不衰减不递增,匀速拉近。和拉拽类机制的分野在"引力球是区域吸不是单体拉":铁链拉一只,引力球吸一圈——吸力源放在怪堆里,效果翻倍。

引力球为什么用匀速拉不用力衰减?匀速拉的距离和速度线性挂钩,玩家能预估"还有几秒聚齐";力衰减的版本远处拉得快近处拉得慢,怪会在球边嗡嗡震——匀速的账好算,好算的账玩家才信。

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

lua
-- @file GravityBall.lua
-- 引力球 —— 丢出去把怪吸过来

local GravityBall = {}

local 参数配置 = {
    BALL_LIFE     = 3.0,
    PULL_RANGE    = 200,
    PULL_SPEED    = 80,
    BALL_RADIUS   = 18,

    AUTOINC_BASE  = 1168000,
}

local _ballOn    = false
local _ballT     = 0
local _ballX     = 0
local _ballY     = 0
local _scheduler = nil
local _autoInc   = 0

local function GenID(prefix)
    _autoInc = _autoInc + 1
    return string.format("%s_%d", prefix or "GRB",
        参数配置.AUTOINC_BASE + _autoInc)
end

local function ShowTip(msg)
    if msg and msg ~= "" then SL:ShowSystemTips(msg) end
end

function GravityBall.Active()
    return _ballOn
end

四、核心代码:完整模块(下·吸力推进与消散)

lua
-- 吸力推进:球活着的每一拍推周围的怪
if not _scheduler then
    _scheduler = SL:Schedule(function(dt)
        if not _ballOn then return end
        _ballT = _ballT - dt
        local mobs = SL:EnumMobsInRange(_ballX, _ballY,
            参数配置.PULL_RANGE)
        for _, mob in ipairs(mobs) do
            local mp = SL:GetPosition(mob)
            if mp then
                local dx = _ballX - mp.x
                local dy = _ballY - mp.y
                local d = math.sqrt(dx * dx + dy * dy)
                if d > 25 then
                    SL:SetPosition(mob,
                        mp.x + dx / d * 参数配置.PULL_SPEED * dt,
                        mp.y + dy / d * 参数配置.PULL_SPEED * dt)
                end
            end
        end
        if _ballT <= 0 then
            _ballOn = false
            ShowTip("引力球散了——怪停在原地")
        end
    end, 0.02)
end

function GravityBall.Cast(x, y)
    if _ballOn then return end
    _ballOn = true
    _ballT = 参数配置.BALL_LIFE
    _ballX = x
    _ballY = y
    SL:PlayBallUpFx(x, y)
    ShowTip("引力球丢出去了——周围的怪被吸过来")
end

SL:ScheduleOnce(function()
    SL:BindDebugButton("丢球", function()
        GravityBall.Cast(330, 150)
    end)
    ShowTip("技能已加载: 引力球 (调试按钮触发)")
end, 1.0)

function GravityBall.卸载()
    if _scheduler then SL:Unschedule(_scheduler) end
    _ballOn = false
end

return GravityBall

五、机制问答

问:怪走到球边会停吗?
答:会——距离小于二十五就不推,怪贴着球站着不动,留给玩家一刀清的窗口。

问:引力球能把怪推出屏外吗?
答:不会——吸力朝球心推,怪只会越来越靠近球,不会跑偏。

问:多只怪互相挤在一起怎么办?
答:不管——怪和怪之间的碰撞不在引力球的管辖范围,挤就挤,挤成一坨更好打。

问:引力球能和减速叠加吗?
答:能——球管拉人减速管慢人,叠了之后怪被慢慢拖过来,手法是双控的入门课。

问:球消失后怪会自己走开吗?
答:不会——球散了吸力没了怪就停在原地,走不走看怪的自己,跟球没关系。

六、调参与实战怎么用

第四笔是吸力的推速:八十步每秒是"看得出在走但不至于瞬移"的速度——推速太快怪像被传送,太慢像在散步。第三笔是球的半径:十八步的球径是"看得见但不遮怪"的尺寸——球太大遮住怪影响瞄准,太小没存在感。第二笔是范围的宽度:两百步是"一屏之内"的口径——范围太大全屏的怪都往一处跑,太小只吸得着近处的一只。第一笔是寿命的秒数:三秒是"够聚一波"的窗口——寿命太短怪还没聚齐球就散了,太长怪聚齐了球还赖着。常见坑三个:吸力没做距离归一导致远处怪拉得更快;球消散后引力波纹没消失;怪的朝向在推进中没有更新。

实战里引力球是"聚怪类"玩法的通用答案:引力球、聚怪阵、吸力井,全是"球体加吸力"的同一副骨架。组里的约定是:凡是"让怪聚到一起"的需求一律先试引力球——聚了打是一发范围技的事,散着打是三发单体的事。这篇的模块照抄能跑,改的就是参数表。

写完留一句给做聚怪系的同学:引力球卖的是"怪来打你"——那颗一鼓一鼓的蓝球和被慢慢拖过来的三只怪,是把追着打变成等着打的一颗引力源。

补充说明:这套写法在热重载环境里有一个额外的优势——模块的 参数表可以在运行时动态修改,修改后的参数立即生效,不需要重启游戏。这意味着调试的过程变成了实时的:改一个数值,立刻看到效果,不满意再改回来。这种即时反馈的调试方式比传统的"改代码→重启→测试→再改"快了不止一个量级,也是热重载环境给机制调试带来的最大红利。写机制的时候养成"参数全放 参数表"的习惯,热重载的便利就自动到位了。

另一个容易忽略的细节是清理的时机。卸载 是模块卸载时被调用的清理口——所有的定时器、事件监听、节点引用都要在这里一揽子清干净。漏了定时器的版本模块卸载后还在跑,漏了事件监听的版本重复挂载时重复触发,漏了节点引用的版本怪死后引用悬空。这三个坑每一个都出过事故,卸载 写全了才能说这个模块是安全的。

作者履历与出处

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

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

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

LATEST ARTICLES

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

进阶实战游戏功能

Lua自动炮台:架一个自动索敌开火

【语法算法】 上一版的炮台索敌逻辑有个隐蔽报错:炮台永远打同一个怪——即使那只怪已经死了,索敌的游标也不挪窝。追到底索敌的游…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua元素转换:火伤转冰伤附带减速

【语法算法】 先抛一个坑:打不完的火系怪怎么办?火抗怪火打不动,换冰系技能要切装备要换面板——切完黄花菜都凉了。元素转换的答…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua连锁引燃:一个着火引燃下一个

【语法算法】 上个月的事故复盘会上有个数字被念了三遍:四成——策划写的是"同伴陪疼四成",代码落下去成了"陪疼四十点",两只…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua弹射地垫:踩上去弹飞到空中

【语法算法】 单行代码拆解:弹射初速=-420——弹射的全部动力就这一行的负初速。负号朝上、四百二十是弹射的初速大小——踩上…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua时间减缓:流速减半的局部时差

【语法算法】 上一版的减速类模块全按"乘以零点五"来写,帧率无关的版本照搬了这套写法——结果高帧率机上减速效果好,低帧率机上…

2026-10-02 04:50 996 技术组
进阶实战游戏功能

Lua引力球:丢出去把怪吸过来

【语法算法】 先抛一个坑:怎么把散在四处的怪聚到一起打?逐个拉是笨办法,一个范围技又只能打一片——引力球的答案是一个会动的吸…

2026-10-02 04:50 996 技术组