Hi there.
So I’m trying to make an advanced movement system for a RPG top down game im working on. The movement script is okay. What’s not is how the player are moving. I don’t know what makes the player move that way. Like evrytime you try to walk diagonally or you spam the WASD keys, it just glitches the entire movement system. Like the player get stuck when you try to walk left but not when the player want to walk right. Im stressing out huhu. Sorry for the bad english btw. Im typing this post pretty fast so yeah.
Play the game so you can see what I meant. Or maybe download the file and read the scripts? idk
Here’s the game link:
This is the scrips that I suspected are the reason why the glitch happens:
ControlModule (ReplicatedStorage.Modules
--//SERVICES
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
--//SYSTEM FOLDERS
local RemoteEvents = ReplicatedStorage.RemoteEvents
local RemoteFunctions = ReplicatedStorage.RemoteFunctions
local Bindables = ReplicatedStorage.Bindables
--//VARAIBLES
local module = {}
local axises = { -- direction = {x, z}
Forward = {0,-1},
Left = {-1,0},
Backward = {0,1},
Right = {1,0},}
local rotations = { -- direction = angle
Forward = 0,
Left = 90,
Backward = 180,
Right = -90,
D1 = -45,
D2 = 45,
D3 = 135,
D4 = -135,}
-- DIAGONAL THINGY
-- local x, z = (math.sin(45) * math.pi/4) * -1, (math.sin(45) * math.pi/4 ) * 1
--//FUNCTIONS
function getAxis(direction : string)
-- check if requesting main axis
if axises[direction] then
--print("A")
return axises[direction]
else
-- check if there's a rotation value of the direction in the rotations table
if rotations[direction] then
--print("B")
local direction1, direction2
local axis1, axis2
local axis
if direction == "D1" then
direction1 = "Forward"
direction2 = "Right"
elseif direction == "D2" then
direction1 = "Forward"
direction2 = "Left"
elseif direction == "D3" then
direction1 = "Backward"
direction2 = "Left"
elseif direction == "D4" then
direction1 = "Backward"
direction2 = "Right"
end
-- combine bypass axis
axis1 = axises[direction1]
axis2 = axises[direction2]
local x1, z1 = axis1[1], axis1[2]
local x2, z2 = axis2[1], axis2[2]
local alpha, beta = x1 + x2, z1 + z2
--print(alpha, beta)
--print(alpha, beta)
-- get bypass coordinate
local x = (math.sin(45) * math.pi/4) * alpha
local z = (math.sin(45) * math.pi/4) * beta
return {x, z}
end
end
end
local hb = 0
function module.MovePlayer(player : Player, move : boolean, direction : string)
-- TEST CODE
if move == true then
-- move
-- check if there's running connection
local MovementConnection = Bindables.GetInfo:Invoke(player, "MovementConnection")
local Facing = Bindables.GetInfo:Invoke(player, "Facing")
--print(MovementConnection, Facing)
-- set infos
Bindables.SetInfo:Fire(player, "Facing", direction)
Bindables.SetInfo:Fire(player, "State", "Moving")
-- if player don't have renderer function running, create one
--print("connecting")
Bindables.SetInfo:Fire(player, "MovementConnection", RunService.Heartbeat:Connect(function(deltaT)
hb += 1
-- if player left
if player.Character == nil then
return
end
-- if standing
if Bindables.GetInfo:Invoke(player, "State") == "Moving" then
-- move
local speed = Bindables.GetInfo:Invoke(player, "Speed")
-- set position
local axis = getAxis(direction)
local alpha = speed * deltaT
local x, z = player.Character.Root.Position.X + (alpha * axis[1]), player.Character.Root.Position.Z + (alpha * axis[2])
--print(direction, axis)
local position = CFrame.new(x,player.Character.Root.Position.Y,z)
local rotation = CFrame.Angles(0,math.rad(rotations[direction]),0)
player.Character.Root.CFrame = position
-- check wth is the problem :(
if hb >= 20 then
hb = 0
local P2 = (player.Character.Root.Position + Vector3.new((alpha * axis[1]), 0, player.Character.Root.Position.Z + (alpha * axis[2])))
print((player.Character.Root.Position - P2).Unit)
end
end
end))
else
-- stop movement
Bindables.SetInfo:Fire(player, "State", "Standing")
--print("stop")
-- disconnect movement connection
local MovementConnection = Bindables.GetInfo:Invoke(player, "MovementConnection")
if MovementConnection then
--print("disconnecting")
MovementConnection:Disconnect()
Bindables.SetInfo:Fire(player, "MovementConnection", nil)
end
end
end
--//CONNECTIONS
RemoteEvents.MovePlayer.OnServerEvent:Connect(module.MovePlayer)
return module
ControlClient (StarterPlayerScripts
--//SERVICES
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
--//SYSTEM FOLDERS
local RemoteEvents = ReplicatedStorage:WaitForChild("RemoteEvents")
local RemoteFunctions = ReplicatedStorage:WaitForChild("RemoteFunctions")
--//OBJECTS
local localPlayer = Players.LocalPlayer
local mouse = localPlayer:GetMouse()
--//VARIABLES
local keys = {"w","a","s","d",}
local pressedKeys = {w = false, a = false, s = false, d = false,}
local lastKey, curKey
local controlConnection1
local controlConnection2
local mainDirections = {
["W"] = "Forward",
["A"] = "Left",
["S"] = "Backward",
["D"] = "Right",}
--//FUNCTIONS
local function getUserDevice()
local device
-- if keyboard enabled
if UserInputService.KeyboardEnabled and not UserInputService.TouchEnabled then
device = "COMPUTER"
-- if touch enabled
elseif UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled then
device = "MOBILE"
-- default
else
device = "COMPUTER"
end
return device
end
-- get pressed keys
function getPressedKeys()
local pack = {}
for key, pressed in pairs(pressedKeys) do
if pressed == true then
-- set weight
if key == curKey then
pack[1] = curKey
elseif key == lastKey then
pack[2] = lastKey
else
local index = #pack + 1
pack[index] = key
end
end
end
--print(pack)
return pack
end
function getDirection(key : any)
-- if single key
if typeof(key) == "string" and mainDirections[key] then
return mainDirections[key]
end
-- if diagonal request
if typeof(key) == "table" then -- D stands for 'diagonal'
if table.find(key, "W") and table.find(key, "D") then -- top right corner
return "D1"
elseif table.find(key, "W") and table.find(key, "A") then -- top left corner
return "D2"
elseif table.find(key, "A") and table.find(key, "S") then -- bottom left corner
return "D3"
elseif table.find(key, "S") and table.find(key, "D") then -- bottom right corner
return "D4"
-- impossible combination
elseif (table.find(key, "A") and table.find(key, "D")) or
(table.find(key, "W") and table.find(key, "S"))
then
return mainDirections[key[1]]
end
end
end
local function toggleCamera(mode : string)
-- access module
local CameraModule = require(script.CameraModule)
-- activate camera base on the mode
if mode == "Game" then -- GAME CAMERA MODE
CameraModule.ActivateGameCamera(localPlayer)
end
end
-- Computer only controller
local function toggleControl(toggle : boolean, device : string)
if device == "COMPUTER" then
if toggle then
-- key pressed
controlConnection1 = mouse.KeyDown:Connect(function(key)
if table.find(keys, key) then
--
lastKey = curKey
curKey = key
pressedKeys[key] = true
-- movement conditions
local results = getPressedKeys()
local direction = getDirection(string.upper(key))
if #results > 1 then
-- diagonal movement
--print("Diagonal!!!")
local keySet = {} -- only send two keys
keySet[1] = string.upper(results[1])
keySet[2] = string.upper(results[2])
direction = getDirection(keySet)
else
-- straight line movement
--print("STRAIGHTHTHT!!!")
end
RemoteEvents:WaitForChild("MovePlayer"):FireServer(true, direction)
end
end)
-- key released
controlConnection2 = mouse.KeyUp:Connect(function(key)
if table.find(keys, key) then
--
pressedKeys[key] = false
-- check if want to continue movement
local results = getPressedKeys()
if #results == 0 then
-- stop completely
--print("STOP")
curKey = nil
RemoteEvents:WaitForChild("MovePlayer"):FireServer(false)
elseif #results == 1 then
-- continue moving
--print("CONTINUE")
local pressedKey = results[1]
local direction = getDirection(string.upper(pressedKey))
curKey = pressedKey
RemoteEvents:WaitForChild("MovePlayer"):FireServer(true, direction)
end
end
end)
else
-- if there's existing connecton, disconnect
if controlConnection1 then
controlConnection1:Disconnect()
controlConnection1 = nil
end
if controlConnection2 then
controlConnection2:Disconnect()
controlConnection2 = nil
end
end
end
end
--//CONNECTIONS
RemoteEvents:WaitForChild("ToggleCamera").OnClientEvent:Connect(toggleCamera)
RemoteEvents:WaitForChild("ToggleControl").OnClientEvent:Connect(toggleControl)
RemoteFunctions:WaitForChild("GetUserDevice").OnClientInvoke = getUserDevice