【游戏功能】
线上事故引入:早上山道的滚石机关出了糗——石碾滚过去把怪顶退四十步,一步没刹住推出了战场地皮,半只身子挂在世界边上。滚石的位移账没有封顶,顶退成了顶飞。这篇把滚石压纹整套写法重写成篇:坡顶放碾、碾过头身、顶退封顶、七秒一滚,一段一段照抄能跑。
一、效果演示
演示场的斜坡道口。点「滚石!」:一座石碾从坡上轰隆滚下——碾轮转着、石纹跟着转,碾过怪的头身二十四点,还把它顶退四十步、误它半拍出爪。顶退有封顶,推到线上就止,怪停在退后的位子上喘。七秒一滚,滚的节奏自己挑——挑它刚进射程的那一滚最值。
flowchart TD
A[点滚石] --> B[石碾下坡]
B --> C{碾过怪身了吗}
C -- 没有 --> C
C -- 碾过 --> D[二十四入账]
D --> E[顶退四十步]
E --> F{推出地皮了吗}
F -- 封顶止步 --> G[碾过 七秒再滚]
F -- 还有余地 --> G
二、底层原理
滚石的机关是"滚动带顶退"——石碾的转角跟着位移走,碾过怪身那一拍结二十四,顺势把怪顶退四十步、出爪慢半拍。那场推出地皮的糗事就是顶退没封顶:位移账只加不减,推到世界边上还没停。正解是顶退的落点卡一条线——线内随意退,线到即止,怪的身体永远留在地皮里。碾压的判定跟着碾轮的横坐标走:碾到身位那一拍结账,碾过去就不再重复。
碾轮的滚动是这条招的性格:轮转的石纹、坡道上的颠簸、碾过之后的浮尘——三样齐了,石碾才有重量。顶退的四十步给了玩家"隔山打"的余味:把怪顶远了,走回来的几拍是白送的输出窗。幂尔框架这边放碾收在口令的口子上,顶退的封顶写在位移的下一行,账面只有滚与止两个动作。
这套玩法的代码量不到八十行,难的不是滚而是封顶——没有封顶的顶退,推的是整个世界。
再看碾压为什么限定碾一次而不是碾着怪走全程——碾轮比怪快,接触只有一拍:一拍一账,干净利落。要是做成碾着持续结算,石碾就成了移动的磨盘,怪被推着碾完整条道,账面好看观感灾难。持续与一次的取舍看速度差:碾轮快过怪,就只结相遇那一拍。
三、核心代码:完整模块(上·骨架)
-- @file CrestRollstone.lua
-- 滚石压纹 —— 石碾子滚过去 压头不压脚
local CrestRollstone = {}
local CONST = {
SPEED = 330,
ROLL_DMG = 24,
PUSH_DIST = 40,
PUSH_LINE = 720,
STUN_TIME = 0.8,
ROLL_CD = 7,
AUTOINC_BASE = 1206000,
}
local _rolling = false
local _x = 0
local _hit = false
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 CrestRollstone.Rolling() return _rolling end
-- 放碾: 从坡顶出发
function CrestRollstone.Release()
if _cd > 0 then
ShowTip("坡上没石头了——再等" .. math.ceil(_cd) .. "秒")
return
end
_cd = CONST.ROLL_CD
_rolling = true
_x = -40
_hit = false
ShowTip("石碾下坡——低头看路,抬头看它")
end
四、核心代码:完整模块(下·推进与卸载)
-- 每拍推进: 碾身结账 顶退封顶
if not _ticker then
_ticker = SL:Schedule(function(dt)
if _cd > 0 then _cd = _cd - dt end
if not _rolling then return end
_x = _x + CONST.SPEED * dt
if not _hit
and math.abs((SL:GetValue("mobX") or 0) - _x) < 30 then
_hit = true
ShowTip("碾过头身——" .. CONST.ROLL_DMG)
SL:SetValue("mobPush", CONST.PUSH_DIST)
SL:SetValue("mobDelay", CONST.STUN_TIME)
end
if _x > 800 then _rolling = false end
end, 0.02)
end
SL:ScheduleOnce(function()
SL:BindDebugButton("滚石!", function()
CrestRollstone.Release()
end)
ShowTip("技能已加载: 滚石压纹")
end, 1.0)
function CrestRollstone.Unload()
if _ticker then SL:Unschedule(_ticker) end
_rolling = false
end
return CrestRollstone
五、机制问答
问:顶退推出地皮的糗事怎么防?
答:顶退的落点卡一条线——线内随意退线到即止,怪的身体永远留在地皮里。
问:碾压为什么只结一拍?
答:碾轮快过怪——相遇一拍一账,碾着走全程的账面好看观感灾难。
问:顶退附赠的误时有什么用?
答:半拍出不了爪——顶远了它还得缓神,走回来的几拍是白送的输出窗。
问:碾轮的石纹为什么要转?
答:滚动是这条招的性格——石纹不转,碾子就成了滑过去的圆饼。
问:滚的时机怎么挑?
答:挑它刚进射程那一滚——从进射程到被碾最近的路,一步不多走。
六、调参与实战怎么用
参数层面三个量——滚速、碾压伤害、顶退封顶线。三百三十的滚速两秒滚完一屏:快得有压迫慢得看得清。实战里这套滚动带顶退的骨架能搬去酒桶阵、巨岩机关、油桶滚爆,全是放碾、碾身、封顶顶退一条线。常见坑两个:顶退不封顶推出世界;碾压持续结算变成移动磨盘。
补充一个设计层面的思考——攻防的账要分"压头"和"压脚"两笔:砸头脸的招吃的是措手不及,扫下盘的招吃的是站稳与否,两笔账的躲法不同、赏法也不同。一套战斗里两类招都备着,玩家才会抬头看低头看两头兼顾——只教一种躲法的战斗,练到后来只剩一种反应。
补充一个维护层面的思考——带机括节奏的招(连发、歇息、回填)要把节奏写成状态而不是写成延时串:连发是一态、歇息是一态、第二轮是一态,态与态的切换写在推进口里。串延时的版本多跑两轮就对不上拍——状态机的账怎么翻都对,延时串的账翻两页就乱。
补充一个工程层面的思考——弹道和牵引类的运动体在目标消失时要"就地收势":刃坠地、鸢归天、箭坠土,各自的收势演完账就清。运动体没收势就复用,新的一发会继承旧的残影和旧的目标——收势是运动体的卸载口,卸载口不在,运动体就是幽灵。
补充一个到达层面的思考——这六式招式各有一套到达的写法:滚石贴地碾过去、纸鸢从天上扎下来、钟摆走弧线来回扫、认踪矢拐弯追、双蛟绞着麻花游、机括匣点射轮转。到达方式就是招式的身份:改伤害容易改到达难,到达一改就成了另一个招。调招先调到达的节奏,数值放到最后一步。
写完留一句给做机关系的同学:玩家滚的是石碾也是那道封顶线——压头不压脚、顶退不顶飞,机关才砸得名正言顺。
全站技术干货持续更新:996 引擎 / Lua 实战帖,语法、参数与示例一篇讲透。进入文章地图 · 查看全部 →
【游戏功能】 隐蔽报错引入:一个很隐蔽的报错——机括匣的箭放完了还在放,匣里的箭明明只有六支,账面上却射出了第十七支:轮次的…
【游戏功能】 线上事故引入:早上水渠的双蛟出了怪相——两条蛟游着游着绞成了一股,分不出你我,双蛟的账记成了单蛟的翻倍。双蛟各…
【游戏功能】 单行代码拆解:先看一行代码: 箭头,往它那里挪一点 ——认踪矢的全部机关就这一行:箭每飞一拍,箭头的朝向往怪的…
【游戏功能】 先抛一个坑:大摆都荡完一个来回了,为什么还有人站在原地没挨刀?摆刃扫过的每一段都有它的账,站得对不对位子,决定…
【游戏功能】 隐蔽报错引入:一个很隐蔽的报错——纸鸢扎下来扎的是怪的脚后跟,明明瞄准的是头脸。鸢的俯坠路径读的是怪的脚下坐标…
【游戏功能】 线上事故引入:早上山道的滚石机关出了糗——石碾滚过去把怪顶退四十步,一步没刹住推出了战场地皮,半只身子挂在世界…