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

万相轮纹:一刀一相,灼缓弱轮着来

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

【游戏功能】

去年秋天的随机事故到现在还是教材:万相纹的初版把随机种子写死在模块顶部——种子固定,掷出的相就固定,一整场打下来只出"灼"一种相,玩家还以为纹就这一个效果。修复的办法是把种子的根扎进时间戳里,每一掷都是新的天意。这篇把整改后的整套模块拆开:配置表、掷相结算、三相通账、定时器、调试按钮,一段一段照抄能跑。

一、效果演示:一刀一相,灼缓弱轮着来

演示场点「万相!」:一圈紫色的纹绕上玩家——十二秒万相期。这一拍起你的每一刀都掷一相:掷出灼——橙字"相·灼"蹦出,怪身上两秒的灼烧滴滴答答;掷出缓——蓝字"相·缓"亮起,它的步子当场慢半截;掷出弱——紫字"相·弱"挂上,它的下一爪软了六点。三相亲转,谁也不保证下一刀是什么味。演示里试两笔账:万相期的账面和裸砍的账面——十二点的基础刀一样,多出来的是那些随机附赠的小相——小相不大,胜在笔笔都是白捡。万相纹教的是万相:每一刀都是一个盲盒,相相有戏,戏戏不同。

demo
 fx-myriadforms

二、底层原理:一次掷相结算加一本三相通账

模块的机关是一对搭档。掷相结算:纹成期里每一刀落账的同时掷一相——灼缓弱三扇轮盘,掷到哪扇哪扇的相挂在怪身上,相与相之间互不覆盖先来后到。通账:三相通账是相的寿命表——灼两秒烧完,缓两步走完,弱挨一爪用完,各自的账各自销。和固定附魔类机制的分野在"万相的相是天意不是配置":附魔是配好的固定词条,万相是每刀现掷的天意——你永远不知道下一刀是灼是缓是弱,掷的过程本身就是这套纹的戏,戏里还套着戏,套到后来玩家自己都会替下一刀猜相。

种子为什么必须扎进时间戳?固定种子的版本随机变循环,全场一个相——那场事故就是这么来的;时间戳做种,每一掷都是独立的天意,玩家的每一刀才有翻盘的盼头,才有一刀一个味的念想,念想就是万相纹的药。

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

lua
-- @file MyriadForms.lua
-- 万相轮纹 —— 一刀一相,灼缓弱轮着来

local MyriadForms = {}

local CONST = {
    CREST_LIFE    = 12.0,
    CREST_CD      = 4.0,
    BURN_TICK     = 2,
    BURN_LIFE     = 2.0,
    SLOW_LIFE     = 2.0,
    WEAK_LIFE     = 4.0,
    WEAK_CUT      = 6,
    BASE_HIT      = 12,

    COLOR_FORMS   = "#a878c8",
    COLOR_DEEP    = "#402858",
    COLOR_GHOST   = "#e0c8f0",

    ZORDER_FORMS  = 133,
    ZORDER_FX     = 135,
    AUTOINC_BASE  = 1128000,
}

local _crestT    = 0
local _cdLeft    = 0
local _crestFx   = nil
local _scheduler = nil
local _autoInc   = 0

local function GenID(prefix)
    _autoInc = _autoInc + 1
    return string.format("%s_%d", prefix or "MYF",
        CONST.AUTOINC_BASE + _autoInc)
end

