
KeylessUniversal

local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local ContextActionService = game:GetService("ContextActionService")
local TweenService = game:GetService("TweenService")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
-- --- CONFIGURATION ---
local CONFIG = {
-- Movement
DoubleJumpPower = 60,
RollDuration = 0.5,
RollDistance = 50,
BaseWalkSpeed = 16,
MaxWalkSpeed = 150,
Acceleration = 30,
BrakingDuration = 0.7,
StopThreshold = 1,
BaseFOV = 70,
MaxFOV = 120,
-- Tool
DashSpeed = 200,
DashMaxTime = 1,
-- Assets
RollAnimID = "rbxassetid://18537367238",
RunAnimID = "rbxassetid://85752365414182",
GreenCursorID = "rbxassetid://1460596350"
}
local DECELERATION = CONFIG.MaxWalkSpeed / CONFIG.BrakingDuration
-- --- STATE VARIABLES ---
local isMobileMode = false
local selectionMade = false
local currentCharacter = nil
-- --- GUI CREATION ---
local function createIntroGUI()
local existing = player:WaitForChild("PlayerGui"):FindFirstChild("MaldixIntroGUI")
if existing then existing:Destroy() end
local screenGui = Instance.new("ScreenGui")
screenGui.Name = "MaldixIntroGUI"
screenGui.Parent = player:WaitForChild("PlayerGui")
screenGui.ResetOnSpawn = false
local frame = Instance.new("Frame")
frame.Name = "MainFrame"
frame.Size = UDim2.new(0, 400, 0, 350)
frame.Position = UDim2.new(0.5, 0, 0.5, 0)
frame.AnchorPoint = Vector2.new(0.5, 0.5)
frame.BackgroundColor3 = Color3.new(0.14, 0.14, 0.14)
frame.BorderSizePixel = 0
frame.Parent = screenGui
local uiCorner = Instance.new("UICorner")
uiCorner.CornerRadius = UDim.new(0, 12)
uiCorner.Parent = frame
local header = Instance.new("TextLabel")
header.Text = "Maldix's Sonic Script"
header.Size = UDim2.new(1, 0, 0, 50)
header.BackgroundTransparency = 1
header.TextColor3 = Color3.new(0.33, 1, 0.5)
header.Font = Enum.Font.FredokaOne
header.TextSize = 28
header.Parent = frame
local desc = Instance.new("TextLabel")
desc.Text = [[
Controls:
• WASD / Joystick: Move (Accelerate)
• Space: Jump (Double tap to Double Jump)
• R / Button: Roll (Spam to go fast)
• Dash Tool: Click in air to Homing Dash
Please select your device type:
]]
desc.Size = UDim2.new(1, -40, 0, 200)
desc.Position = UDim2.new(0, 20, 0, 50)
desc.BackgroundTransparency = 1
desc.TextColor3 = Color3.new(0.86, 0.86, 0.86)
desc.Font = Enum.Font.GothamMedium
desc.TextSize = 16
desc.TextXAlignment = Enum.TextXAlignment.Left
desc.TextYAlignment = Enum.TextYAlignment.Top
desc.TextWrapped = true
desc.Parent = frame
local btnPC = Instance.new("TextButton")
btnPC.Name = "PCButton"
btnPC.Text = "PC"
btnPC.Size = UDim2.new(0.4, 0, 0, 50)
btnPC.Position = UDim2.new(0.05, 0, 1, -60)
btnPC.BackgroundColor3 = Color3.new(0.23, 0.23, 0.23)
btnPC.TextColor3 = Color3.new(1, 1, 1)
btnPC.Font = Enum.Font.GothamBold
btnPC.TextSize = 18
btnPC.Parent = frame
local btnCorner1 = Instance.new("UICorner")
btnCorner1.CornerRadius = UDim.new(0, 8)
btnCorner1.Parent = btnPC
local btnMobile = Instance.new("TextButton")
btnMobile.Name = "MobileButton"
btnMobile.Text = "Mobile"
btnMobile.Size = UDim2.new(0.4, 0, 0, 50)
btnMobile.Position = UDim2.new(0.55, 0, 1, -60)
btnMobile.BackgroundColor3 = Color3.new(0.23, 0.23, 0.23)
btnMobile.TextColor3 = Color3.new(1, 1, 1)
btnMobile.Font = Enum.Font.GothamBold
btnMobile.TextSize = 18
btnMobile.Parent = frame
local btnCorner2 = Instance.new("UICorner")
btnCorner2.CornerRadius = UDim.new(0, 8)
btnCorner2.Parent = btnMobile
local function closeGui()
screenGui:Destroy()
end
btnPC.MouseButton1Click:Connect(function()
isMobileMode = false
selectionMade = true
closeGui()
end)
btnMobile.MouseButton1Click:Connect(function()
isMobileMode = true
selectionMade = true
closeGui()
end)
end
-- --- MAIN LOGIC ---
local function onCharacterAdded(character)
currentCharacter = character
local humanoid = character:WaitForChild("Humanoid")
local rootPart = character:WaitForChild("HumanoidRootPart")
local animator = humanoid:WaitForChild("Animator")
humanoid.WalkSpeed = CONFIG.BaseWalkSpeed
local currentSpeed = CONFIG.BaseWalkSpeed
local lastMoveDirection = Vector3.new(0, 0, -1)
-- --- ANIMATIONS ---
local runAnim = Instance.new("Animation")
runAnim.AnimationId = CONFIG.RunAnimID
local runTrack = animator:LoadAnimation(runAnim)
runTrack.Priority = Enum.AnimationPriority.Movement
runTrack.Looped = true
local rollAnim = Instance.new("Animation")
rollAnim.AnimationId = CONFIG.RollAnimID
local rollTrack = animator:LoadAnimation(rollAnim)
rollTrack.Priority = Enum.AnimationPriority.Action
rollTrack.Looped = true
local jumpAnim = Instance.new("Animation")
jumpAnim.AnimationId = CONFIG.RollAnimID
local jumpTrack = animator:LoadAnimation(jumpAnim)
jumpTrack.Priority = Enum.AnimationPriority.Action
jumpTrack.Looped = false
-- --- TOOL SETUP ---
local tool = Instance.new("Tool")
tool.Name = "Dash Cursor"
tool.RequiresHandle = false
tool.CanBeDropped = false
tool.Parent = player.Backpack
local mouse = player:GetMouse()
tool.Equipped:Connect(function() mouse.Icon = CONFIG.GreenCursorID end)
tool.Unequipped:Connect(function() mouse.Icon = "" end)
tool.Activated:Connect(function()
local state = humanoid:GetState()
local isInAir = (state == Enum.HumanoidStateType.Freefall or state == Enum.HumanoidStateType.Jumping)
if isInAir then
local targetPos = mouse.Hit.Position
local startPos = rootPart.Position
local direction = (targetPos - startPos).Unit
local distance = (targetPos - startPos).Magnitude
local duration = math.min(distance / CONFIG.DashSpeed, CONFIG.DashMaxTime)
rollTrack:Play()
local bv = Instance.new("BodyVelocity")
bv.Velocity = direction * CONFIG.DashSpeed
bv.MaxForce = Vector3.new(1e5, 1e5, 1e5)
bv.P = 10000
bv.Parent = rootPart
local bg = Instance.new("BodyGyro")
bg.CFrame = CFrame.lookAt(startPos, targetPos)
bg.MaxTorque = Vector3.new(1e5, 1e5, 1e5)
bg.P = 20000
bg.Parent = rootPart
task.delay(duration, function()
if bv then bv:Destroy() end
if bg then bg:Destroy() end
rollTrack:Stop()
rootPart.AssemblyLinearVelocity = Vector3.zero
end)
end
end)
-- --- DOUBLE JUMP ---
local hasDoubleJumped = false
local canTriggerDoubleJump = false
humanoid.StateChanged:Connect(function(oldState, newState)
if newState == Enum.HumanoidStateType.Landed then
hasDoubleJumped = false
canTriggerDoubleJump = false
elseif newState == Enum.HumanoidStateType.Jumping then
canTriggerDoubleJump = false
task.wait(0.2)
canTriggerDoubleJump = true
elseif newState == Enum.HumanoidStateType.Freefall then
if oldState == Enum.HumanoidStateType.Landed then
canTriggerDoubleJump = true
end
end
end)
UserInputService.JumpRequest:Connect(function()
local state = humanoid:GetState()
local isInAir = (state == Enum.HumanoidStateType.Freefall or state == Enum.HumanoidStateType.Jumping)
if canTriggerDoubleJump and not hasDoubleJumped and isInAir then
hasDoubleJumped = true
rootPart.AssemblyLinearVelocity = Vector3.new(rootPart.AssemblyLinearVelocity.X, CONFIG.DoubleJumpPower, rootPart.AssemblyLinearVelocity.Z)
jumpTrack:Stop()
jumpTrack:Play()
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
end)
-- --- ROLL LOGIC ---
local rolling = false
local holdingRollKey = false
local function stopRolling()
rolling = false
rollTrack:Stop()
end
local function performRoll()
local direction = rootPart.CFrame.LookVector
local startPos = rootPart.Position
local targetPos = startPos + (direction * CONFIG.RollDistance)
local startTime = tick()
local connection
connection = RunService.RenderStepped:Connect(function()
local elapsed = tick() - startTime
if elapsed > CONFIG.RollDuration then
connection:Disconnect()
if holdingRollKey then performRoll() else stopRolling() end
return
end
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = {character}
rayParams.FilterType = Enum.RaycastFilterType.Exclude
local rayResult = workspace:Raycast(rootPart.Position, direction * 3, rayParams)
if rayResult and rayResult.Instance.CanCollide then
connection:Disconnect()
stopRolling()
return
end
local alpha = elapsed / CONFIG.RollDuration
local nextPos = startPos:Lerp(targetPos, alpha)
rootPart.CFrame = CFrame.new(nextPos, nextPos + direction)
end)
end
local function startRoll()
if rolling then return end
rolling = true
rollTrack:Play()
performRoll()
end
-- Define Input Handler
local function handleRollInput(actionName, inputState)
if inputState == Enum.UserInputState.Begin then
holdingRollKey = true
startRoll()
elseif inputState == Enum.UserInputState.End then
holdingRollKey = false
end
end
-- Function to bind controls based on current selection
local function bindControls()
ContextActionService:UnbindAction("RollAction")
-- Bind R key always, add TouchButton only if mobile
ContextActionService:BindAction("RollAction", handleRollInput, isMobileMode, Enum.KeyCode.R)
if isMobileMode then
ContextActionService:SetTitle("RollAction", "Roll")
-- Moved to Left Side (0.15 = 15% from left edge)
ContextActionService:SetPosition("RollAction", UDim2.new(0.15, 0, 0.6, 0))
end
end
-- Watch for selection change if not yet made
task.spawn(function()
while not selectionMade do
task.wait(0.5)
end
bindControls()
end)
if selectionMade then
bindControls()
end
-- --- MOVEMENT LOOP ---
local function getUserInputVector()
local moveVector = Vector3.new(0, 0, 0)
-- Explicit assignment used to prevent compiler errors
if UserInputService:IsKeyDown(Enum.KeyCode.W) then moveVector = moveVector + Vector3.new(0,0,-1) end
if UserInputService:IsKeyDown(Enum.KeyCode.S) then moveVector = moveVector + Vector3.new(0,0,1) end
if UserInputService:IsKeyDown(Enum.KeyCode.A) then moveVector = moveVector + Vector3.new(-1,0,0) end
if UserInputService:IsKeyDown(Enum.KeyCode.D) then moveVector = moveVector + Vector3.new(1,0,0) end
local success, module = pcall(function() return require(player.PlayerScripts.PlayerModule) end)
if success and module then
local controls = module:GetControls()
if controls then
local touchMove = controls:GetMoveVector()
if touchMove.Magnitude > 0 then moveVector = touchMove end
end
end
return moveVector
end
RunService.RenderStepped:Connect(function(dt)
local inputVector = getUserInputVector()
local isInputting = inputVector.Magnitude > 0.1
if isInputting then
if rootPart.AssemblyLinearVelocity.Magnitude > 1 then
lastMoveDirection = Vector3.new(rootPart.AssemblyLinearVelocity.X, 0, rootPart.AssemblyLinearVelocity.Z).Unit
else
lastMoveDirection = rootPart.CFrame.LookVector
end
currentSpeed = math.min(currentSpeed + (CONFIG.Acceleration * dt), CONFIG.MaxWalkSpeed)
humanoid.WalkSpeed = currentSpeed
else
if currentSpeed > CONFIG.BaseWalkSpeed then
currentSpeed = math.max(currentSpeed - (DECELERATION * dt), CONFIG.BaseWalkSpeed)
humanoid.WalkSpeed = currentSpeed
humanoid:Move(lastMoveDirection, false)
else
currentSpeed = CONFIG.BaseWalkSpeed
humanoid.WalkSpeed = CONFIG.BaseWalkSpeed
end
end
local velocityMag = Vector3.new(rootPart.AssemblyLinearVelocity.X, 0, rootPart.AssemblyLinearVelocity.Z).Magnitude
local intensity = math.clamp((velocityMag - CONFIG.BaseWalkSpeed) / (CONFIG.MaxWalkSpeed - CONFIG.BaseWalkSpeed), 0, 1)
local targetFOV = CONFIG.BaseFOV + (intensity * (CONFIG.MaxFOV - CONFIG.BaseFOV))
camera.FieldOfView = camera.FieldOfView + (targetFOV - camera.FieldOfView) * math.clamp(dt * 5, 0, 1)
if velocityMag > 1 then
if not runTrack.IsPlaying then runTrack:Play() end
runTrack:AdjustSpeed(0.5 + (intensity * 2))
else
if runTrack.IsPlaying then runTrack:Stop() end
end
end)
end
-- Init
createIntroGUI()
if player.Character then
onCharacterAdded(player.Character)
end
player.CharacterAdded:Connect(onCharacterAdded)



kinda buggy but it works ig
@darkbeing yeah it is
@wokhard213 i made it(chatgpt) in like 15 minutes
chat gpt scripts suck
@robloxtestinm63_hack i cant code for *
Please make mobile buttons but it’s so good I can’t use it but I do in script builder
@Carino i update