The bunnyhop itself is normal, the problem is that, for a normal bunnyhop, you have to gradually press A, D and space bar. But in my case and on the video, I just pressed W and space bar, and began to gradually press A and D by myself. In another case, I can just press one of them and jump endlessly without straying.
(sorry if I explained my problem bad, lol)
Here is the video:
https://gyazo.com/ab6a33baf869e20ea75c9af6670fbfd6
And here is the module:
local Framework = {}
Framework.__index = Framework
local LOOKVECTOR_UPDATE_TICK = 0.01
local MINIMUM_VELOCITY = 0
local MAXIMUM_VELOCITY = 35
local VELOCITY_MULTIPLIER = 2
local VELOCITY_DEGRADATION = 0.1
local VELOCITY_DEGRADATION_TICK = 0.02
local CUSTOM_BODY_VELOCITY = nil
local STANDING_STILL_SAFEGUARD = true
local WALK_SPEED_TRANSITION = true
local VELOCITY_VALIDATOR_TICK = 0.7
local velocityIndex = 0
local jumpValueHolder = false
local proxy_walkspeed = 0
local initialSpeed, jumpSpeedCap = 10, 75
local maxForwardSpeed, maxBackwardsSpeed = 24, 12
local lerpRate = 0.05
local cameraMovementThreshold = 0.5
local abruptCameraMovementThreshold = 1.0
local Camera = workspace.CurrentCamera
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
function Framework.new()
local self = setmetatable({}, Framework)
self._JumpRequestConnection = nil
self._LandedRequestConnection = nil
self._loopBreakCondition = true
self._velocityObject = nil
self._jumpRequests = 0
self._renderSignal = Instance.new("BindableEvent")
self.Player = Players.LocalPlayer
self.Character = self.Player.Character or self.Player.CharacterAdded:Wait()
self.Humanoid = self.Character:WaitForChild("Humanoid")
self.HumanoidRootPart = self.Character.PrimaryPart
assert(self.Character, "Invalid character")
if CUSTOM_BODY_VELOCITY then
assert(CUSTOM_BODY_VELOCITY:IsA("BodyVelocity"), "Custom body velocity of invalid type, expected type 'BodyVelocity'")
end
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {self.Character}
self.params = params
self:Enable()
return self
end
function Framework:Enable()
local VelocityObj
self._renderSignal:Fire()
self.Humanoid.WalkSpeed = initialSpeed
if CUSTOM_BODY_VELOCITY == nil then VelocityObj = self:_createVelocityObject()
else VelocityObj = CUSTOM_BODY_VELOCITY end
self._loopBreakCondition = true
self._velocityObject = VelocityObj
self._JumpRequestConnection = UserInputService.JumpRequest:Connect(function()
if self.Humanoid.Health <= 0 then return end
if jumpValueHolder then return end
if STANDING_STILL_SAFEGUARD and self.Humanoid.MoveDirection == Vector3.new() then
velocityIndex = MINIMUM_VELOCITY
self._renderSignal:Fire() return
end
local moveDirection = self.Humanoid.MoveDirection
local facingDirection = self.HumanoidRootPart.CFrame.LookVector
local dotProduct = moveDirection:Dot(facingDirection)
if dotProduct < 0 then return end
if self.Humanoid:GetState() == Enum.HumanoidStateType.Freefall or self.Humanoid:GetState() == Enum.HumanoidStateType.Landed then
self._velocityObject.Parent = self.HumanoidRootPart
velocityIndex += (VELOCITY_MULTIPLIER * 2)
jumpValueHolder = true
self._renderSignal:Fire()
end
end)
self._LandedRequestConnection = self.Humanoid.StateChanged:Connect(function(New, Old)
if New == Enum.HumanoidStateType.Landed then
if self.Humanoid.MoveDirection.Magnitude > 0 then
if (UserInputService:IsKeyDown(Enum.KeyCode.A) or UserInputService:IsKeyDown(Enum.KeyCode.D)) then
jumpValueHolder = true
velocityIndex += (VELOCITY_MULTIPLIER * 2)
else
velocityIndex = velocityIndex * (1 - (lerpRate * 5))
warn("Decreasing velocityIndex: ", velocityIndex, "- Degradation: ", VELOCITY_DEGRADATION)
end
end
task.delay(VELOCITY_VALIDATOR_TICK, function()
if not jumpValueHolder then
velocityIndex = MINIMUM_VELOCITY
self._velocityObject.Parent = ReplicatedStorage
self._renderSignal:Fire()
end
end)
end
end)
self:_SpawnThreads()
end
function Framework:_SpawnThreads()
task.spawn(function()
while task.wait(VELOCITY_DEGRADATION_TICK) do
if not self._loopBreakCondition then break end
local moveDirection = self.Humanoid.MoveDirection
if moveDirection.Magnitude <= 0 then
velocityIndex = velocityIndex * (1 - (lerpRate / 0.5))
else
if velocityIndex > MINIMUM_VELOCITY then
velocityIndex -= VELOCITY_DEGRADATION
if velocityIndex < MINIMUM_VELOCITY then
velocityIndex = MINIMUM_VELOCITY
end
end
end
self._renderSignal:Fire()
end
end)
task.spawn(function()
local previousCameraCFrame = Camera.CFrame
local previousCameraOrientationX, previousCameraOrientationY, previousCameraOrientationZ
= previousCameraCFrame:ToEulerAnglesXYZ()
while task.wait(LOOKVECTOR_UPDATE_TICK) do
if not self._loopBreakCondition then break end
local forwardVelocity = self.HumanoidRootPart.CFrame.LookVector * velocityIndex
local lateralVelocity = self.Humanoid.MoveDirection * self.Humanoid.WalkSpeed
self._velocityObject.Velocity = forwardVelocity + lateralVelocity
local currentCameraCFrame = Camera.CFrame
local currentCameraOrientationX, currentCameraOrientationY, currentCameraOrientationZ
= currentCameraCFrame:ToEulerAnglesXYZ()
local angleDifferenceX = currentCameraOrientationX - previousCameraOrientationX
local angleDifferenceY = currentCameraOrientationY - previousCameraOrientationY
local angleDifferenceZ = currentCameraOrientationZ - previousCameraOrientationZ
local angleDifferenceMagnitude = math.sqrt(angleDifferenceX^2 + angleDifferenceY^2 + angleDifferenceZ^2)
if angleDifferenceMagnitude > abruptCameraMovementThreshold then
self.Humanoid.WalkSpeed = math.max(self.Humanoid.WalkSpeed - 1, initialSpeed)
end
previousCameraOrientationX, previousCameraOrientationY, previousCameraOrientationZ
= currentCameraOrientationX, currentCameraOrientationY, currentCameraOrientationZ
previousCameraCFrame = currentCameraCFrame
local NotInFrontOfObjectRay = workspace:Raycast(
self.HumanoidRootPart.Position,
self.HumanoidRootPart.CFrame.LookVector * 2,
self.params
)
if NotInFrontOfObjectRay and NotInFrontOfObjectRay.Instance then
velocityIndex = MINIMUM_VELOCITY
self._velocityObject.Parent = ReplicatedStorage
self._renderSignal:Fire()
end
end
end)
task.spawn(function()
while task.wait(0.01) do
local targetSpeed = initialSpeed
local moveDirection = self.Humanoid.MoveDirection
local facingDirection, rightDirection =
self.HumanoidRootPart.CFrame.LookVector, self.HumanoidRootPart.CFrame.RightVector
if moveDirection.Magnitude > 0.1 then
local forwardDotProduct = moveDirection:Dot(facingDirection)
local isPressingLeftOrRight = UserInputService:IsKeyDown(Enum.KeyCode.A)
or UserInputService:IsKeyDown(Enum.KeyCode.D)
if forwardDotProduct > 0.7 then
targetSpeed = maxForwardSpeed
if jumpValueHolder and isPressingLeftOrRight then
local potentialBunnyHopSpeed = maxForwardSpeed + (velocityIndex / 1.75)
targetSpeed = math.min(potentialBunnyHopSpeed, jumpSpeedCap)
end
elseif math.abs(forwardDotProduct) < 0.7 then
targetSpeed = maxForwardSpeed * 0.7
if jumpValueHolder and forwardDotProduct < -0.7 then
jumpValueHolder = false
end
else
targetSpeed = maxBackwardsSpeed
if jumpValueHolder then jumpValueHolder = false end
end
else targetSpeed = initialSpeed end
self.Humanoid.WalkSpeed = self.Humanoid.WalkSpeed +
(targetSpeed - self.Humanoid.WalkSpeed) * lerpRate
end
end)
task.spawn(function()
self._renderSignal.Event:Connect(function()
local PlayerGui = self.Player:WaitForChild("PlayerGui")
local GameFrame: Frame? = PlayerGui:WaitForChild("Player")["Main"].Game
local VELOCITY_RENDERER = GameFrame:WaitForChild("Velocity").Text
if VELOCITY_RENDERER then
assert(VELOCITY_RENDERER:IsA("TextLabel"), "Velocity Text Renderer invalid type! Expected: 'TextLabel'")
VELOCITY_RENDERER.Text = string.format("%0.1f", tostring(velocityIndex))
end
end)
end)
end
function Framework:Disable()
self:_terminateVelocityObject()
self._loopBreakCondition = false
self._JumpRequestConnection:Disconnect()
self._LandedRequestConnection:Disconnect()
end
function Framework:_terminateVelocityObject()
if self._velocityObject then
self._velocityObject:Destroy()
self._velocityObject = nil
end
end
function Framework:_createVelocityObject()
local BodyVelocity = Instance.new("BodyVelocity", ReplicatedStorage)
BodyVelocity.MaxForce = Vector3.new(MAXIMUM_VELOCITY, 0, MAXIMUM_VELOCITY)
return BodyVelocity
end
return Framework