local f=game:GetService("\082\117\110\083\101\114\118\105\099\101")local F=game:GetService("\080\108\097\121\101\114\115")local R=game:GetService("\067\111\108\108\101\099\116\105\111\110\083\101\114\118\105\099\101")local q=require(script.BouncePlatform)local k=require(script.BouncePlatformConstants)local b=k.BOUNCY_TAG local Q=false local i=2 local V={Vector2.new(-1,.5),Vector2.new(0,.5);Vector2.new(1,.5);Vector2.new(0,0);Vector2.new(-1,-0.5),Vector2.new(0,-0.5);Vector2.new(1,-0.5)}local K=F.LocalPlayer local function A(f)assert(f~=nil,"\080\097\114\116 \101\120\112\101\099\116\101\100 \103\111\116 \110\105\108")assert(typeof(f)=="\073\110\115\116\097\110\099\101","\101\120\112\101\099\116\101\100 \073\110\115\116\097\110\099\101 \103\111\116 "..typeof(f))assert(f.ClassName=="\077\101\115\104\080\097\114\116"or f.ClassName=="\080\097\114\116","\101\120\112\101\099\116\101\100 \077\101\115\104\080\097\114\116 \111\114 \080\097\114\116 \103\111\116 "..f.ClassName)end local function u(f)local F=0 for f,R in pairs(f:GetDescendants())do if R:IsA("\066\097\115\101\080\097\114\116")then F+=R:GetMass()end end return F end local c={ActiveBouncePlatforms={}}function c.new(f,F)A(f)local R=q.new(f,F)c.ActiveBouncePlatforms[R.platform]=R if Q then R:_debug(R)end return R end function c._detect(R,f,F)local q={}local k=K.Character.PrimaryPart.CFrame.LookVector local b=K.Character.PrimaryPart.CFrame.RightVector for R,Q in pairs(V)do local i=b*Q.X local V=k*Q.Y local A=(K.Character.PrimaryPart.Position+V)+i local u=workspace:Raycast(A,Vector3.new(0,-F,0),f)if u and u.Instance then table.insert(q,u)end end return q end function c._checkForBouncePlatforms(f)if not K.Character then return end if not K.Character.PrimaryPart then return end local F=K.Character:FindFirstChildOfClass("\072\117\109\097\110\111\105\100")if not F then return end local q=F.HipHeight+i local k=RaycastParams.new()k.FilterDescendantsInstances=R:GetTagged(b)k.FilterType=Enum.RaycastFilterType.Whitelist local Q=c:_detect(k,q)for f,F in pairs(Q)do local R=F.Instance local q=c:getBouncePlatformFromInstance(R)if not q or q and not q.enabled then return end local k=os.clock()if k-q.lastBouncedAt>=q.debounce then q.lastBouncedAt=k K.Character.PrimaryPart.Velocity=Vector3.new(0,0,0)local f=(q.bounceVector*q.bounceForce)*K.Character.PrimaryPart.AssemblyMass K.Character.PrimaryPart:ApplyImpulse(f)q:_onBounced()return end end end function c.enable(F)if c.HeartbeatConnection then c:disable()end c.HeartbeatConnection=f.Heartbeat:Connect(function()c:_checkForBouncePlatforms()end)end function c.disable(f)if c.HeartbeatConnection then c.HeartbeatConnection:Disconnect()c.HeartbeatConnection=nil end end function c.getBouncePlatformFromInstance(F,f)return c.ActiveBouncePlatforms[f]end function c.getActiveBouncePlatforms(f)return c.ActiveBouncePlatforms end return c
--[[ How to use BouncePlatforms

LocalScript:
	BouncePlatforms.new(part, {
		debounce = 0.2,
		bounceVector = Vector3.new(0, 1, 0),
		bounceForce = 2000,
	})

	BouncePlatforms:enable()

]]

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

local BouncePlatform = require(script.BouncePlatform)
local BouncePlatformConstants = require(script.BouncePlatformConstants)

local BOUNCY_TAG = BouncePlatformConstants.BOUNCY_TAG
local DEBUG = false
local HIPHEIGHT_BUFFER = 2
local RAYCAST_DETECTION_OFFSETS = {
	Vector2.new(-1, 0.5),
	Vector2.new(0, 0.5),
	Vector2.new(1, 0.5),
	Vector2.new(0, 0),
	Vector2.new(-1, -0.5),
	Vector2.new(0, -0.5),
	Vector2.new(1, -0.5),
}

