【游戏功能】
单行代码拆解:先看一行代码:箭头,往它那里挪一点——认踪矢的全部机关就这一行:箭每飞一拍,箭头的朝向往怪的方向挪一点,拐着弯也要追上。追击不需要瞄得准,需要的是每拍那一点点的转向。这篇把认踪矢纹整套写法拆开:认踪出矢、逐拍转向、咬中收矢、飞累坠地,一段一段照抄能跑。
一、效果演示
演示场的箭庐里射出一支翠羽矢。点「认踪!」:矢出鞘时朝着正前方——怪一露头,箭头拐着弯追过去,翠色的尾光在空中拖出一道弯。追上咬中二十四,收矢;要是绕了三秒还没追上,箭飞累了就地一坠。矢的弯拐得讲道理:转向的幅度每拍封了顶,弯得圆滑不神经。
flowchart TD
A[点认踪] --> B[矢出鞘 朝正前]
B --> C[每拍箭头挪一点]
C --> D{追上怪了吗}
D -- 追上 --> E[咬中二十四]
D -- 没追上 --> F{飞满三秒了吗}
F -- 没有 --> C
F -- 飞累了 --> G[坠地收矢]
E --> H[六秒后再射]
G --> H
二、底层原理
认踪矢的机关是"逐拍微转向"——箭不瞄着射,是飞起来以后每拍把朝向往怪的方向挪一点:挪的幅度每拍封顶,弯就拐得圆滑。追击的公平也在这封顶里:转向有速率上限,怪跑得够巧箭就一时追不上——追得上追不上是箭和怪的比赛,不是系统的判决。三秒的飞累坠地是追击的底:不设时限的追踪矢会绕着场追到天荒地老。
翠尾的拖光是箭的行迹:箭头走到哪,尾光拖到哪,弯拐得多急尾光就弯得多急——读尾光就是读箭的心思。咬中那一拍的收矢干脆:二十四点加一身翠屑,箭完成使命就地散架。幂尔框架这边转向收在每拍推进里,幅度封顶写在挪动的那一行,坠地收矢挂在三秒的时辰上,账面只有追与收两笔。
这套玩法的代码量不到八十行,难的不是追而是挪的那一点——转向不封顶的追踪矢,拐的是鬼手弯,追的是系统的判决。
再看认踪矢为什么飞三秒就坠而不追到天荒地老——三秒是箭的体力:体力尽了箭就是一根普通木棍,坠地是最诚实的收场。坠地还有一个隐性收益:它逼着玩家在箭出手的时机上用功——怪贴脸时射,一拍就咬中;怪远遁时射,箭追三秒坠一路。时机算计的深度,是拿箭的体力换来的。
三、核心代码:完整模块(上·骨架)
-- @file CrestHoming.lua
-- 认踪矢纹 —— 箭认准了影 拐着弯也要追上
local CrestHoming = {}
local CONST = {
ARROW_SPEED = 300,
TURN_RATE = 4,
HOMING_DMG = 24,
TIRED_TIME = 3,
ARROW_CD = 6,
AUTOINC_BASE = 1206300,
}
local _flying = false
local _x = 0
local _y = 0
local _ang = 0
local _t = 0
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 CrestHoming.Flying() return _flying end
-- 射矢: 出鞘朝正前
function CrestHoming.Shoot()
if _cd > 0 then
ShowTip("箭庐还在制矢——再等" .. math.ceil(_cd) .. "秒")
return
end
_cd = CONST.ARROW_CD
_flying = true
_x = 226
_y = 180
_ang = 0
_t = 0
ShowTip("认踪矢出——拐着弯也要追上")
end
四、核心代码:完整模块(下·推进与卸载)
-- 每拍推进: 逐拍微转向 追上收矢
if not _ticker then
_ticker = SL:Schedule(function(dt)
if _cd > 0 then _cd = _cd - dt end
if not _flying then return end
_t = _t + dt
if _t >= CONST.TIRED_TIME then
_flying = false
ShowTip("矢飞累了——坠地没咬着")
return
end
local dx = (SL:GetValue("mobX") or 0) - 8 - _x
local dy = (SL:GetValue("mobHeadY") or 0) - _y
local want = math.atan(dy, dx)
local diff = want - _ang
while diff > 3.14 do diff = diff - 6.28 end
while diff < -3.14 do diff = diff + 6.28 end
local step = math.max(-4 * dt, math.min(4 * dt, diff))
_ang = _ang + step
_x = _x + math.cos(_ang) * CONST.ARROW_SPEED * dt
_y = _y + math.sin(_ang) * CONST.ARROW_SPEED * dt
if math.sqrt(dx * dx + dy * dy) < 20 then
_flying = false
ShowTip("咬中" .. CONST.HOMING_DMG .. "!")
end
end, 0.02)
end
SL:ScheduleOnce(function()
SL:BindDebugButton("认踪!", function()
CrestHoming.Shoot()
end)
ShowTip("技能已加载: 认踪矢纹")
end, 1.0)
function CrestHoming.Unload()
if _ticker then SL:Unschedule(_ticker) end
_flying = false
end
return CrestHoming
五、机制问答
问:拐弯为什么拐得圆滑?
答:转向每拍封顶——挪的幅度有限,弯才拐得圆,鬼手弯是没封顶的产物。
问:追击的公平在哪?
答:转向有速率上限——怪跑得巧箭就一时追不上,追与逃是比赛不是判决。
问:三秒坠地图什么?
答:箭的体力——坠地是最诚实的收场,还逼着玩家在出手时机上用功。
问:翠尾的拖光图什么?
答:读箭的心思——弯拐得多急尾光就弯得多急,尾光是箭的心电图。
问:怪贴脸时射为什么最值?
答:一拍咬中——箭的体力全花在刀刃上,追击的弯都没机会拐。
六、调参与实战怎么用
参数层面三个量——飞速、转向速率、体力时限。三百的飞速配四弧度转向是"追得上又追得辛苦"的线:转向翻倍箭成雷达。实战里这套逐拍微转向的骨架能搬去魔导追击弹、回声蝠、认主飞剑,全是出鞘、微转向、体力坠地一条线。常见坑两个:转向不封顶拐鬼手弯;不设体力,箭绕场三圈追到天荒地老。
补充一个设计层面的思考——攻防的账要分"压头"和"压脚"两笔:砸头脸的招吃的是措手不及,扫下盘的招吃的是站稳与否,两笔账的躲法不同、赏法也不同。一套战斗里两类招都备着,玩家才会抬头看低头看两头兼顾——只教一种躲法的战斗,练到后来只剩一种反应。
补充一个维护层面的思考——带机括节奏的招(连发、歇息、回填)要把节奏写成状态而不是写成延时串:连发是一态、歇息是一态、第二轮是一态,态与态的切换写在推进口里。串延时的版本多跑两轮就对不上拍——状态机的账怎么翻都对,延时串的账翻两页就乱。
补充一个工程层面的思考——弹道和牵引类的运动体在目标消失时要"就地收势":刃坠地、鸢归天、箭坠土,各自的收势演完账就清。运动体没收势就复用,新的一发会继承旧的残影和旧的目标——收势是运动体的卸载口,卸载口不在,运动体就是幽灵。
补充一个到达层面的思考——这六式招式各有一套到达的写法:滚石贴地碾过去、纸鸢从天上扎下来、钟摆走弧线来回扫、认踪矢拐弯追、双蛟绞着麻花游、机括匣点射轮转。到达方式就是招式的身份:改伤害容易改到达难,到达一改就成了另一个招。调招先调到达的节奏,数值放到最后一步。
写完留一句给做追踪系的同学:玩家看的是翠尾也是那一点点的转向——每拍封顶,箭才拐得圆滑追得公平。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 隐蔽报错引入:一个很隐蔽的报错——机括匣的箭放完了还在放,匣里的箭明明只有六支,账面上却射出了第十七支:轮次的…
【游戏功能】 线上事故引入:早上水渠的双蛟出了怪相——两条蛟游着游着绞成了一股,分不出你我,双蛟的账记成了单蛟的翻倍。双蛟各…
【游戏功能】 单行代码拆解:先看一行代码: 箭头,往它那里挪一点 ——认踪矢的全部机关就这一行:箭每飞一拍,箭头的朝向往怪的…
【游戏功能】 先抛一个坑:大摆都荡完一个来回了,为什么还有人站在原地没挨刀?摆刃扫过的每一段都有它的账,站得对不对位子,决定…
【游戏功能】 隐蔽报错引入:一个很隐蔽的报错——纸鸢扎下来扎的是怪的脚后跟,明明瞄准的是头脸。鸢的俯坠路径读的是怪的脚下坐标…
【游戏功能】 线上事故引入:早上山道的滚石机关出了糗——石碾滚过去把怪顶退四十步,一步没刹住推出了战场地皮,半只身子挂在世界…