local function GetActorPos(id)
    if not id then return nil end
    local x = SL:GetValue("ACTOR_POSITION_X", id)
    local y = SL:GetValue("ACTOR_POSITION_Y", 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 RollForm()
    local seed = math.floor(os.clock() * 1000)
    math.randomseed(seed)
    return math.random(1, 3)
end

四、核心代码:完整模块(下·三相通账与挂相)

lua
-- 挂相:掷出哪相挂哪相,各记各的账
local function ApplyForm(tid, form)
    if form == 1 then
        SL:AddBuff(tid, "SCORCH", CONST.BURN_LIFE)
        SL:TipAbove(tid, "相·灼")
    elseif form == 2 then
        SL:AddBuff(tid, "TARSlow", CONST.SLOW_LIFE)
        SL:TipAbove(tid, "相·缓")
    else
        SL:AddBuff(tid, "ENFEEBLE", CONST.WEAK_LIFE)
        SL:TipAbove(tid, "相·弱")
    end
end

-- 三相通账:灼烧跳账,缓弱到期自销
if not _scheduler then
    _scheduler = SL:Schedule(function(dt)
        _cdLeft = math.max(0, _cdLeft - dt)
        if _crestT > 0 then
            _crestT = _crestT - dt
            if _crestT <= 0 then
                SafeRemove(_crestFx)
                ShowTip("相收了——刀回平常")
            end
        end
    end, 0.02)
end

function MyriadForms.Cast()
    if _cdLeft > 0 or _crestT > 0 then return end
    local myID = SL:GetValue("USER_ID")
    _cdLeft = CONST.CREST_CD
    _crestT = CONST.CREST_LIFE
    SafeRemove(_crestFx)
    _crestFx = GUI:Layout_Create(GUI:Attach_SceneF(),
        GenID("Forms"), 0, 0, 0, 0, false)
    GUI:setLocalZOrder(_crestFx, CONST.ZORDER_FORMS)
    SL:PlayFormsUpFx(myID)
    ShowTip("万相开了——每一刀掷一相,灼缓弱轮着来")
end

-- 出手掷相:每一刀落账即掷
SL:RegisterLUAEvent(LUA_EVENT_MELEE_HIT, "MYF_Roll", function(tid)
    if _crestT <= 0 or not tid then return 0 end
    ApplyForm(tid, RollForm())
    return 0
end)

SL:ScheduleOnce(function()
    SL:BindDebugButton("万相", function()
        MyriadForms.Cast()
    end)
    ShowTip("技能已加载: 万相纹 (调试按钮触发)")
end, 1.0)

function MyriadForms.Unload()
    if _scheduler then SL:Unschedule(_scheduler) end
    SL:UnregisterLUAEvent(LUA_EVENT_MELEE_HIT, "MYF_Roll")
    SafeRemove(_crestFx)
    _crestT = 0
end

return MyriadForms

五、机制问答

问:三相能同时挂在怪身上吗?
答:能——三扇轮盘各记各的账,灼缓弱一起挂的怪又慢又弱还冒烟,相相不冲突。

问:连掷两刀同一相会叠加吗?
答:同相刷新不叠加——第二刀掷出灼,灼的账从头再走,不会烧成双层。

问:掷相的种子为什么不能写死?
答:写死的种子掷出的是死循环——那场"全场只会灼"的事故就是种子定了命,天意得每掷都新。

问:万相的相吃暴击吗?
答:相不是刀——十二点的刀身照常掷暴击,相是搭售的赠品,赠品不参与暴击的账。

问:相的挂机能被驱散吗?
答:能——相走的是标准的加持通道,怪身上的净化照样扫得掉,扫掉哪相哪相的账作废。

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

第四笔是种子的根:时间戳做种是那场事故的整改核心——种子写死,随机变剧本,这一行是整套纹的天条。第三笔是三相的均衡:灼缓弱各占一扇是相的均势——一相独大的掷盘让另外两相成摆设,均势的三相才逼着玩家临场应变。第二笔是各相的寿命:灼两秒、缓两步、弱一爪是相的保质期——寿命太长相变常驻,太短掷了白掷,各走各的销账节奏才叫万相。第一笔是相的配色:灼橙缓蓝弱紫,一相一色一一对应——玩家看颜色就知道怪身上挂着什么账,配色乱了万相就成了一锅粥。常见坑三个:种子写死的随机事故原型;三相同时挂的小字挤成一行看不清;缓相的减速在怪死亡后没解除带着尸体慢半拍。

商业服里万相纹是"百戏班"的彩头:别人的附魔是配好的,他的附魔是现掷的——商城里相的样式做成品级,粗陶相、珐琅相、琉璃相,那三个轮着蹦的彩色小字就是百戏班的戏码。运营落地还有两笔:一段是认相教学——教一句"掷出什么用什么,灼缓弱都是白捡",流派第一课是随缘;一段是万相榜——按一窗之内三相凑齐的总次数排名,相相都沾的人有碑。变体做成四相:加一扇"震"字相,掷中震一下小眩晕——从三扇轮盘到四扇,百戏班的戏码越翻越多。这一篇的演示和整套模块照抄能跑,改的就是 CONST 那张表。

写完留一句给做随机系的同学:万相纹卖的是"每一刀都是新天意"——那三个轮着蹦的彩色相字和谁也猜不透的下一刀,是把附魔从配菜单改成掷骰盅的一台轮盘。

作者履历与出处

本文由 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 技术组