天天看點

java鍵盤監聽wasd控制_dota2rpg自定義按鍵綁定及WASD移動的實作

本文的目的是在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