Improving my Movement Framework

Hello Everyone, so I was working on my Bunnyhop Movement module (I used Bunnyhop V1 Module by @Teryjaki20 for the main part, and just improved it). And, I have a problem.

How can I make it more advanced? For example I want to make bunny hop like in CS, to do it, you should manually press A or D and spacebar, to do bhop. But I don’t really know how to implement it. There is a really cool game called: Games Unite Testing Place. And, this game has REALLY good Bunnyhop Movement, that I want to add in my game.

i pasted a module here, but since no one helps me, then no one gets it :((

Thanks.

1 Like

So you just want to make bunnies hop?

2 Likes

I already made it, but I did it really bad, and like it’s not even looks like real bunnyhop movement. I can send you module, if you want to help. (I just deleted it because no one helped me)

2 Likes

Could you send a video of your (bad) bunny hopping, along with the module?

1 Like

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