想要怎么動,那就怎么動,用Lua modifier實現位移技能

我們在制作Lua modifier的時候,第一步自然是這個API

LinkLuaModifier("modifier_your_modifier_name", "path/to/your/modifier/modifier_your_modifier_name.lua", LUA_MODIFIER_MOTION_NONE)

多思考一下就不難想到,最后一個參數,是做什么用的,如果改為其他的結果,比如LUA_MODIFIER_MOTION_HORIZONTAL/LUA_MODIFIER_MOTION_VERTICAL/LUA_MODIFIER_MOTION_BOTH,會有什么不同呢?
答案是,如果你在Lua modifier的代碼里面不做什么特殊的處理的話,做出來的效果并沒有什么不同。
而這個參數的不同,導致的結果是,我們在modifier_your_modifier.lua中,使用

modifier_your_modifier_name = class({})

所創建的這個class,在你為其指定LUA_MODIFIER_MOTION_HORIZONTAL的時候,其鏈接到的class不是CDOTA_Modifier_Lua,而是CDOTA_Modifier_Lua_Horizontal_Motion,而仔細查看這個繼承自CDOTA_Modifier_Lua的class的API文檔,不難發現,他多出來的幾個API就是實現運動控制的關鍵。
首先,我們需要在modifier的OnCreated函數中,調用ApplyHorizontalMotionController,之后在UpdateHorizontalMotion的函數中為單位刷新位置,之后在modifier的OnDestroy函數中為單位移除運動控制器RemoveHorizontalMotionController
具體實現

modifier_horizontal_motion_example = class({})

function modifier_horizontal_motion_example:OnDestroy()
    if IsServer() then
        -- 移除運動控制器
        self:GetParent():RemoveHorizontalMotionController(self)
    end
end

function modifier_horizontal_motion_example:OnCreated(kv)
    if IsServer() then
        -- 為單位添加水平運動控制器
        self:ApplyHorizontalMotionController()
        local owner                            = self:GetParent()
        -- 儲存一些初始狀態
        self.vStartingPosition                 = owner:GetOrigin()
        self.flTimeExpired                     = 0
    end
end

function modifier_player_entering_next_level:UpdateHorizontalMotion(me, dt)
    if IsServer() then
        -- 計算具體的新位置,這個要根據實際需要來
        -- me指代的是擁有運動控制器的單位,也就是這個modifier的owner,dt就指距離上次調用這個
        -- 函數過去的時間
        -- 引擎將會為這兩次調用之間平滑地插補動畫
        me:SetOrigin(newOrigin)
    end
end

至于具體想要怎么動,那就看你想要具體怎么計算newOrigin了。

舉一個簡單的例子:

newOrigin = self:GetParent():GetForwardVector() * 1000 + self:GetParent():GetOrigin()

這樣這個單位就會以1000的速度向前沖刺了。

如果你還要上上下下地動?
原理是一樣的,你需要在OnCreated函數中添加 self:ApplyVerticalMotionController(),并在UpdateVerticalMotion(me, dt)中為單位確定新的位置。
需要注意的是,你需要先獲取單位所在的位置,然后計算單位的Z軸的位置,并使用me:SetOrigin()來確定單位的位置。

function modifier_vertical_motion_example:UpdateVerticalMotion(me, dt)
    if IsServer() then
        local origin = me:GetOrigin()
        origin.z = CalculateYourZ() -- 具體怎么計算根據你的實際需要來
        me:SetOrigin(origin)
    end
end

最后放上一段自己的代碼
具體的實現效果是,完成一次向指定地點的,高度為4000的拋物線運動:

modifier_creature_pudge_jump = class({})

function modifier_creature_pudge_jump:IsStunDebuff()
    return true
end

function modifier_creature_pudge_jump:IsHidden()
    return true
end

function modifier_creature_pudge_jump:IsPurgable()
    return false
end

function modifier_creature_pudge_jump:RemoveOnDeath()
    return false
end

