美文网首页
dota2rpg自定义按键绑定及WASD移动的实现

dota2rpg自定义按键绑定及WASD移动的实现

作者: XavierCHN | 来源:发表于2019-05-21 16:49 被阅读0次

    本文的目的是在DOTA2自定义游戏中实现一个WASD控制的8方向移动,如果你想实现的是4方向的,稍微修改一点点代码也可以做到。
    通过本文,你也可以了解到DOTA2自定义按键的流程。
    本文的所有代码你都可以在我开源的Endless Dungeon项目中找到

    一、声明按键绑定

    按键绑定需要写在 game/dota_addons/你的项目文件夹/addon_info.txt中(完整代码

        "Default_Keys"
        {
            "01"
            {
                "Key"       "D"
                "Command"   "+PlayerMoveRight"
                "Name"      "PlayerMoveRight"
            }
            "02"
            {
                "Key"       "W"
                "Command"   "+PlayerMoveUp"
                "Name"      "PlayerMoveUp"
            }
            "03"
            {
                "Key"       "S"
                "Command"   "+PlayerMoveDown"
                "Name"      "PlayerMoveDown"
            }
            "04"
            {
                "Key"       "A"
                "Command"   "+PlayerMoveLeft"
                "Name"      "PlayerMoveLeft"
            }
    }
    

    就完成了按键的声明。

    命令的回调声明则是在content/dota_addons/你的项目名称/panorama/scripts/custom_game/key_binding.js文件中(完整代码
    其中,要注意的是+代表按键按下,-代表按键抬起。

    function WrapFunction(name) {
        return function() {
            Game[name]();
        };
    }
    
    (function() {
        Game.AddCommand( "+PlayerMoveUp", WrapFunction("PlayerMoveUp"), "", 0 );
        Game.AddCommand( "+PlayerMoveDown", WrapFunction("PlayerMoveDown"), "", 0 );
        Game.AddCommand( "+PlayerMoveLeft", WrapFunction("PlayerMoveLeft"), "", 0 );
        Game.AddCommand( "+PlayerMoveRight", WrapFunction("PlayerMoveRight"), "", 0 );
        Game.AddCommand( "-PlayerMoveUp", WrapFunction("PlayerMoveUp_End"), "", 0 );
        Game.AddCommand( "-PlayerMoveDown", WrapFunction("PlayerMoveDown_End"), "", 0 );
        Game.AddCommand( "-PlayerMoveLeft", WrapFunction("PlayerMoveLeft_End"), "", 0 );
        Game.AddCommand( "-PlayerMoveRight", WrapFunction("PlayerMoveRight_End"), "", 0 );
    )();
    

    这里需要注意的问题是,这个js文件,你最好一次性写完之后,只在custom_ui_menifest.xml里面引用他,这也是为什么需要用WrapFunction方法来把回调放在其他的文件中,这样如果你如果修改回调方法并保存js文件后,引擎重新运行js文件就不会运行到Game.AddCommand,否则,命令绑定就会失效导致按键就会无响应(这是一个已知的BUG,很影响debug的效率)。

    二、js的命令回调

    在任意被引用的js文件中写明命令的回调如下:

    Game.PlayerMoveUp = function() {
        GameEvents.SendCustomGameEventToServer("ed_player_start_move_up", {})
    };
    Game.PlayerMoveDown = function() {
        GameEvents.SendCustomGameEventToServer("ed_player_start_move_down", {})
    };
    Game.PlayerMoveLeft = function() {
        GameEvents.SendCustomGameEventToServer("ed_player_start_move_left", {})
    };
    Game.PlayerMoveRight = function() {
        GameEvents.SendCustomGameEventToServer("ed_player_start_move_right", {})
    };
    
    Game.PlayerMoveUp_End = function() {
        GameEvents.SendCustomGameEventToServer("ed_player_end_move_up", {})
    };
    Game.PlayerMoveDown_End = function() {
        GameEvents.SendCustomGameEventToServer("ed_player_end_move_down", {})
    };
    Game.PlayerMoveLeft_End = function() {
        GameEvents.SendCustomGameEventToServer("ed_player_end_move_left", {})
    };
    Game.PlayerMoveRight_End = function() {
        GameEvents.SendCustomGameEventToServer("ed_player_end_move_right", {})
    };
    

    三、服务器端的事件响应

    服务器在收到ed_player_start_move_up之类的事件之后,做出具体的响应,代码如下,具体说明见注释

    function CEDGameMode:_RegisterCustomGameEventListeners()
        -- 注册移动的事件响应,上下左右的开始和结束(按下即开始,松开即结束)
        CustomGameEventManager:RegisterListener("ed_player_start_move_up", function(_, keys)
            self:On_ed_player_start_move_up(keys)
        end)
        CustomGameEventManager:RegisterListener("ed_player_start_move_down", function(_, keys)
            self:On_ed_player_start_move_down(keys)
        end)
        CustomGameEventManager:RegisterListener("ed_player_start_move_left", function(_, keys)
            self:On_ed_player_start_move_left(keys)
        end)
        CustomGameEventManager:RegisterListener("ed_player_start_move_right", function(_, keys)
            self:On_ed_player_start_move_right(keys)
        end)
        CustomGameEventManager:RegisterListener("ed_player_end_move_up", function(_, keys)
            self:On_ed_player_end_move_up(keys)
        end)
        CustomGameEventManager:RegisterListener("ed_player_end_move_down", function(_, keys)
            self:On_ed_player_end_move_down(keys)
        end)
        CustomGameEventManager:RegisterListener("ed_player_end_move_left", function(_, keys)
            self:On_ed_player_end_move_left(keys)
        end)
        CustomGameEventManager:RegisterListener("ed_player_end_move_right", function(_, keys)
            self:On_ed_player_end_move_right(keys)
        end)
    end
    
    -- 上下左右四个方向
    local upVector    = Vector(0, 1, 0)
    local downVector  = Vector(0, - 1, 0)
    local leftVector  = Vector(- 1, 0, 0)
    local rightVector = Vector(1, 0, 0)
    
    -- 核心的控制上下左右移动的循环
    local function createMovingTimer(hero)
        if hero.m_MovingTimer then
            return
        end
        
        -- 创建按键计时器,Timer函数需要https://github.com/XavierCHN/EndlessDungeon/blob/master/game/ed/scripts/vscripts/utils/funcs.lua
        -- 中的Timer函数    
        hero.m_MovingTimer = Timer(function()
            if not (IsValidEntity(hero) and hero:IsAlive()) then
                hero.bMovingUp    = false
                hero.bMovingDown  = false
                hero.bMovingLeft  = false
                hero.bMovingRight = false
                return 0.03
            end
    
            local movingVector = Vector(0, 0, 0)
    
            -- 根据玩家英雄当前上下左右的状态,计算玩家当前应该移动的方向
            -- 如按下A则应当向左移动
            -- 同时按AD应当不移动
            -- 同时按WD应当向右上方移动
            if hero.bMovingUp then
                movingVector = movingVector + upVector
            end
            if hero.bMovingDown then
                movingVector = movingVector + downVector
            end
            if hero.bMovingLeft then
                movingVector = movingVector + leftVector
            end
            if hero.bMovingRight then
                movingVector = movingVector + rightVector
            end
            movingVector = movingVector:Normalized()
    
            -- 具体的移动
            if movingVector.x == 0 and movingVector.y == 0 then
                -- 如果x, y均等于0,则不移动
            else
                -- 开始移动
                if not hero:IsStunned() then
                    -- 直接设定面向,这样快速交替按AD才会有响应
                    hero:SetForwardVector(movingVector)
                    -- 往移动的方向移动一小步
                    ExecuteOrderFromTable({
                                              UnitIndex = hero:entindex(),
                                              OrderType = DOTA_UNIT_ORDER_MOVE_TO_POSITION,
                                              Position  = hero:GetOrigin() + movingVector * 32
                                          })
                else
                    hero:Stop()
                end
            end
            return 0.03
        end)
    end
    
    -- 开始向上移动的按键响应,其他方向的与此类似
    function CEDGameMode:On_ed_player_start_move_up(keys)
        local player = PlayerResource:GetPlayer(keys.PlayerID)
        if not player then
            return
        end
        local hero = player:GetAssignedHero()
        if not hero then
            return
        end
    
        if not (IsValidEntity(hero) and hero:IsAlive()) then
            hero.bMovingUp = false
            ShowError("ed_hud_error_cannot_move", keys.PlayerID)
            return
        end
    
        if not hero.m_MovingTimer then
            createMovingTimer(hero)
        end
    
        -- 置向上移动为true
        hero.bMovingUp = true
    end
    function CEDGameMode:On_ed_player_start_move_down(keys)
        local player = PlayerResource:GetPlayer(keys.PlayerID)
        if not player then
            return
        end
        local hero = player:GetAssignedHero()
        if not hero then
            return
        end
    
        if not (IsValidEntity(hero) and hero:IsAlive()) then
            hero.bMovingDown = false
            ShowError("ed_hud_error_cannot_move", keys.PlayerID)
            return
        end
    
        if not hero.m_MovingTimer then
            createMovingTimer(hero)
        end
    
        hero.bMovingDown = true
    end
    function CEDGameMode:On_ed_player_start_move_left(keys)
        local player = PlayerResource:GetPlayer(keys.PlayerID)
        if not player then
            return
        end
        local hero = player:GetAssignedHero()
        if not hero then
            return
        end
    
        if not (IsValidEntity(hero) and hero:IsAlive()) then
            hero.bMovingLeft = false
            ShowError("ed_hud_error_cannot_move", keys.PlayerID)
            return
        end
    
        if not hero.m_MovingTimer then
            createMovingTimer(hero)
        end
    
        hero.bMovingLeft = true
    end
    function CEDGameMode:On_ed_player_start_move_right(keys)
        local player = PlayerResource:GetPlayer(keys.PlayerID)
        if not player then
            return
        end
        local hero = player:GetAssignedHero()
        if not hero then
            return
        end
    
        if not (IsValidEntity(hero) and hero:IsAlive()) then
            hero.bMovingRight = false
            ShowError("ed_hud_error_cannot_move", keys.PlayerID)
            return
        end
    
        if not hero.m_MovingTimer then
            createMovingTimer(hero)
        end
    
        hero.bMovingRight = true
    end
    function CEDGameMode:On_ed_player_end_move_up(keys)
        local player = PlayerResource:GetPlayer(keys.PlayerID)
        if not player then
            return
        end
        local hero = player:GetAssignedHero()
        if not hero then
            return
        end
    
        if not (IsValidEntity(hero) and hero:IsAlive()) then
            hero.bMovingUp = false
            ShowError("ed_hud_error_cannot_move", keys.PlayerID)
            return
        end
    
        if not hero.m_MovingTimer then
            createMovingTimer(hero)
        end
    
        hero.bMovingUp = false
    end
    function CEDGameMode:On_ed_player_end_move_down(keys)
        local player = PlayerResource:GetPlayer(keys.PlayerID)
        if not player then
            return
        end
        local hero = player:GetAssignedHero()
        if not hero then
            return
        end
    
        if not (IsValidEntity(hero) and hero:IsAlive()) then
            hero.bMovingDown = false
            ShowError("ed_hud_error_cannot_move", keys.PlayerID)
            return
        end
    
        if not hero.m_MovingTimer then
            createMovingTimer(hero)
        end
    
        hero.bMovingDown = false
    end
    function CEDGameMode:On_ed_player_end_move_left(keys)
        local player = PlayerResource:GetPlayer(keys.PlayerID)
        if not player then
            return
        end
        local hero = player:GetAssignedHero()
        if not hero then
            return
        end
    
        if not (IsValidEntity(hero) and hero:IsAlive()) then
            hero.bMovingLeft = false
            ShowError("ed_hud_error_cannot_move", keys.PlayerID)
            return
        end
    
        if not hero.m_MovingTimer then
            createMovingTimer(hero)
        end
    
        hero.bMovingLeft = false
    end
    function CEDGameMode:On_ed_player_end_move_right(keys)
        local player = PlayerResource:GetPlayer(keys.PlayerID)
        if not player then
            return
        end
        local hero = player:GetAssignedHero()
        if not hero then
            return
        end
    
        if not (IsValidEntity(hero) and hero:IsAlive()) then
            hero.bMovingRight = false
            ShowError("ed_hud_error_cannot_move", keys.PlayerID)
            return
        end
    
        if not hero.m_MovingTimer then
            createMovingTimer(hero)
        end
    
        hero.bMovingRight = false
    end
    

    相关文章

      网友评论

          本文标题:dota2rpg自定义按键绑定及WASD移动的实现

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