local player = Players.LocalPlayer

local function _assert(part)
	assert(part ~= nil, "Part expected got nil")
	assert(typeof(part) == "Instance", "expected Instance got " .. typeof(part))
	assert(part.ClassName == "MeshPart" or part.ClassName == "Part", "expected MeshPart or Part got " .. part.ClassName)
end

local function getModelMass(model)
	local totalMass = 0

	for _, basepart in pairs(model:GetDescendants()) do
		if basepart:IsA("BasePart") then
			totalMass += basepart:GetMass()
		end
	end

	return totalMass
end

local BouncePlatforms = {
	ActiveBouncePlatforms = {},
}

function BouncePlatforms.new(part, config)
	_assert(part)

	local bouncePlatform = BouncePlatform.new(part, config)

	BouncePlatforms.ActiveBouncePlatforms[bouncePlatform.platform] = bouncePlatform

	if DEBUG then
		bouncePlatform:_debug(bouncePlatform)
	end

	return bouncePlatform
end

function BouncePlatforms:_detect(raycastParams, length)
	local raycastResults = {}

	local lookVector = player.Character.PrimaryPart.CFrame.LookVector
	local rightVector = player.Character.PrimaryPart.CFrame.RightVector

	for _, cell in pairs(RAYCAST_DETECTION_OFFSETS) do
		local offsetX = rightVector * cell.X
		local offsetZ = lookVector * cell.Y
		local origin = (player.Character.PrimaryPart.Position + offsetZ + offsetX)
		local raycastResult = workspace:Raycast(origin, Vector3.new(0, -length, 0), raycastParams)

		if raycastResult and raycastResult.Instance then
			table.insert(raycastResults, raycastResult)
		end
	end

	return raycastResults
end

function BouncePlatforms:_checkForBouncePlatforms()
	if not player.Character then
		return
	end

	if not player.Character.PrimaryPart then
		return
	end

	local humanoid = player.Character:FindFirstChildOfClass("Humanoid")
	if not humanoid then
		return
	end

	local length = humanoid.HipHeight + HIPHEIGHT_BUFFER
	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = CollectionService:GetTagged(BOUNCY_TAG)
	raycastParams.FilterType = Enum.RaycastFilterType.Whitelist

	local raycastResults = BouncePlatforms:_detect(raycastParams, length)

	for _, raycastResult in pairs(raycastResults) do
		local platformInstance = raycastResult.Instance

		local bouncePlatform = BouncePlatforms:getBouncePlatformFromInstance(platformInstance)

		if not bouncePlatform or (bouncePlatform and not bouncePlatform.enabled) then
			return
		end

		local currentTime = os.clock()

		if currentTime - bouncePlatform.lastBouncedAt >= bouncePlatform.debounce then
			bouncePlatform.lastBouncedAt = currentTime

			player.Character.PrimaryPart.Velocity = Vector3.new(0, 0, 0)

			local momentum = bouncePlatform.bounceVector
				* bouncePlatform.bounceForce
				* player.Character.PrimaryPart.AssemblyMass

			player.Character.PrimaryPart:ApplyImpulse(momentum)

			bouncePlatform:_onBounced()

			return
		end
	end
end

function BouncePlatforms:enable()
	if BouncePlatforms.HeartbeatConnection then
		BouncePlatforms:disable()
	end

	BouncePlatforms.HeartbeatConnection = RunService.Heartbeat:Connect(function()
		BouncePlatforms:_checkForBouncePlatforms()
	end)
end

function BouncePlatforms:disable()
	if BouncePlatforms.HeartbeatConnection then
		BouncePlatforms.HeartbeatConnection:Disconnect()
		BouncePlatforms.HeartbeatConnection = nil
	end
end

function BouncePlatforms:getBouncePlatformFromInstance(platform)
	return BouncePlatforms.ActiveBouncePlatforms[platform]
end

function BouncePlatforms:getActiveBouncePlatforms()
	return BouncePlatforms.ActiveBouncePlatforms
end

return BouncePlatforms
