Hello. I am currently making a movement system for a game. Idk what the game is gonna be yet, but I have what I think to be a decent movement system implemented. Granted, I am biased since I made it and know how everything works and the best ways to go fast and not hit walls and such. The black square is a trampoline. It’s there so u can gain speed quickly.
The 2 UI elements are for speed; the top, smaller one is your horizontal speed and the bottom, bigger one is your total speed (horizontal and vertical).
Also, if you are a scripter, please give me feedback on my script (variable/function names, optimizations, features). The script is located under StarterCharacterScripts
and is called “Movement”. Note that this is a very ugly and poorly written script. I do not feel like making a script pretty if I’m not sure I’m going to implement all of the features currently present in it.
There is also some background music because I got bored play testing and wanted something to listen to.
Place file:
movement showcase.rbxl (94.2 KB)
Movement code if u don’t wanna download the place:
local TS = game:GetService("TweenService")
local char: Model = script.Parent
local humanoid: Humanoid = char.Humanoid
local hrp: Part = char:FindFirstChild("HumanoidRootPart")
local torso: Part = char:FindFirstChild("Torso") or char:FindFirstChild("UpperTorso")
--speeds
--set to 0 for no walking and only sprinting (not recommended, instead set it to 16 or so for better movement)
local DEFAULT_SPEED = game:GetService("StarterPlayer").CharacterWalkSpeed
local SPRINT_SPEED = 50
local MAX_SPEED = 200 --math.huge for infinity/no max speed
local BODY_VELOCITY_TIME = 0.3 --amount of time the BodyVelocity impacts the player after they jump for
local BUNNY_HOP_SPEED_MULTIPLIER = 1.2 --recommended: 1.2
local FREEFALL_SPEED_MULTIPLIER = 1.5
--amount of time, in seconds, that a player can be on the ground for and still gain speed if they jump again
local BUNNY_HOP_GRACE_PERIOD = 0.2
local SPRINT_TIME = 2 --amount of time, in seconds, that the SPRINT_SPEED takes to reach from DEFAULT_SPEED
local SLOW_DOWN_TIME = 0.6
local WALL_BOUNCE_SPEED_MULTIPLIER = 1
local speedTweenPlaying = false
local slowTweenPlaying = false
local bunnyHopping = true
local running = false
local timeSinceLanded = 0
local timeSinceJump = math.huge
local timeAirborne = math.huge
local justEnteredFreefall = false
local freefallTweenComplete = true
local freefallTween: Tween = nil
local gui = game:GetService("Players").LocalPlayer.PlayerGui:WaitForChild("ScreenGui")
local totalSpeedLabel = gui:WaitForChild("Total Speed")
local horizontalSpeedLabel = gui:WaitForChild("Horizontal Speed")
local function roundNum(num: number): string
local s = tostring(num)
local dot = s:find("%.")
return s:sub(1, dot and dot+1 or #s)
end
local function isPlayerJumping()
return humanoid:GetState() == Enum.HumanoidStateType.Jumping
end
local function isPlayerRunning()
return humanoid.MoveDirection.Magnitude > 0
end
local function slowDown()
TS:Create(humanoid, TweenInfo.new(SLOW_DOWN_TIME, Enum.EasingStyle.Quart, Enum.EasingDirection.In), {["WalkSpeed"] =
running and SPRINT_SPEED or DEFAULT_SPEED}):Play()
end
humanoid.StateChanged:Connect(function(old: Enum.HumanoidStateType, new: Enum.HumanoidStateType)
if new == Enum.HumanoidStateType.Freefall then
justEnteredFreefall = true
end
if new == Enum.HumanoidStateType.Jumping then
timeSinceJump = os.clock()
end
end)
--wall bouncing
local wallDebounce = false
torso.Touched:Connect(function(hit: BasePart)
--print((hrp.AssemblyLinearVelocity * Vector3.new(1,0,1)).Magnitude)
local horizontalMomentum = (hrp.AssemblyLinearVelocity * Vector3.new(1,0,1)).Magnitude
if not wallDebounce then
if (bunnyHopping or os.clock() - timeAirborne > 0.5) and (humanoid:GetState() == Enum.HumanoidStateType.Freefall or
humanoid:GetState() == Enum.HumanoidStateType.Freefall or isPlayerJumping()) and
horizontalMomentum > SPRINT_SPEED * 0.75 then
wallDebounce = true
local params = RaycastParams.new()
params.IgnoreWater = true
params.CollisionGroup = "Player"
local ray = workspace:Raycast(torso.Position, torso.CFrame.LookVector * 3, params)
if ray and ray.Instance then
print(horizontalMomentum)
local lv = Instance.new("LinearVelocity")
lv.ForceLimitsEnabled = false
lv.RelativeTo = Enum.ActuatorRelativeTo.World
lv.VelocityConstraintMode = Enum.VelocityConstraintMode.Line
lv.LineDirection = ray.Normal
lv.LineVelocity = horizontalMomentum * WALL_BOUNCE_SPEED_MULTIPLIER
lv.Attachment0 = hrp:FindFirstChild("MovementAttachment") or hrp:FindFirstChildWhichIsA("Attachment")
lv.Parent = hrp
game:GetService("Debris"):AddItem(lv, 0.2)
end
task.wait(1)
wallDebounce = false
end
end
end)
local isBhopTweenPlaying = false
while task.wait() do
--update text (can't use `GetPropertyChangedSignal` because it doesn't fire for physics-related properties)
local currentSpeed = hrp.AssemblyLinearVelocity
local horizontalSpeed = currentSpeed * Vector3.new(1,0,1)
totalSpeedLabel.Text = roundNum(currentSpeed.Magnitude)
horizontalSpeedLabel.Text = roundNum(horizontalSpeed.Magnitude)
--sprinting
local relativeSpeedUpTime = SPRINT_TIME*(SPRINT_SPEED-humanoid.WalkSpeed)/(SPRINT_SPEED-DEFAULT_SPEED)
if isPlayerRunning() and not running then
TS:Create(humanoid, TweenInfo.new(relativeSpeedUpTime, Enum.EasingStyle.Quad, Enum.EasingDirection.In), {["WalkSpeed"] = SPRINT_SPEED}):Play()
running = true
end
if running and not isPlayerRunning() then
TS:Create(humanoid, TweenInfo.new(SLOW_DOWN_TIME, Enum.EasingStyle.Quad, Enum.EasingDirection.In), {["WalkSpeed"] = DEFAULT_SPEED}):Play()
running = false
end
--bunny hopping
if humanoid:GetState() == Enum.HumanoidStateType.Landed then
timeSinceLanded = os.clock()
if os.clock() - timeAirborne > 0.5 then
slowDown()
end
timeAirborne = math.huge
if freefallTween then freefallTween:Cancel() end
end
if justEnteredFreefall then
if humanoid:GetState() == Enum.HumanoidStateType.Freefall and os.clock() - timeSinceJump > 0.5 then
justEnteredFreefall = false
timeAirborne = os.clock()
end
end
if os.clock() - timeAirborne > 0.5 and freefallTweenComplete then
freefallTweenComplete = false
freefallTween = TS:Create(humanoid, TweenInfo.new(0.5, Enum.EasingStyle.Linear, Enum.EasingDirection.In), {["WalkSpeed"] =
math.clamp(humanoid.WalkSpeed * FREEFALL_SPEED_MULTIPLIER, SPRINT_SPEED, MAX_SPEED)})
freefallTween:Play()
freefallTween.Completed:Connect(function()
freefallTweenComplete = true
end)
end
if isPlayerJumping() and running and humanoid.WalkSpeed >= SPRINT_SPEED - 0.5 and
horizontalSpeed.Magnitude >= SPRINT_SPEED - 0.5 then
if os.clock() - timeSinceLanded < BUNNY_HOP_GRACE_PERIOD then
TS:Create(humanoid, TweenInfo.new(0.6, Enum.EasingStyle.Quart, Enum.EasingDirection.In), {["WalkSpeed"] =
math.clamp(humanoid.WalkSpeed * BUNNY_HOP_SPEED_MULTIPLIER, SPRINT_SPEED, MAX_SPEED)}):Play()
local lv = Instance.new("LinearVelocity")
lv.ForceLimitsEnabled = true
lv.ForceLimitMode = Enum.ForceLimitMode.PerAxis
lv.MaxAxesForce = Vector3.new(1,0,1) * 2e3
lv.VelocityConstraintMode = Enum.VelocityConstraintMode.Vector
lv.VectorVelocity = humanoid.MoveDirection * humanoid.WalkSpeed
lv.Attachment0 = hrp:FindFirstChild("MovementAttachment") or hrp:FindFirstChildWhichIsA("Attachment")
lv.Parent = hrp
game:GetService("Debris"):AddItem(lv, BODY_VELOCITY_TIME)
bunnyHopping = true
end
continue
else
if bunnyHopping then
if humanoid:GetState() == Enum.HumanoidStateType.Freefall then continue end
if os.clock() - timeSinceLanded > BUNNY_HOP_GRACE_PERIOD or currentSpeed.Magnitude <= SPRINT_SPEED - 0.5 then
slowDown()
bunnyHopping = false
end
end
end
end