Player Direction

so before i get yelled at yes I did use ai, but I’m hoping to learn how it all works and eventually rewrite it myself, but for now I’ve ran into an issue, where the player doesn’t face left or right in the 2d plane, but instead front and back. How can I fix this? I tried a bunch of like repositioning but its eosnt work.

PlayerInputScript:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
character.PrimaryPart = rootPart

local fightEvent = ReplicatedStorage:WaitForChild("FightState")
local playerStart = ReplicatedStorage:WaitForChild("PlayerStart") -- Vector3Value

-- Load animations
local animator = humanoid:WaitForChild("Animator")

local function loadAnimation(id)
	local anim = Instance.new("Animation")
	anim.AnimationId = "rbxassetid://" .. id
	return animator:LoadAnimation(anim)
end

local walkFrontTrack = loadAnimation("111437686490686") -- Replace with correct ID
local walkBackTrack = loadAnimation("71507897049072") -- Replace with correct ID
local idleTrack = loadAnimation("134052246679083") -- Replace with correct ID


-- Movement config
local moveSpeed = 8
local moveVelocity = 0
local direction = 0
local keysPressed = { A = false, D = false }
local enabled = false

-- Animation control
local function updateAnimation()
	if math.abs(moveVelocity) < 0.05 then
		if not idleTrack.IsPlaying then
			walkFrontTrack:Stop()
			walkBackTrack:Stop()
			idleTrack:Play()
		end
	elseif moveVelocity > 0 then
		if not walkFrontTrack.IsPlaying then
			idleTrack:Stop()
			walkBackTrack:Stop()
			walkFrontTrack:Play()
		end
	elseif moveVelocity < 0 then
		if not walkBackTrack.IsPlaying then
			idleTrack:Stop()
			walkFrontTrack:Stop()
			walkBackTrack:Play()
		end
	end
end

-- Facing logic
local function updateFacing()
	if direction ~= 0 then
		local facingAngle = direction == -1 and math.rad(180) or 0
		local pos = rootPart.Position
		character:SetPrimaryPartCFrame(CFrame.new(pos.X, pos.Y, playerStart.Value.Z) * CFrame.Angles(0, facingAngle, 0))
	end
end

UserInputService.InputBegan:Connect(function(input, gpe)
	if gpe or not enabled then return end
	if input.KeyCode == Enum.KeyCode.A then
		keysPressed.A = true
	elseif input.KeyCode == Enum.KeyCode.D then
		keysPressed.D = true
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if not enabled then return end
	if input.KeyCode == Enum.KeyCode.A then
		keysPressed.A = false
	elseif input.KeyCode == Enum.KeyCode.D then
		keysPressed.D = false
	end
end)

RunService.RenderStepped:Connect(function(dt)
	if not enabled then return end

	if keysPressed.A and not keysPressed.D then
		direction = -1
	elseif keysPressed.D and not keysPressed.A then
		direction = 1
	else
		direction = 0
	end

	moveVelocity = direction * moveSpeed
	humanoid:Move(Vector3.new(moveVelocity, 0, 0), true)

	updateFacing()
	updateAnimation()
end)

fightEvent.OnClientEvent:Connect(function(state)
	enabled = state
	if not state then
		moveVelocity = 0
		keysPressed = { A = false, D = false }
		walkFrontTrack:Stop()
		walkBackTrack:Stop()
		idleTrack:Play()
	end
end)

CameraController:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local workspace = game:GetService("Workspace")

local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local rootPart = character:WaitForChild("HumanoidRootPart")
local camera = workspace.CurrentCamera
local fightEvent = ReplicatedStorage:WaitForChild("FightState")

local opponentDummy = nil

local CAMERA_HEIGHT = 8
local CAMERA_MIN_ZOOM = 20
local CAMERA_MAX_ZOOM = 50

local enabled = false

local function getDummyRoot(dummy)
	if not dummy then return nil end
	return dummy:FindFirstChild("HumanoidRootPart") or dummy.PrimaryPart
end

fightEvent.OnClientEvent:Connect(function(state)
	enabled = state
	if not state then
		camera.CameraType = Enum.CameraType.Custom
		opponentDummy = nil
	else
		for _, obj in pairs(workspace:GetChildren()) do
			if obj.Name == "Dummy" then
				opponentDummy = obj
				break
			end
		end
	end
end)

RunService.RenderStepped:Connect(function()
	if not enabled or not opponentDummy or not rootPart then return end

	local dummyRoot = getDummyRoot(opponentDummy)
	if not dummyRoot then return end

	local playerPos = rootPart.Position
	local dummyPos = dummyRoot.Position

	local midpoint = (playerPos + dummyPos) / 2
	local distance = (playerPos - dummyPos).Magnitude
	local zoom = math.clamp(distance * 1.2, CAMERA_MIN_ZOOM, CAMERA_MAX_ZOOM)

	local camPos = Vector3.new(midpoint.X, midpoint.Y + CAMERA_HEIGHT, midpoint.Z + zoom)
	local camFocus = Vector3.new(midpoint.X, midpoint.Y, midpoint.Z)

	camera.CameraType = Enum.CameraType.Scriptable
	camera.CFrame = CFrame.new(camPos, camFocus)
end)

