簡介
“時間停止”是曉美焰的標(biāo)志性技能歼冰,其效果顧名思義,凍結(jié)時間耻警,控制除自己以外的所有物體,暫停其一切行為甸怕。當(dāng)這個技能發(fā)動的時候甘穿,怪物無法移動和攻擊,花草樹木不會生長梢杭,查理不會傷害黑暗中的玩家温兼,飛行物將被定在原地,就連雨滴募判、雪和火山灰也會暫時懸浮在半空中届垫。
時停技能可通過點按技能圖標(biāo)(在饑餓值圖標(biāo)左側(cè))來主動觸發(fā),持續(xù)8秒全释,技能結(jié)束后會進(jìn)入冷卻浸船,時間為25秒(單機版)/30秒(聯(lián)機版)登淘。
在單機版中,世界時鐘也會因為這個技能停擺辩撑。換言之,如果你頻繁發(fā)動時間停止峭判,那么一天的時間可能會延長到10分鐘,而非默認(rèn)的8分鐘疗认。這拖延了獵犬、蝙蝠和四季boss的來襲時間缎浇,但也意味著更多的饑餓值消耗和魔力的流失誉券。
在聯(lián)機版中仑乌,這個技能不會真正地停止游戲時間,并且它只會作用于曉美焰附近40單位距離內(nèi)的物體,所以離曉美焰太遠(yuǎn)的玩家可能并不會察覺到這個技能被發(fā)動,但一旦玩家踏入魔法的控制范圍畅买,則ta也同樣會被凍結(jié)。作為發(fā)動者犀填,曉美焰自己顯然不會受時間停止的影響,而其他玩家也可以在魔法欄位利用1個金塊冕广,1個齒輪和15點理智值制作一個精致的懷表父能,防止自己遭受時間魔法控制鹃唯。
這些實體可以免疫時停:
- 帶有homuraTag_ignoretimemagic標(biāo)簽(如熔爐模式下的傷害數(shù)字)
- 帶有INLIMBO標(biāo)簽(放在物品欄和容器內(nèi)的所有物體)
- 攜帶精致的懷表(包括玩家、豬人跪者、切斯特等)
- 曉美焰
- 本身不符合上述條件弟晚,但母體免疫時停(如玩家釋放符咒時的光)
這些實體可以暫時免疫時停:
- 剛剛被扔出的物體(如回力標(biāo)、水球)
- 剛剛被丟在地上的物體
代碼實現(xiàn)
1.計時機制的暫停
暫停實體需要注意很多細(xì)節(jié)。比如指煎,將一個物體的動畫(AnimState)和運動(Physics)暫停以后,還需要阻止它內(nèi)部的計時機制黎棠。以草的燃燒為例畴栖,一根草被點燃后,經(jīng)過7.5秒的燃燒重绷,熄滅變?yōu)榛覡a候醒,這個過程的計時是基于延時任務(wù)函數(shù)(DoTaskInTime)。對于這個計時器,官方提供了添加和取消它的方法,但沒有提供暫停它的方法犬金,所以得自己寫一個该默。
--這個函數(shù)可以讓延時任務(wù)的完成時間往后推1幀
local function PeriodicPostInit(self)
function self:AddTick()
local thislist = scheduler.attime[self.nexttick]
self.nexttick = self.nexttick + 1
if not thislist then
return
end
if not scheduler.attime[self.nexttick] then
scheduler.attime[self.nexttick] = {}
end
local nextlist = scheduler.attime[self.nexttick]
thislist[self] = nil
nextlist[self] = true
self.list = nextlist
end
end
AddGlobalClassPostConstruct('scheduler', 'Periodic', PeriodicPostInit)
如果想要暫停一個實體的全部延時任務(wù)音榜,可以用以下這段代碼违霞。
--遍歷實體的所有計時器泌类,并讓它們的完成時間往后推1幀
--配合組件的OnUpdate函數(shù)就能實現(xiàn)計時器暫停
for k in pairs(inst.pendingtasks or {})do
k:AddTick()
end
這樣一來,物體內(nèi)部的計時器就被控制住了。這有什么作用呢茅诱?舉兩個例子。一個干草已經(jīng)燃燒了5秒搬卒,此時發(fā)動時停技能瑟俭,則這個燃燒的草不會在技能持續(xù)期間突然變成灰燼摆寄,而是在技能結(jié)束后的2.5秒才熄滅;反之欠橘,先在地上擺5個干草建炫,發(fā)動技能,趁技能結(jié)束前依次點燃這5個干草乔夯,那么這些干草會在技能結(jié)束后才會熄滅妹笆,并且是同時熄滅。(因為它們是被“同時”點燃)
2.阻止組件刷新
colourtweener(漸變)拳缠,grue(查理攻擊)墩新,projectile(子彈)等組件中存在著一個刷新機制茂腥,例如海象射出的吹箭,會以每秒30次的頻率計算自己和目標(biāo)的距離切省,如果距離小于1最岗,就判定為擊中目標(biāo),否則繼續(xù)往前飛行朝捆。我們并不希望在撞上停止運動的飛行物后會受到傷害般渡,所以要阻止組件的刷新活動。
有少部分組件的刷新是不應(yīng)該被暫停的芙盘,如container(容器)驯用,如果暫停的話,會導(dǎo)致界面無法正常關(guān)閉儒老。
local skip_components = {
'container', --保證容器界面正常關(guān)閉
--[[......]]--
}
local function CanHook(name)
for _,v in pairs(skip_components)do
if v == name then
return false
end
end
return true
end
local function ComponentPostInit(self)
local old_add = self.AddComponent
function self:AddComponent(name, ...)
old_add(self, name, ...)
if CanHook(name) and self.components[name].OnUpdate then
local cmp = self.components[name]
local old_up = cmp.OnUpdate
cmp.OnUpdate = function(self, ...)
if self.inst:HasTag('homuraTag_pause') then
return
else
old_up(self, ...)
end
end
end
end
end
AddGlobalClassPostConstruct('entityscript','EntityScript', ComponentPostInit)
3.范圍搜索
為了游戲的流暢性蝴乔,時間停止技能顯然不應(yīng)該將饑荒世界里的所有物體都控制住,它只影響以玩家為中心驮樊,40半徑范圍內(nèi)的物體——這個范圍已經(jīng)大大超出了玩家的視野范圍薇正。
在何時搜索附近實體呢?一般的思路是囚衔,在技能發(fā)動時搜索一次挖腰,把附近所有物體暫停,然后在技能結(jié)束時解除暫停狀態(tài)练湿。但略作思考就能發(fā)現(xiàn)問題:假如在技能持續(xù)期間猴仑,出現(xiàn)了一個新的物體(比如落下來一只鳥),則這個物體是無法受到控制的肥哎。因此辽俗,我們應(yīng)該每隔一段時間就進(jìn)行一次搜索。
--以每秒30次的頻率搜索附近實體
local function OnUpdate(inst, dt)
--[[......]]--
--再次遍歷周圍實體贤姆,加入新的榆苞,移除出范圍的
local ignoretags = {"INLIMBO", "homuraTag_ignoretimemagic"}
local searchlocal = not TheNet:IsDedicated()
for player in pairs(inst.centers)do
local x,y,z = player:GetPosition():Get()
local ents = TheSim:FindEntities(x,y,z, MAGIC_RADIUS, nil, ignoretags)
for _, item in pairs(ents)do
if not IsMagicImmue(item) and (item.Network or searchlocal) then
if not inst.items[item] then
inst:AddItem(item)
inst.items[item] = 2
else
inst.items[item] = 2
end
end
--[[......]]--
end
end
--如果對應(yīng)值仍然為1稳衬,則移除
--如果對應(yīng)值為2霞捡,不移除,并重置為1薄疚,然后對這些實體進(jìn)行更新
for k,v in pairs(inst.items)do
if v == 1 then
inst:RemoveItem(k)
end
if v == 2 then
inst.items[k] = 1
ItemTimeMagicUpdate(k, dt)
end
end
--[[......]]--
end