New Bunny Hoppy Movement Code

What sort of script are you using? It has to be a local script

It’s a local script yes, but it only works if the ControlScript isn’t there

Did you copy and paste the code in the original post, or did you use the linked model

I used the linked model and only edited the speed values in the variables

Does anyone know why UIS in other scripts dont work why this is on?

Let me see your script. If you are using the UserInputService you might have something that looks like this:

local UserInputService = game:GetService("UserInputService")

local function onInputBegan(input, gameProcessed)
  if not gameProcessed then
    if input.KeyCode == Enum.KeyCode.C then
      -- do sliding stuff
    end
  end
end
UserInputService.InputBegan:Connect(onInputBegan)

Since I have already used the ContextActionService in my own script to bind C to crouch, your UserInputService script won’t run because the variable gameProcessed would be true.

If that is not the case, then I am not sure what the problem is. Like I said let me see your script and I can help you out!

Yeah, part of my script looks like this.

UserInputService.InputBegan:Connect(function (i, gPE) if gPE then return end

Sorry for the late reply. And how do I format my code here, like you did? First time replying to a post, sorry

Yep so you can either remove the gPE variable from your script, or you could edit my script and make crouching do different stuff, but using the same input system I used in my script.

Anyways, to format your code in the devforum you click the “</>” button

1 Like

how would i go about making it work for w because when i press w when jump it slows me down but i dont want it to

nevermind i Figured it out i just had to get rid of the apply friction if forward move ~= 0

if someone else also wants this result copy this local ContextActionService = game:GetService(“ContextActionService”)
local RunService = game:GetService(“RunService”)

local player = game:GetService(“Players”).LocalPlayer
local camera = workspace.CurrentCamera

local character
local humanoidRootPart
local humanoid
local groundCheck

player.CharacterAdded:Connect(function(newCharacter)

character = newCharacter
humanoidRootPart = character:WaitForChild("HumanoidRootPart")
humanoid = character:WaitForChild("Humanoid")

groundCheck = script.GroundCheck:Clone()
groundCheck.Weld.Part0 = humanoidRootPart
groundCheck.Parent = character

 runanim = humanoid.Animator:LoadAnimation(script.runanim)

end)

local Cmd = {

upMove = false;
downMove = false;

leftMove = false;
rightMove = false;

lastUp = false;
lastLeft = false;

jump = false;
justPressed = false;

crouch = false;
cjustPressed = false;

Sprint = false;
LeftShiftJustPressed = false;

}

local function onUp(actionName, inputState)

if inputState == Enum.UserInputState.Begin then

	Cmd.upMove = true
	Cmd.lastUp = true

elseif inputState == Enum.UserInputState.End then

	Cmd.upMove = false

end

end

local function onLeft(actionName, inputState)

if inputState == Enum.UserInputState.Begin then

	Cmd.leftMove = true
	Cmd.lastLeft = true

elseif inputState == Enum.UserInputState.End then

	Cmd.leftMove = false

end

end

local function onDown(actionName, inputState)

if inputState == Enum.UserInputState.Begin then

	Cmd.downMove = true
	Cmd.lastUp = false

elseif inputState == Enum.UserInputState.End then

	Cmd.downMove = false

end

end

local function onRight(actionName, inputState)

if inputState == Enum.UserInputState.Begin then

	Cmd.rightMove = true
	Cmd.lastLeft = false

elseif inputState == Enum.UserInputState.End then

	Cmd.rightMove = false

end

end

local function onJump(actionName, inputState)

if inputState == Enum.UserInputState.Begin then

	Cmd.jump = true
	Cmd.justPressed = true

elseif inputState == Enum.UserInputState.End then

	Cmd.jump = false

end

end

local function onCrouch(actionName, inputState)

if inputState == Enum.UserInputState.Begin then

	Cmd.crouch = true
	Cmd.cjustPressed = true

elseif inputState == Enum.UserInputState.End then

	Cmd.crouch = false

end

end

local function onSprint(actionName, inputState)

if inputState == Enum.UserInputState.Begin then
	game.ReplicatedStorage:WaitForChild("Sprinting").Value = true
	Cmd.Sprint = true
	Cmd.LeftShiftJustPressed = true
elseif inputState == Enum.UserInputState.End then
	game.ReplicatedStorage:WaitForChild("Sprinting").Value = false
	Cmd.Sprint = false
	runanim:Stop()
end

end

ContextActionService:BindAction(“Up”, onUp, false, “w”)
ContextActionService:BindAction(“Left”, onLeft, false, “a”)
ContextActionService:BindAction(“Down”, onDown, false, “s”)
ContextActionService:BindAction(“Right”, onRight, false, “d”)
ContextActionService:BindAction(“Jump”, onJump, false, Enum.KeyCode.Space)
ContextActionService:BindAction(“Crouch”, onCrouch, false, “c”)
ContextActionService:BindAction(“Sprint”, onSprint, false, Enum.KeyCode.LeftShift)

local moveSpeed = 30
local runAccel = 2.5
local runDeaccel = 2
local airAccel = 15
local airDeaccel = 2.5
local sideStrafeAccel = 550
local sideStrafeSpeed = 5
local ForwardStrafeSpeed = 2
local friction = 4
local airFriction = 3
local maxSpeed = 70
local SprintSpeed = 3.5 – doesnt actually = 3.5 where times the normal speed * 2 which gets us a higher value dont set above 6

local playerVel = Vector3.new(0, 0, 0)
local forwardMove = 0
local sideMove = 0

local grounded = false

local wishJump = false
local canJump = true
local jumpBuffer = 0.1
local holdJumpToBhop = true

local function Update(deltaTime)

if not humanoidRootPart then return end

if Cmd.leftMove and Cmd.rightMove then

	if Cmd.lastLeft then sideMove = -1 else sideMove = 1 end

else

	if Cmd.leftMove then sideMove = -1 elseif Cmd.rightMove then sideMove = 1 else sideMove = 0 end

end

if Cmd.upMove and Cmd.downMove then

	if Cmd.lastUp then forwardMove = -1 else forwardMove = 1 end

else

	if Cmd.upMove then forwardMove = -1 elseif Cmd.downMove then forwardMove = 1 else forwardMove = 0 end

end

QueueJump()
grounded = CheckGround()

if grounded then

	GroundMove()

else

	AirMove()

end

local newDir = Vector3.new()
if playerVel ~= Vector3.new(0, 0, 0) then newDir = playerVel.Unit end

local newSpeed = playerVel.Magnitude
newSpeed = math.clamp(newSpeed, 0, maxSpeed)

humanoid.WalkSpeed = newSpeed
humanoid:Move(newDir, false)

end

RunService.RenderStepped:Connect(Update)

function QueueJump()

if holdJumpToBhop then

	wishJump = Cmd.jump
	return

end

if Cmd.jump and not wishJump and Cmd.justPressed then

	wishJump = true
	Cmd.justPressed = false

end

if not Cmd.jump then

	wishJump = false

end

end

function CheckGround()

local connection = groundCheck.Touched:Connect(function()end)

for index, value in ipairs(groundCheck:GetTouchingParts()) do

	if value:IsA("BasePart") and value.Parent ~= character and value.CanCollide then

		connection:Disconnect()
		return true

	end

end

if humanoid:GetState() == Enum.HumanoidStateType.Climbing then

	return true

end

connection:Disconnect()
return false

end

function AirMove()

--if forwardMove ~= 0 then

	--ApplyFriction(1, true)

--end

local accel
local cameraCFrame = camera.CFrame
local inputVel = Vector3.new(sideMove, 0, 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 forwardMove == 0 and sideMove ~= 0 then

	if wishSpeed > sideStrafeSpeed then

		wishSpeed = sideStrafeSpeed

	end
	
	accel = sideStrafeAccel
	
elseif forwardMove ~= 0 and sideMove == 0 then
	if wishSpeed > ForwardStrafeSpeed then

		wishSpeed = ForwardStrafeSpeed

	end
elseif forwardMove ~=0 and sideMove ~= 0 then
	if wishSpeed > sideStrafeSpeed + ForwardStrafeSpeed then

		wishSpeed = ForwardStrafeSpeed + sideStrafeSpeed

	end
end

Accelerate(wishDir, wishSpeed, accel)

end

function GroundMove()

if not wishJump and canJump then

	ApplyFriction(1, false)

else

	ApplyFriction(0, false)

end

local cameraCFrame = camera.CFrame
local inputVel = Vector3.new(sideMove, 0, 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)


if Cmd.Sprint == true then
Sprint(wishDir, wishSpeed, runAccel)
end


playerVel = Vector3.new(playerVel.X, 0, playerVel.Z)

if wishJump and canJump and humanoid.FloorMaterial ~= Enum.Material.Air then

	humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
	wishJump = false
	canJump = false

	local co = coroutine.create(function()

		local begin = tick()

		while tick() - begin < jumpBuffer do

			RunService.Heartbeat:Wait()

		end
		canJump = true	
	end)

	coroutine.resume(co)

end

end

function ApplyFriction(t, inAir)

local vec = Vector3.new(playerVel.X, 0, playerVel.Z)
local speed = vec.Magnitude
local drop = 0
local control = 0
local newFriction = inAir and airFriction or friction

control = speed < runDeaccel and runDeaccel or speed
drop = control * newFriction * 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)
onSprint()
masterMovement()
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

function Sprint(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 * 2
	if runanim.IsPlaying == false then
		runanim:Play(accelSpeed / 2)
		if Cmd.Sprint == false then
			runanim:Stop()
		end
	end
end
local x = playerVel.X + accelSpeed * wishDir.X
local z = playerVel.Z + accelSpeed * wishDir.Z
playerVel = Vector3.new(x, 0, z)

end

function masterMovement()
if runanim.IsPlaying then
if humanoid.FloorMaterial == Enum.Material.Air then
runanim:Stop()
end
end
end

1 Like

Hey I just wanted to let you other people know this is not a bug this is intentional. In Source Engine games which is what I derived this code from, pressing W does not allow you to Bunny Hop and will slow you down to the normal movement speed. But of course if you don’t like that then your code is good!

I know its not a bug i’ve played many games that work like that but i just personally think it didnt fit with what i wanted

This is really cool. Any way to make it more like quake 3 instead of counter strike? Strafe jumping in quake 3/quake live works a little different from csgo bhopping. Idk exactly what the programming differences between the 2 would be though. In csgo you let go of W and just use A, D and your mouse to steer, but in Quake you keep W held and move your mouse to the direction you’re strafing just a little to gain momentum. Also in quake if you were to let go of W and try to bhop like in csgo it just wouldn’t work. You would continue to go in a straight line and fairly quickly lose speed.

This is pretty cool and I always wanted to add quake movement style. However I rescripted the code for cross-platform support:
https://create.roblox.com/marketplace/asset/12448751857/Quake-Movement-Style

Code (OLD)
--!strict

local MOVE_SPEED = 30
local RUN_ACCELERATION = 5
local RUN_DEACCELERATION = 5
local AIR_ACCELERATION = 2.5
local AIR_DEACCELERATION = 2.5
local SIDE_STRAFE_ACCELERATION = 100
local SIDE_STRAFE_SPEED = 1
local FRICTION = 8
local AIR_FRICTION = 3
local MAX_SPEED = 30
local JUMP_BUFFER = 0.1
local HOLD_JUMP_TO_BHOP = true

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

local function WaitForChildWhichIsA(Parent: Instance, ClassName: string, TimeOut: number?): Instance
	local Child = Parent:FindFirstChildWhichIsA(ClassName)
	if Child then
		return Child
	else
		local Connection: RBXScriptConnection?
		local Thread = coroutine.running()

		Connection = Parent.ChildAdded:Connect(function(ChildAdded: Instance)
			if ChildAdded:IsA(ClassName) then
				Child = ChildAdded
				if Connection then
					if Connection.Connected then
						Connection:Disconnect()
					end
					Connection = nil
				end
				task.spawn(Thread, Child)
			end
		end)

		if TimeOut then
			task.delay(TimeOut, function()
				if not Child then
					if Connection then
						if Connection.Connected then
							Connection:Disconnect()
						end
						Connection = nil
					end
					task.spawn(Thread, nil)
				end
			end)
		else
			task.delay(5, function()
				if not Child then
					warn(string.format("Infinite yield possible waiting on %s:FindFirstChildWhichIsA(\"%s\")", Parent:GetFullName(), ClassName))
				end
			end)
		end

		return coroutine.yield()
	end
end

local LocalPlayer = Players.LocalPlayer
if not LocalPlayer then
	Players:GetPropertyChangedSignal("LocalPlayer"):Wait()
	LocalPlayer = Players.LocalPlayer
end

local CharacterConnections: {RBXScriptConnection} = {}
local PlayerConnections: {RBXScriptConnection} = {}

local PlayerScripts = WaitForChildWhichIsA(LocalPlayer, "PlayerScripts") :: PlayerScripts
local PlayerModule = require(PlayerScripts:WaitForChild("PlayerModule")) :: any

local Controls = PlayerModule:GetControls()
local PlayerVelocity = Vector3.zero

local InputVelocity = Vector3.zero
local Humanoid: Humanoid?

local WishJump = false
local CanJump = true

local function ThumbstickCurve(X: number): number
	local K_CURVATURE = 2.0
	local K_DEADZONE = 0.15

	local function FCurve(X: number): number
		return (math.exp(K_CURVATURE * X) - 1) / (math.exp(K_CURVATURE) - 1)
	end

	local function FDeadzone(X: number): number
		return FCurve((X - K_DEADZONE) / (1 - K_DEADZONE))
	end

	return math.sign(X) * math.clamp(FDeadzone(math.abs(X)), 0, 1)
end

local function OnCharacterAdded(Character: Model)
	local NewHumanoid = WaitForChildWhichIsA(Character, "Humanoid", 5) :: Humanoid
	if NewHumanoid then
		table.insert(CharacterConnections, NewHumanoid:GetPropertyChangedSignal("Jump"):Connect(function()
			if not CanJump then
				NewHumanoid.Jump = false
			end
		end))
		Humanoid = NewHumanoid
	end
end

local function OnCharacterRemoving(_: Model)
	Humanoid = nil
	if table.getn(CharacterConnections) > 0 then
		for _, Connection in ipairs(CharacterConnections) do
			if Connection.Connected then
				Connection:Disconnect()
			end
		end
		table.clear(CharacterConnections)
	end
end

if LocalPlayer.Character then
	task.spawn(OnCharacterAdded, LocalPlayer.Character)
end
table.insert(PlayerConnections, LocalPlayer.CharacterAdded:Connect(OnCharacterAdded))
table.insert(PlayerConnections, LocalPlayer.CharacterRemoving:Connect(OnCharacterRemoving))

Players.PlayerRemoving:Connect(function(Player: Player)
	if Player == LocalPlayer then
		LocalPlayer = nil
		if table.getn(PlayerConnections) > 0 then
			for _, Connection in ipairs(PlayerConnections) do
				if Connection.Connected then
					Connection:Disconnect()
				end
			end
			table.clear(PlayerConnections)
		end
		if Player.Character then
			OnCharacterRemoving(Player.Character)
		end
	end
end)

local function QueueJump()
	if Humanoid then
		local IsJumping = if (Controls.activeController and Controls.activeController.enabled and Controls.humanoid) 
			then (if (Controls.activeController:GetIsJumping() or (Controls.touchJumpController and Controls.touchJumpController:GetIsJumping())) 
				then true 
				else false) 
			else false
		if not Humanoid:GetStateEnabled(Enum.HumanoidStateType.Jumping) and IsJumping then
			IsJumping = false
		end
		if HOLD_JUMP_TO_BHOP then
			WishJump = IsJumping
		else
			if IsJumping and not WishJump then
				WishJump = true
				if Controls.activeController then
					Controls.activeController.isJumping = false
				elseif Controls.touchJumpController then
					Controls.touchJumpController.isJumping = false
				end
			end
			if not IsJumping then
				WishJump = false
			end
		end
	end
end

local function ApplyFriction(Time: number, InAir: boolean)
	local Vector = Vector3.new(PlayerVelocity.X, 0, PlayerVelocity.Z)
	local Speed = Vector.Magnitude
	local Control = if Speed < RUN_DEACCELERATION then RUN_DEACCELERATION else Speed
	local NewFriction = if InAir then AIR_FRICTION else FRICTION
	local Drop = Control * NewFriction * RunService.Heartbeat:Wait() * Time
	local NewSpeed = Speed - Drop

	if NewSpeed < 0 then
		NewSpeed = 0
	end

	if Speed > 0 then
		NewSpeed /= Speed
	end

	local X = PlayerVelocity.X * NewSpeed
	local Z = PlayerVelocity.Z * NewSpeed
	PlayerVelocity = Vector3.new(X, 0, Z)
end

local function Accelerate(WishDirection: Vector3, WishSpeed: number, Acceleration: number)
	local Currentspeed = PlayerVelocity:Dot(WishDirection)
	local AddSpeed = WishSpeed - Currentspeed

	if AddSpeed > 0 then 
		local AccelerationSpeed = Acceleration * RunService.Heartbeat:Wait() * WishSpeed
		if AccelerationSpeed > AddSpeed then
			AccelerationSpeed = AddSpeed
		end

		local X = PlayerVelocity.X + AccelerationSpeed * WishDirection.X
		local Z = PlayerVelocity.Z + AccelerationSpeed * WishDirection.Z
		PlayerVelocity = Vector3.new(X, 0, Z)
	end
end

local function GroundMove(RelativeToCamera: boolean)
	if not WishJump and CanJump then
		ApplyFriction(1, false)
	else
		ApplyFriction(0, false)
	end
	
	local CoordinateFrame = if workspace.CurrentCamera 
		then workspace.CurrentCamera.CFrame
		else CFrame.new()

	local WishDirection = CoordinateFrame:VectorToWorldSpace(InputVelocity)
	WishDirection = if RelativeToCamera 
		then Vector3.new(WishDirection.X, 0, WishDirection.Z)
		else InputVelocity

	if WishDirection ~= Vector3.zero then
		WishDirection = WishDirection.Unit
	end

	local WishSpeed = WishDirection.Magnitude
	WishSpeed *= MOVE_SPEED

	Accelerate(
		WishDirection, 
		WishSpeed, 
		RUN_ACCELERATION
	)

	PlayerVelocity = Vector3.new(
		PlayerVelocity.X, 
		0, 
		PlayerVelocity.Z
	)
	
	if Humanoid and WishJump and CanJump then
		Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
		WishJump = false
		CanJump = false

		task.spawn(function()
			local Begin = tick()
			while tick() - Begin < JUMP_BUFFER do
				RunService.Heartbeat:Wait()
			end
			CanJump = true
		end)
	end
end

local function AirMove(RelativeToCamera: boolean)
	if InputVelocity.Z ~= 0 then
		ApplyFriction(1, true)
	end

	local CoordinateFrame = if workspace.CurrentCamera 
		then workspace.CurrentCamera.CFrame
		else CFrame.new()

	local WishDirection = CoordinateFrame:VectorToWorldSpace(InputVelocity)
	WishDirection = if RelativeToCamera 
		then Vector3.new(WishDirection.X, 0, WishDirection.Z)
		else InputVelocity
	
	local WishSpeed = WishDirection.Magnitude
	WishSpeed *= MOVE_SPEED

	if WishDirection ~= Vector3.zero then
		WishDirection = WishDirection.Unit
	end

	local Acceleration: number = if PlayerVelocity:Dot(WishDirection) < 0 
		then AIR_DEACCELERATION
		else AIR_ACCELERATION

	if InputVelocity.Z == 0 and InputVelocity.X ~= 0 then
		if WishSpeed > SIDE_STRAFE_SPEED then
			WishSpeed = SIDE_STRAFE_SPEED
		end
		Acceleration = SIDE_STRAFE_ACCELERATION
	end
	
	Accelerate(WishDirection, WishSpeed, Acceleration)
end

Controls.moveFunction = function(Player: Player, WalkDirection: Vector3, RelativeToCamera: boolean)
	RelativeToCamera = if Controls.activeController
		then Controls.activeController:IsMoveVectorCameraRelative()
		else RelativeToCamera
	if Player == LocalPlayer then
		local MoveVector = Controls:GetMoveVector()
		MoveVector = Vector3.new(
			ThumbstickCurve(MoveVector.X),
			ThumbstickCurve(MoveVector.Y),
			ThumbstickCurve(MoveVector.Z)
		)
		if MoveVector ~= InputVelocity then
			InputVelocity = MoveVector
		end
		if Humanoid then
			QueueJump()
			local Grounded = Humanoid.FloorMaterial ~= Enum.Material.Air or Humanoid:GetState() == Enum.HumanoidStateType.Climbing
			if Grounded then
				GroundMove(RelativeToCamera)
			else
				AirMove(RelativeToCamera)
			end
			
			local NewDirection = Vector3.zero
			if PlayerVelocity ~= Vector3.zero then 
				NewDirection = PlayerVelocity.Unit 
			end
			
			local NewSpeed = PlayerVelocity.Magnitude
			NewSpeed = math.clamp(NewSpeed, 0, MAX_SPEED)
			
			if Humanoid then
				Humanoid.WalkSpeed = NewSpeed
				Humanoid:Move(NewDirection, false)
			end
		end
	end
end
7 Likes

Hi, love the module so far.
What are the movement settings you use in World War Bean?

1 Like

image

2 Likes

I noticed that there is no thumbstick or jump button when using this on mobile? Does it work for mobile?

Yes it is. I used :GetMoveVector() and :GetIsJumping() from ControlModule

For some reason I keep gettings: Workspace.sharklier.ControlScript.LocalScript:173: Expected ‘else’ when parsing if then else expression, got ‘=’