-- Player Movement Script --
-- Derived from CS:S Source Code --
local runService = game:GetService("RunService")
local modules = game.ReplicatedStorage.Modules
local velocity = require(modules.Velocity):Init(true)
local inputs = velocity:GetService("InputService")
-- movement variables
local moveSpeed = 1000
local runAccel = 10
local runDeaccel = 1000
local airAccel = 7.5
local airDeaccel = 7.5
local sideStrafeAccel = 100
local sideStrafeSpeed = 100
local jumpSpeed = 16
local holdJumpToBhop = true
local gravity = 50
local friction = 5
-- vectors for movment
local playerVel = Vector3.new(0, 0, 0)
-- variable to check if player is on ground
local grounded = false
-- thing to queue jumps
local wishJump = false
local canJump = true
local jumpBuffer = 0.1
-- contains inputs for character
local command = {
forwardMove = 0;
rightMove = 0;
upmove = 0;
space = false;
justPressed = false;
}
local enumBinds = {
[1] = "One";
[2] = "Two";
[3] = "Three";
}
-- player variables
local player = game.Players.LocalPlayer
local camera = workspace.CurrentCamera
local character = player.Character
local humanoidRootPart = character.HumanoidRootPart
-- create body velocity to control the player
local bodyVel = Instance.new("BodyVelocity", humanoidRootPart)
bodyVel.MaxForce = Vector3.new(100000, 0, 100000)
-- input stuff
local function onUp(toggle)
if toggle then command.forwardMove = -1 else if command.forwardMove ~= 1 then command.forwardMove = 0 end end
end
local function onRight(toggle)
if toggle then command.rightMove = 1 else if command.rightMove ~= -1 then command.rightMove = 0 end end
end
local function onDown(toggle)
if toggle then command.forwardMove = 1 else if command.forwardMove ~= -1 then command.forwardMove = 0 end end
end
local function onLeft(toggle)
if toggle then command.rightMove = -1 else if command.rightMove ~= 1 then command.rightMove = 0 end end
end
local function onSpace(toggle)
if toggle then command.space = true command.justPressed = true else command.space = false command.justPressed = false end
end
-- movement inputs
inputs.BindOnBegan(nil, "W", function() onUp(true) end, "Up : True")
inputs.BindOnEnded(nil, "W", function() onUp(false) end, "Up : False")
inputs.BindOnBegan(nil, "A", function() onLeft(true) end, "Left : True")
inputs.BindOnEnded(nil, "A", function() onLeft(false) end, "Left : False")
inputs.BindOnBegan(nil, "S", function() onDown(true) end, "Down : True")
inputs.BindOnEnded(nil, "S", function() onDown(false) end, "Down : False")
inputs.BindOnBegan(nil, "D", function() onRight(true) end, "Right : True")
inputs.BindOnEnded(nil, "D", function() onRight(false) end, "Right : False")
inputs.BindOnBegan(nil, "Space", function() onSpace(true) end, "Jump : True")
inputs.BindOnEnded(nil, "Space", function() onSpace(false) end, "Jump : False")
-- call every frame
local function update(dt)
-- queue jump function
queueJump()
grounded = checkGround()
-- update move speed to humanoid walk speed
moveSpeed = character.Humanoid.WalkSpeed
-- check if grounded to decide function
if grounded then
groundMove()
else
airMove()
end
-- move the player
bodyVel.Velocity = playerVel * dt
end
local updateFunction = runService.RenderStepped:Connect(update)
character.Humanoid.Died:Connect(function()
bodyVel:Destroy()
updateFunction:Disconnect()
end)
function queueJump()
if holdJumpToBhop then
wishJump = command.space
return
end
if command.space and not wishJump and command.justPressed then
wishJump = true
command.justPressed = false
end
if not command.space then
wishJump = false
end
end
function checkGround()
local ray = Ray.new(humanoidRootPart.Position, Vector3.new(0, -3.25, 0))
local hit, hitPos = workspace:FindPartOnRayWithIgnoreList(ray, {character})
if hit then
return true
end
return false
end
function airMove()
if command.forwardMove ~= 0 then
applyFriction(1)
end
local accel
local cameraCFrame = camera.CFrame
local inputVel = Vector3.new(command.rightMove, 0, command.forwardMove)
local wishDir = cameraCFrame:VectorToWorldSpace(inputVel)
wishDir = Vector3.new(wishDir.X, 0, wishDir.Z)
local wishSpeed = wishDir.Magnitude
wishSpeed *= moveSpeed
if wishDir ~= Vector3.new(0, 0, 0) then
wishDir = wishDir.Unit
end
if playerVel:Dot(wishDir) < 0 then
accel = airDeaccel
else
accel = airAccel
end
if command.forwardMove == 0 and command.rightMove ~= 0 then
if wishSpeed > sideStrafeSpeed then
wishSpeed = sideStrafeSpeed
end
accel = sideStrafeAccel
end
accelerate(wishDir, wishSpeed, accel)
humanoidRootPart.Velocity = Vector3.new(humanoidRootPart.Velocity.X, humanoidRootPart.Velocity.Y - gravity * runService.Heartbeat:Wait(), humanoidRootPart.Velocity.Z)
end
function groundMove()
if not wishJump and canJump then
applyFriction(1)
else
applyFriction(0)
end
local cameraCFrame = camera.CFrame
local inputVel = Vector3.new(command.rightMove, 0, command.forwardMove)
local wishDir = cameraCFrame:VectorToWorldSpace(inputVel)
wishDir = Vector3.new(wishDir.X, 0, wishDir.Z)
if wishDir ~= Vector3.new(0, 0, 0) then
wishDir = wishDir.Unit
end
local wishSpeed = wishDir.Magnitude
wishSpeed *= moveSpeed
accelerate(wishDir, wishSpeed, runAccel)
playerVel = Vector3.new(playerVel.X, 0, playerVel.Z)
if wishJump and canJump then
jumpSpeed = character.Humanoid.JumpPower
humanoidRootPart.Velocity = Vector3.new(humanoidRootPart.Velocity.X, jumpSpeed, humanoidRootPart.Velocity.Z)
wishJump = false
canJump = false
local co = coroutine.create(function()
local begin = tick()
while tick() - begin < jumpBuffer do
wait()
end
canJump = true
end)
coroutine.resume(co)
end
end
function applyFriction(t)
local vec = Vector3.new(playerVel.X, 0, playerVel.Z)
local speed = vec.Magnitude
local drop = 0
local control = 0
control = speed < runDeaccel and runDeaccel or speed
drop = control * friction * runService.Heartbeat:Wait() * t
local newspeed = speed - drop
if newspeed < 0 then
newspeed = 0
end
if speed > 0 then
newspeed /= speed
end
local x = playerVel.X * newspeed
local z = playerVel.Z * newspeed
playerVel = Vector3.new(x, 0, z)
end
function accelerate(wishDir, wishSpeed, accel)
local currentspeed = playerVel:Dot(wishDir)
local addSpeed = wishSpeed - currentspeed
if addSpeed <= 0 then return end
local accelSpeed = accel * runService.Heartbeat:Wait() * wishSpeed
if accelSpeed > addSpeed then
accelSpeed = addSpeed
end
local x = playerVel.X + accelSpeed * wishDir.X
local z = playerVel.Z + accelSpeed * wishDir.Z
playerVel = Vector3.new(x, 0, z)
end
Things to Note:
- Set the player and all of the map to have no friction
- The input system uses this module:
https://www.roblox.com/library/4814957268/Velocity-Customized - I have this script put in StarterCharacterScripts
- Make sure your Humanoid’s Walkspeed is around 1000
You can test out the game I use this for here:
https://www.roblox.com/games/5528985075/Trigger-Happy?refPageId=05c909cf-f667-4c3f-ad3f-9a7cab3f41d3
NEW VERSION
I highly recommend you use my update code, link is here: New Bunny Hoppy Movement Code