FightStateSwitcher:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ReplicatedFirst = game:GetService("ReplicatedFirst")
local workspace = game:GetService("Workspace")
local fightEvent = ReplicatedStorage:WaitForChild("FightState")

local playerStart = ReplicatedStorage:WaitForChild("PlayerStart")
local opponentStart = ReplicatedStorage:WaitForChild("OpponentStart")
local dummyTemplate = ReplicatedFirst:WaitForChild("Dummies"):FindFirstChild("Dummy")

local triggerPart = workspace:WaitForChild("FightTriggerPart")

local function setupPrompt(part)
	local prompt = part:FindFirstChildWhichIsA("ProximityPrompt")
	if not prompt then warn("Missing ProximityPrompt!"); return end

	prompt.Triggered:Connect(function(player)
		local char = player.Character
		local hrp = char and char:FindFirstChild("HumanoidRootPart")
		if not hrp then return end

		hrp.CFrame = CFrame.new(playerStart.Value)

		if dummyTemplate then
			local newDummy = dummyTemplate:Clone()
			newDummy:PivotTo(CFrame.new(opponentStart.Value))
			newDummy.Parent = workspace
		else
			warn("Dummy missing")
		end

		task.delay(0.2, function()
			fightEvent:FireClient(player, true)
		end)
	end)
end

setupPrompt(triggerPart)

1 Like

I cant test rn but my best guess is

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")

local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
character.PrimaryPart = rootPart

local fightEvent = ReplicatedStorage:WaitForChild("FightState")
local playerStart = ReplicatedStorage:WaitForChild("PlayerStart") -- Vector3Value

-- Load animations
local animator = humanoid:WaitForChild("Animator")

local function loadAnimation(id)
	local anim = Instance.new("Animation")
	anim.AnimationId = "rbxassetid://" .. id
	return animator:LoadAnimation(anim)
end

local walkFrontTrack = loadAnimation("111437686490686") -- Replace with correct ID
local walkBackTrack = loadAnimation("71507897049072") -- Replace with correct ID
local idleTrack = loadAnimation("134052246679083") -- Replace with correct ID


-- Movement config
local moveSpeed = 8
local moveVelocity = 0
local direction = 0
local keysPressed = { A = false, D = false }
local enabled = false

-- Animation control
local function updateAnimation()
	if math.abs(moveVelocity) < 0.05 then
		if not idleTrack.IsPlaying then
			walkFrontTrack:Stop()
			walkBackTrack:Stop()
			idleTrack:Play()
		end
	elseif moveVelocity > 0 then
		if not walkFrontTrack.IsPlaying then
			idleTrack:Stop()
			walkBackTrack:Stop()
			walkFrontTrack:Play()
		end
	elseif moveVelocity < 0 then
		if not walkBackTrack.IsPlaying then
			idleTrack:Stop()
			walkFrontTrack:Stop()
			walkBackTrack:Play()
		end
	end
end

-- Facing logic
local function updateFacing()
	if direction ~= 0 then
		local facingAngle = direction == -1 and math.rad(90) or math.rad(-90)
		local pos = rootPart.Position
		character:SetPrimaryPartCFrame(CFrame.new(pos.X, pos.Y, playerStart.Value.Z) * CFrame.Angles(0, facingAngle, 0))
	end
end

UserInputService.InputBegan:Connect(function(input, gpe)
	if gpe or not enabled then return end
	if input.KeyCode == Enum.KeyCode.A then
		keysPressed.A = true
	elseif input.KeyCode == Enum.KeyCode.D then
		keysPressed.D = true
	end
end)

UserInputService.InputEnded:Connect(function(input)
	if not enabled then return end
	if input.KeyCode == Enum.KeyCode.A then
		keysPressed.A = false
	elseif input.KeyCode == Enum.KeyCode.D then
		keysPressed.D = false
	end
end)

RunService.RenderStepped:Connect(function(dt)
	if not enabled then return end

	if keysPressed.A and not keysPressed.D then
		direction = -1
	elseif keysPressed.D and not keysPressed.A then
		direction = 1
	else
		direction = 0
	end

	moveVelocity = direction * moveSpeed
	humanoid:Move(Vector3.new(moveVelocity, 0, 0), true)

	updateFacing()
	updateAnimation()
end)

fightEvent.OnClientEvent:Connect(function(state)
	enabled = state
	if not state then
		moveVelocity = 0
		keysPressed = { A = false, D = false }
		walkFrontTrack:Stop()
		walkBackTrack:Stop()
		idleTrack:Play()
	end
end)

word count gagagagagagagagagagagaga

Thanks that helped

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.