【游戏功能】
单行代码拆解:先看一行代码:三道扇骨,各走一路——扇骨剑纹的全部章法就在这一行:一道剑气是直线,三道剑气按上中下错开角度齐出,就是一面扇。扇面铺开多大、剑骨走多偏,全是角度的账。这篇把扇骨剑纹整套写法拆开:出鞘扇骨、三路齐发、近身全吃、走空认赔,一段一段照抄能跑。
一、效果演示
演示场的剑冢里插着历代残剑。点「出鞘!」:三道月牙剑气从鞘口扇面般展开——上路、中路、下路各一道,一路一道地朝怪滚过去。怪站得近,三道全吃三十点;站得远只吃得着中路那道,上下两路擦身而过。五秒一出鞘,贴脸放扇还是远远放剑,扇面的账自己算。
flowchart TD
A[点出鞘] --> B[三道扇骨齐发]
B --> C[上路剑气]
B --> D[中路剑气]
B --> E[下路剑气]
C --> F{怪接得住吗}
D --> F
E --> F
F -- 贴脸 --> G[三道全吃 三十]
F -- 离得远 --> H[只中一道 十]
G --> I[五秒后再出鞘]
H --> I
fx-crest-fan
二、底层原理
扇骨系统的机关是"一道变一面"——单发剑气只有命中与落空两种结局,三道错角齐出的剑气把结算变成几何题:怪接得住几道,取决于它站的远近和你的出鞘时机。贴脸全吃的三十是扇的满赏,远远只中一路的十是扇的保底——同一招两种价,距离就是定价器。
扇骨的错角是章法所在:上中下三路各偏零点四二弧度,扇面铺得开又不散——错角再大就漏怪,再小就挤成一道。三道剑气各自独立结算:中路先到先结,上下两路随后各走各的账,谁命中谁落账,一板一眼。月牙形的剑气画法给了扇"骨"的形态:弧背朝外、弧口朝人,滚过去的时候像三弯月牙在追。幂尔框架这边扇骨收在出鞘口子里一次生成三道,各自带着角度和寿命自己飞,命中口只认触到的剑气。
这套玩法的代码量不到八十行,难的不是发三道而是错角的章法——扇面铺开又不散,角度的账就立住了。
再看全吃的赏为什么给在贴脸而不给在远距——扇形剑气天然是近战的延伸:贴脸放扇要顶着怪的爪子出手,风险换满赏合情合理;远距放扇本就安全,只给保底不亏不欠。距离定价的账在一切扇形、锥形、放射类招式里通用:越险的位置赏越满,扇子才不会变成无脑远刷的洗地招。
三、核心代码:完整模块(上·骨架)
-- @file CrestFan.lua
-- 扇骨剑纹 —— 三道扇骨齐出 贴脸全吃
local CrestFan = {}
local CONST = {
BONES = 3,
SPREAD = 0.42,
WAVE_LIFE = 0.7,
WAVE_REACH = 320,
WAVE_DMG = 10,
FAN_CD = 5,
AUTOINC_BASE = 1204100,
}
local _waves = {}
local _cd = 0
local _autoInc = 0
local function ShowTip(msg)
if msg and msg ~= "" then SL:ShowSystemTips(msg) end
end
local function GenID()
_autoInc = _autoInc + 1
return CONST.AUTOINC_BASE + _autoInc
end
function CrestFan.Waves() return #_waves end
-- 出鞘: 三道扇骨各带角度
function CrestFan.Unsheath()
if _cd > 0 then
ShowTip("剑气还没凝——再等" .. math.ceil(_cd) .. "秒")
return
end
_cd = CONST.FAN_CD
for i = 1, CONST.BONES do
_waves[#_waves + 1] = {
t = 0,
ang = (i - 2) * CONST.SPREAD,
hit = false,
}
end
ShowTip("出鞘!三道扇骨——上中下各一道")
end
四、核心代码:完整模块(下·推进与卸载)
-- 每拍推进: 各飞各的 各结各的账
if not _ticker then
_ticker = SL:Schedule(function(dt)
if _cd > 0 then _cd = _cd - dt end
for i = #_waves, 1, -1 do
local w = _waves[i]
w.t = w.t + dt
local dist = w.t / CONST.WAVE_LIFE * CONST.WAVE_REACH
if not w.hit and dist >= SL:GetValue("mobDist") then
w.hit = true
ShowTip("扇骨命中——" .. CONST.WAVE_DMG)
end
if w.t >= CONST.WAVE_LIFE then
table.remove(_waves, i)
end
end
end, 0.02)
end
SL:ScheduleOnce(function()
SL:BindDebugButton("出鞘!", function()
CrestFan.Unsheath()
end)
ShowTip("技能已加载: 扇骨剑纹")
end, 1.0)
function CrestFan.Unload()
if _ticker then SL:Unschedule(_ticker) end
_waves = {}
end
return CrestFan
五、机制问答
问:一道剑气和一面扇差在哪?
答:差在错角——三道错角齐出,结算从命中落空变成一道几何题。
问:错角的零点四二怎么定的?
答:铺得开又不散——再大漏怪再小挤成一道,扇骨的章法就在这个分寸。
问:三道为什么各自独立结账?
答:谁命中谁落账——中路先到先结,上下随后,一板一眼不混账。
问:全吃的赏为什么给在贴脸?
答:距离定价——贴脸顶爪出手风险换满赏,远距安全只配保底。
问:月牙的画法图什么?
答:扇骨的形态——弧背朝外弧口朝人,三弯月牙追着滚才有剑气的样子。
问:三道剑气能拐弯吗?
答:不能——扇骨各走各的直路,拐弯的剑气是另一门功课,扇子的章法在直。
六、调参与实战怎么用
参数层面三个量——扇骨数、错角、飞行寿命。三骨是扇的标准骨:两骨成箭五骨成帘。剑气的寿命和射程要一起定:七分寿命飞三百二十步,寿命到头剑气就地散掉,别让它飞出画面还结账。实战里这道几何题的骨架能搬去散弹扇、飞牌轮、暗器幕,全是错角、齐发、距离定价一条线。常见坑两个:错角失衡扇面漏怪或挤成一道;远近距离一个价,扇子沦为洗地招。
补充一个设计层面的思考——出招的动作语言要和招的性质说一回事:绳就该有绳的弧线、壶就该有壶的抛物线、浪就该有浪的推进,玩家看动作就能猜到招怎么算。动作和数值两张皮是最伤的——看着是重锤结果是挠痒,看着是轻挑结果瞬杀,玩家对出招的信任就这么散的。
补充一个维护层面的思考——动作进行中的状态(飞行中的壶、钻地的一半、索飞的半程)要在换怪和重开时收干净:飞到一半的壶落地不落账、钻到一半的人卡在土里,都是阶段切换没扫尾。每一类飞行物配一句"到点没对象就作废"的清理,换多少次场都不留悬案。
补充一个工程层面的思考——位移类的演出要让位移的起点和终点都有交代:从哪起、到哪落、落地站哪,三问各有答案再动手。位移是所有演出里最容易穿模穿边界的,起落说不清的位移宁可拆成两段演,也别让人物在两帧之间瞬移到图外面去。
写完留一句给做扇形系的同学:玩家算的是角度也是身位——错角铺扇、贴脸全吃,一面扇子打出了几何的章法。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
接手二开的兄弟几乎都撞过同一堵墙:玩家嫌走路"一格一格像机器人",老板拍板要"丝滑移动",改服务端速度?不对。改客户端动画帧…
【游戏功能】 先看一个熟场面:法师的火球特效挂在怪的脚后跟上,明明技能说明写着"焚烧其面",火星子却在地上打滚。群里有位策划…
【游戏功能】 上周有个开服的老板在群里发了一段录屏:他的战士明明刀刀都砍中了,观众却一片"这刀挥空了吧"。他原话是"判定日志…
【游戏功能】 先说结论放在开头:怪的皮一会儿绿一会儿红,不是美术换了几套贴图,是染色系统在怪身上盖了一层"色镜"。开服群里有…
前两天群里有个架设的朋友问了个需求:中毒的人要变绿、每两秒掉一次血、毒还能叠五层,问是不是要在服务端把整套状态机重写。我说你…
【游戏功能】 先抛一个坑:五口钟一模一样大,为什么一口比一口疼?先后次序动不得吗?倒过来敲会怎样?这篇把编钟纹整套写法拆开:…