function modifier_creature_pudge_jump:OnCreated(kv)
    if IsServer() then
        if self:ApplyHorizontalMotionController() == false or self:ApplyVerticalMotionController() == false then
            self:Destroy()
            return
        end

        self.vStartPosition    = GetGroundPosition( self:GetParent():GetOrigin(), self:GetParent() )

        self.vTargetPosition   = self:GetAbility():GetCursorPosition()
        self.flDuration        = 1.7
        self.flHeight          = 4000

        self.vDirection        = (self.vTargetPosition - self.vStartPosition):Normalized()
        self.flDistance        = (self.vTargetPosition - self.vStartPosition):Length2D()
        self.flHorizontalSpeed = self.flDistance / self.flDuration

        -- 創建開始的特效和音效
        EmitSoundOnLocationWithCaster(self.vStartPosition, "Ability.TossThrow", self:GetParent())

    end
end

function modifier_creature_pudge_jump:OnDestroy()
    if IsServer() then
        self:GetParent():RemoveHorizontalMotionController(self)
        self:GetParent():RemoveVerticalMotionController(self)
    end
end

function modifier_creature_pudge_jump:DeclareFunctions()
    local funcs = {
        MODIFIER_PROPERTY_OVERRIDE_ANIMATION,
    }
    return funcs
end

function modifier_creature_pudge_jump:CheckState()
    local state = {
        [MODIFIER_STATE_STUNNED] = true,
    }

    return state
end

function modifier_creature_pudge_jump:GetOverrideAnimation()
    return ACT_DOTA_CAST_ABILITY_ROT
end

function modifier_creature_pudge_jump:UpdateHorizontalMotion(me, dt)
    if IsServer() then
        -- 根據速度,設置當前的位置
        local vOldPosition = me:GetOrigin()
        local vNewPos      = vOldPosition + self.vDirection * self.flHorizontalSpeed * dt
        vNewPos.z          = 0
        me:SetOrigin(vNewPos)

        -- 判斷是否到達了終點
    end
end

function modifier_creature_pudge_jump:UpdateVerticalMotion(me, dt)
    if IsServer() then
        local vOrigin        = me:GetOrigin()
        local vDistance      = (vOrigin - self.vStartPosition):Length2D()
        local vZ             = - 4 * self.flHeight / (self.flDistance * self.flDistance) * (vDistance * vDistance) + 4 * self.flHeight / self.flDistance * vDistance
        vOrigin.z            = vZ
        -- 判斷是否到達了終點
        local flGroundHeight = GetGroundHeight( vOrigin, self:GetParent() )
        local bLanded        = false

        if ( vOrigin.z < flGroundHeight and vDistance > self.flDistance / 2 ) then
            vOrigin.z = flGroundHeight
            bLanded   = true
        end

        me:SetOrigin(vOrigin)
        if bLanded == true then
            -- ApplyDamage
            local units = FindUnitsInRadius(self:GetParent():GetTeamNumber(), self:GetParent():GetOrigin(), nil, 275, DOTA_UNIT_TARGET_TEAM_BOTH, DOTA_UNIT_TARGET_ALL, DOTA_UNIT_TARGET_FLAG_NONE, FIND_ANY_ORDER, false)
            for _, unit in pairs(units) do
                DealDamage(self:GetParent(), unit, 1, self)
            end


            -- Particle
            local pid = ParticleManager:CreateParticle("particles/econ/items/earthshaker/earthshaker_totem_ti6/earthshaker_totem_ti6_leap_impact.vpcf", PATTACH_WORLDORIGIN, self:GetParent())
            ParticleManager:SetParticleControl(pid, 0, me:GetOrigin())
            ParticleManager:ReleaseParticleIndex(pid)

            EmitSoundOnLocationWithCaster(self:GetParent():GetOrigin(), "Ability.TossImpact", self:GetParent())

            self:GetParent():RemoveHorizontalMotionController(self)
            self:GetParent():RemoveVerticalMotionController(self)
            self:SetDuration(0.15, true)
        end
    end
end

教程到此結束。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容