Untitled
Anonymous
plain_text
02/20/2026 5:12 PM
5.3 KB
19
Indexable
local ContextActionService = game:GetService("ContextActionService")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local GuiService = game:GetService("GuiService")
local player = Players.LocalPlayer
local mouse = player:GetMouse()
-- Tuning
local MAX_SPEED, ACCEL, DRAG = 200, 200, 0.5
local TURN_RESP, TURN_180 = 20, true
local WALL_CHECK_DIST = 5.5
local STICK_RADIUS = 150
local DEADZONE = 10
local moving, vel = false, Vector3.zero
-- Mobile UI Setup
local screenGui = player:WaitForChild("PlayerGui"):WaitForChild("MobileControls")
local Stick = screenGui:WaitForChild("Stick")
-- AUTO-HIDE UI FOR PC
local function updateUI()
if UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled then
screenGui.Enabled = true
else
screenGui.Enabled = false
end
end
updateUI()
local function getChar()
local char = player.Character
return char, char and char:FindFirstChild("HumanoidRootPart")
end
local function canControl(char, hrp)
return char and hrp and char.Parent == workspace and not char:GetAttribute("Dead")
end
-- PC Keybinds
ContextActionService:BindAction("Move", function(_, state)
moving = (state == Enum.UserInputState.Begin)
end, false, Enum.KeyCode.W, Enum.UserInputType.MouseButton1)
-- Wall slide logic
local function applyWallSlide(hrp, currentVel)
if currentVel.Magnitude < 0.1 then return Vector3.zero end
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {hrp.Parent, workspace:FindFirstChild("Enemies"), workspace:FindFirstChild("Projectiles")}
local result = workspace:Raycast(hrp.Position, currentVel.Unit * WALL_CHECK_DIST, params)
if result and math.abs(result.Normal.Y) < 0.5 then
local dot = currentVel:Dot(result.Normal)
if dot < 0 then
currentVel = currentVel - (result.Normal * dot)
currentVel *= 0.9
end
end
return Vector3.new(currentVel.X, 0, currentVel.Z)
end
RunService.RenderStepped:Connect(function(dt)
local char, hrp = getChar()
if not canControl(char, hrp) then return end
local moveDirection = Vector3.zero
local isTouch = UserInputService.TouchEnabled
-- INPUT LOGIC
if not isTouch or UserInputService.KeyboardEnabled then
-- PC: Use Mouse for Rotation
local target = Vector3.new(mouse.Hit.X, hrp.Position.Y, mouse.Hit.Z)
local dir = (target - hrp.Position)
if dir.Magnitude > 0.1 then
local yRot = math.atan2(dir.X, dir.Z)
local targetRot = CFrame.new(hrp.Position) * CFrame.Angles(0, yRot + (TURN_180 and math.pi or 0), 0)
hrp.CFrame = hrp.CFrame:Lerp(targetRot, math.clamp(TURN_RESP * dt, 0, 1))
end
if moving then moveDirection = hrp.CFrame.LookVector end
else
-- MOBILE: Use Stick
local inset = GuiService:GetGuiInset()
local rawTouchPos = UserInputService:GetMouseLocation()
local touchPos = rawTouchPos - inset
local stickCenter = Stick.AbsolutePosition + (Stick.AbsoluteSize / 2)
local diff = Vector2.new(touchPos.X - stickCenter.X, touchPos.Y - stickCenter.Y)
local isPressing = UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1)
-- Only move if pressing and outside deadzone
if isPressing and diff.Magnitude > DEADZONE and diff.Magnitude < STICK_RADIUS then
-- Normalized 270-degree rotation logic
moveDirection = Vector3.new(-diff.Y, 0, diff.X).Unit
local yRot = math.atan2(-diff.Y, diff.X)
local targetRot = CFrame.new(hrp.Position) * CFrame.Angles(0, yRot + math.pi, 0)
hrp.CFrame = hrp.CFrame:Lerp(targetRot, math.clamp(TURN_RESP * dt, 0, 1))
end
end
-- Movement Physics
if moveDirection.Magnitude > 0 then
vel += moveDirection * (ACCEL * dt)
end
vel -= vel * math.clamp(DRAG * dt, 0, 1)
if vel.Magnitude > MAX_SPEED then vel = vel.Unit * MAX_SPEED end
vel = applyWallSlide(hrp, vel)
hrp.AssemblyLinearVelocity = Vector3.new(vel.X, 0, vel.Z)
hrp.AssemblyAngularVelocity = Vector3.zero
end)Editor is loading...
Leave a Comment