时间停止

作者: 能鸽善舞的小豪 | 来源:发表于2019-07-10 11:20 被阅读0次

简介

“时间停止”是晓美焰的标志性技能,其效果顾名思义,冻结时间,控制除自己以外的所有物体,暂停其一切行为。当这个技能发动的时候,怪物无法移动和攻击,花草树木不会生长,查理不会伤害黑暗中的玩家,飞行物将被定在原地,就连雨滴、雪和火山灰也会暂时悬浮在半空中。

时停技能可通过点按技能图标(在饥饿值图标左侧)来主动触发,持续8秒,技能结束后会进入冷却,时间为25秒(单机版)/30秒(联机版)。

在单机版中,世界时钟也会因为这个技能停摆。换言之,如果你频繁发动时间停止,那么一天的时间可能会延长到10分钟,而非默认的8分钟。这拖延了猎犬、蝙蝠和四季boss的来袭时间,但也意味着更多的饥饿值消耗和魔力的流失。

在联机版中,这个技能不会真正地停止游戏时间,并且它只会作用于晓美焰附近40单位距离内的物体,所以离晓美焰太远的玩家可能并不会察觉到这个技能被发动,但一旦玩家踏入魔法的控制范围,则ta也同样会被冻结。作为发动者,晓美焰自己显然不会受时间停止的影响,而其他玩家也可以在魔法栏位利用1个金块,1个齿轮和15点理智值制作一个精致的怀表,防止自己遭受时间魔法控制。


这些实体可以免疫时停:

  • 带有homuraTag_ignoretimemagic标签(如熔炉模式下的伤害数字)
  • 带有INLIMBO标签(放在物品栏和容器内的所有物体)
  • 携带精致的怀表(包括玩家、猪人、切斯特等)
  • 晓美焰
  • 本身不符合上述条件,但母体免疫时停(如玩家释放符咒时的光)

这些实体可以暂时免疫时停:

  • 刚刚被扔出的物体(如回力标、水球)
  • 刚刚被丢在地上的物体

代码实现

1.计时机制的暂停

暂停实体需要注意很多细节。比如,将一个物体的动画(AnimState)和运动(Physics)暂停以后,还需要阻止它内部的计时机制。以草的燃烧为例,一根草被点燃后,经过7.5秒的燃烧,熄灭变为灰烬,这个过程的计时是基于延时任务函数(DoTaskInTime)。对于这个计时器,官方提供了添加和取消它的方法,但没有提供暂停它的方法,所以得自己写一个。

--这个函数可以让延时任务的完成时间往后推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)

如果想要暂停一个实体的全部延时任务,可以用以下这段代码。

--遍历实体的所有计时器,并让它们的完成时间往后推1帧
--配合组件的OnUpdate函数就能实现计时器暂停
for k in pairs(inst.pendingtasks or {})do
    k:AddTick()
end

这样一来,物体内部的计时器就被控制住了。这有什么作用呢?举两个例子。一个干草已经燃烧了5秒,此时发动时停技能,则这个燃烧的草不会在技能持续期间突然变成灰烬,而是在技能结束后的2.5秒才熄灭;反之,先在地上摆5个干草,发动技能,趁技能结束前依次点燃这5个干草,那么这些干草会在技能结束后才会熄灭,并且是同时熄灭。(因为它们是被“同时”点燃)

2.阻止组件刷新

colourtweener(渐变),grue(查理攻击),projectile(子弹)等组件中存在着一个刷新机制,例如海象射出的吹箭,会以每秒30次的频率计算自己和目标的距离,如果距离小于1,就判定为击中目标,否则继续往前飞行。我们并不希望在撞上停止运动的飞行物后会受到伤害,所以要阻止组件的刷新活动。
有少部分组件的刷新是不应该被暂停的,如container(容器),如果暂停的话,会导致界面无法正常关闭。

local skip_components = {
    'container', --保证容器界面正常关闭
   --[[......]]--
}
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.范围搜索

为了游戏的流畅性,时间停止技能显然不应该将饥荒世界里的所有物体都控制住,它只影响以玩家为中心,40半径范围内的物体——这个范围已经大大超出了玩家的视野范围。

在何时搜索附近实体呢?一般的思路是,在技能发动时搜索一次,把附近所有物体暂停,然后在技能结束时解除暂停状态。但略作思考就能发现问题:假如在技能持续期间,出现了一个新的物体(比如落下来一只鸟),则这个物体是无法受到控制的。因此,我们应该每隔一段时间就进行一次搜索。

--以每秒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

    --如果对应值仍然为1,则移除
    --如果对应值为2,不移除,并重置为1,然后对这些实体进行更新
    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

相关文章

  • 时间停止

  • 停止时间

    别人眼中的我会是什么样子? 首先说说我在自己眼中呈现的面貌。 有一份能养活自己的工作,并且还能较好地完成工作,不算...

  • 时间停止

    简介 “时间停止”是晓美焰的标志性技能,其效果顾名思义,冻结时间,控制除自己以外的所有物体,暂停其一切行为。当这个...

  • 停止时间

    停止的时间 如同按下了暂停键 某一刻的事 从此刻开始断线 时间外的事 依然连绵不断 只是这一段时间 断断续续难以相...

  • 时间停止

    小我是无意识的状况下产生思维认同,情感认同所导致小我的需求,它不仅了无止境,还脆弱不堪,容易受到威胁。 只要有恐惧...

  • 希望时间停止

    做了个不是很完美的决定,即将要面对,如果时间停止在今天就好了,这样我不用承受还没做好决定的焦虑,也不用去面对...

  • 假如时间停止

    如果,时间可以停止,你,会做什么? 如果时间可以停止,我想穿梭在贫民窟,看尽这世间的无奈;我想流走在灯火通明的街道...

  • 停止的时间

    坐公交车,从北到南,从南到北,窗外闪过一条条街,好听的歌,风拂乱了发,思绪跑得很远。似乎穿越了时光,不知所...

  • 时间停止吧

    很希望时间可以停在某一刻,那样,悲伤不会继续,开心不会结束。 悲伤铺天盖地席卷而来的时候,真的不知道该做什么,只是...

  • 愿时间停止

    突然觉得时间停止在这一刻多好,在这最纯真,最天真的年代!聊着最“无聊”的话题,没有烦恼,没有疾病!就这么一直玩儿下去!

网友评论

    本文标题:时间停止

    本文链接:https://www.haomeiwen.com/subject/nkpckctx.html