Blade Ball Ball Physics

VectorCurves are still better though.

Vector3Curve is not tween, also Vector3Curve cons is once the object moved the waypoint curve will changed like really bad and Vector3Curve the curve speed is not constant. im sure blade ball curve are using object look direction with velocity.

Look what the owner of the module just said lol.

I have a better solution in mind but can’t test it rn…

Didn’t look at the source code just saw someone say it contains tweens… So i assumed he was correct

the contain tweens is “Tween:GetValue(…)” and its optional, i more prefer using get position from time or alpha.

1 Like
With Root LookVector
local players = game:GetService("Players")

local objects = {
	game:GetService("Workspace"):WaitForChild("Rig"),
	game:GetService("Workspace"):WaitForChild("Rig2"),
	game:GetService("Workspace"):WaitForChild('Rig3'),
	game:GetService("Workspace"):WaitForChild('Rig4'),
	game:GetService("Workspace"):WaitForChild('Rig5'),
	game:GetService("Workspace"):WaitForChild('Rig6'),
}

players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function(char)
		table.insert(objects, char)
	end)
end)
task.wait(3.5)
local past = nil
local ball = game:GetService("Workspace"):WaitForChild("Ball")
local target = nil
local direction = nil

local speedVelocity = 5
local alpha = 0
local maxspeed = 25

function randomTarget(previous)
	local new = previous
	while (new == previous) do
		new = objects[math.random(1, #objects)]
	end
	if not new then
		return randomTarget(previous)
	end
	return new
end

local function updateBallPosition(delta)
	if not target then
		target = randomTarget(target)
	end
	if target then
		if (target.PrimaryPart.Position - ball.Position).Magnitude <= 2 then
			past = target
			direction = past.PrimaryPart.CFrame
			target = randomTarget(target)
			alpha = 0
			speedVelocity *= 1.1
		end
		if past then
			local playerDirection = direction.LookVector
			local targetDirection = (target.PrimaryPart.Position - ball.Position).Unit
			ball.LinearVelocity.MaxForce = math.huge
			ball.LinearVelocity.VectorVelocity = (targetDirection + (playerDirection:Lerp(targetDirection, 0.5)) * 2) * math.min(maxspeed, speedVelocity)
		else
			alpha += delta
			ball.Position = ball.Position:Lerp(target.PrimaryPart.Position, math.min(1, alpha))
		end
	end
end

game:GetService("RunService").PostSimulation:Connect(updateBallPosition)
With Camera LookVector
local players = game:GetService("Players")

local objects = {
	game:GetService("Workspace"):WaitForChild("Rig"),
	--game:GetService("Workspace"):WaitForChild("Rig2"),
	--game:GetService("Workspace"):WaitForChild('Rig3'),
	--game:GetService("Workspace"):WaitForChild('Rig4'),
	--game:GetService("Workspace"):WaitForChild('Rig5'),
	--game:GetService("Workspace"):WaitForChild('Rig6'),
}

players.PlayerAdded:Connect(function(plr)
	plr.CharacterAdded:Connect(function(char)
		if not table.find(objects, char) then
			table.insert(objects, char)
		end
	end)
end)

task.wait(3.5)
local RemoteEvent = game:GetService("ReplicatedStorage"):WaitForChild('RemoteEvent')
local ball = game:GetService("Workspace"):WaitForChild("Ball")
local past = nil
local target = nil
local direction = nil
local playerFacing = {}

local speedVelocity = 5
local alpha = 0
local maxspeed = 25

function randomTarget(previous)
	local new = previous
	while (new == previous) do
		new = objects[math.random(1, #objects)]
	end
	if not new then
		return randomTarget(previous)
	end
	return new
end

local function updateBallPosition(delta)
	if #objects <= 1 then return end
	for _, v in pairs(objects) do
		playerFacing[v] = v.PrimaryPart.CFrame.LookVector
	end
	if not target then
		target = randomTarget(target)
	end
	if target then
		if (target.PrimaryPart.Position - ball.Position).Magnitude <= 2 then
			past = target
			direction = playerFacing[past]
			target = randomTarget(target)
			alpha = 0
			speedVelocity *= 1.1
		end
		if past and direction then
			local targetDirection = (target.PrimaryPart.Position - ball.Position).Unit
			ball.LinearVelocity.MaxForce = math.huge
			ball.LinearVelocity.VectorVelocity = (targetDirection + (direction:Lerp(targetDirection, 0.5)) * 2) * math.min(maxspeed, speedVelocity)
		else
			alpha += delta
			ball.Position = ball.Position:Lerp(target.PrimaryPart.Position, math.min(1, alpha))
		end
	end
end

function stringtoCFrame(str)
	return Vector3.new(table.unpack(str:gsub(" ",""):split(",")))
end

RemoteEvent.OnServerEvent:Connect(function(plr: Player, pos: string)
	if plr and plr.Character then
		playerFacing[plr.Character] = stringtoCFrame(pos)
	end
end)

game:GetService("RunService").PostSimulation:Connect(updateBallPosition)

made it with Roblox Assistant but i made some customization for better curving, btw its using LinearVelocity. (its server sided)

Example:

7 Likes

Could it be Lerps, or is it something else?

Devs said they dont use lerp or tween

People constantly trying to theorise what the devs used, when they explicitly mentioned what they did use.

@Kazisita It actually does exactly this, but instead of TweenServiceV2, they actually just use simple position lerping, which gives the same effect with less bloat. However, this does not actually hinder the ball hitbox visibility because of client delay. Instead, it just lets the player have more accurate hits-to-visuals (not exactly sparing the player) with their raycast or workspace:GetPartsIn?() depending on which one they use

2 Likes

If you are reusing the same PathBall object, use PathBall:resetMovement() when a player hits the ball. It has parameters for start position and initial direction. If you create a new PathBall every time, give the start position and initial direction to the constructor PathBall.new().

The local script in my reply doesn’t reset the ball’s movement or detect hits. You’ll need to add the hit detection code yourself and then either use PathBall:resetMovement() or PathBall:destroy() and PathBall.new().

2 Likes

Yall still trying to this day man!

1 Like

It’s been open for 2 months wild.

Yall still trying to this day man!

Tell us man!

:pleading_face: :pleading_face: :pleading_face: :pleading_face:

Why would he leak his game’s methods

1 Like

It’s so easy to make it
(character filler e)

i think this should work

script type: Server
location: ServerScriptStorage

local Competitors = Instance.new("Team", game.Teams)
Competitors.Name = "Competitors"
Competitors.TeamColor = BrickColor.Red()
Competitors.AutoAssignable = false

local Lobby = Instance.new("Team", game.Teams)
Lobby.Name = "Lobby"
Lobby.TeamColor = BrickColor.Gray()
Lobby.AutoAssignable = true

local function GetCompetitors()
	local Tab = {}
	for _, i in game.Players:GetPlayers() do
		if i.Team == Competitors then
			table.insert(Tab, i)
		end
	end
	return Tab
end

local function CreateBall()
	game.ReplicatedStorage.CreateBall:FireAllClients(true)
	
	local velocity = Vector3.new(0,1,0)
	local speed = 0
	local Hit = false
	local Target = GetCompetitors()[math.random(1,#GetCompetitors())].Character --Pick Random Player To Be Target
	game.ReplicatedStorage.BallTarget:FireAllClients(Target)
	local Pos = Vector3.new(0,0,0) -- Ball Spawn
	--Customizable Settings
	local BallSize = 3
	local PlayerForce = 10
	local BallUpdatesPerSecond = 10
	
	local SpeedIncrease = task.spawn(function()--To Make The Ball's Speed Increase Over Time
		while true do
			task.wait(1/BallUpdatesPerSecond)
			speed += 1/BallUpdatesPerSecond
		end
	end)
	
	repeat
		local RelativeCF = CFrame.new(Pos,Target:WaitForChild("HumanoidRootPart").Position)
		velocity = RelativeCF:VectorToObjectSpace(velocity)
		velocity = Vector3.new(velocity.X, velocity.Y, math.clamp(velocity.Z,-speed/BallUpdatesPerSecond,100))
		velocity = RelativeCF:VectorToWorldSpace(velocity)
		Pos += velocity
		velocity -= velocity.Unit*speed/BallUpdatesPerSecond
		velocity += (Target:WaitForChild("HumanoidRootPart").Position-Pos).Unit*speed/BallUpdatesPerSecond
		
		game.ReplicatedStorage.UpdateBallPos:FireAllClients(Pos)
		for _, i in workspace:GetPartBoundsInRadius(Pos, BallSize/2) do
			if i.Name == "HumanoidRootPart" then
				if i.Parent == Target then
					if Target.Blocking.Value == true then
						Target.Blocking.Value = false
						local Velo = i.CFrame.LookVector
						local t = tick()
						local CFrameReturned = false
						game.ReplicatedStorage.GetCameraCFrame:FireClient(game.Players:GetPlayerFromCharacter(Target))
						local cfFunc = game.ReplicatedStorage.GetCameraCFrame.OnServerEvent:Connect(function(plr, CF : CFrame)
							if plr == game.Players:GetPlayerFromCharacter(Target) then
								local VeloPreset = CF.LookVector*PlayerForce
								Velo = Vector3.new(VeloPreset.X,math.clamp(VeloPreset.Y,0,1),VeloPreset.Z)
								CFrameReturned = true
							end
						end)
						
						repeat task.wait(0.05) until CFrameReturned or tick()-t > 0.5
						cfFunc:Disconnect()
						local Path = CFrame.new(i.Position,i.Position+Velo)
						local BestTarget = nil
						local BestMag = math.huge
						for _, v in GetCompetitors() do
							local a = v.Character
							if a ~= Target then
								local Pos = Path:VectorToObjectSpace(a.HumanoidRootPart.Position)
								if Pos.Z > 0 then
									if math.sqrt(Pos.X^2+Pos.Y^2) < BestMag then
										BestMag = math.sqrt(Pos.X^2+Pos.Y^2)
										BestTarget = a
									end
								end
							end
						end
						if BestTarget == nil then
							for _, v in GetCompetitors() do
								local a = v.Character
								if a ~= Target then
									local Pos = Path:VectorToObjectSpace(a.HumanoidRootPart.Position)
									if math.sqrt(Pos.X^2+Pos.Y^2) < BestMag then
										BestMag = math.sqrt(Pos.X^2+Pos.Y^2)
										BestTarget = a
									end
								end
							end
						end
						Target = BestTarget
						game.ReplicatedStorage.BallTarget:FireAllClients(Target)
						velocity = Velo
					else
						Target.Humanoid.Health = 0
						Hit = true
					end
				end
			end
		end
		task.wait(1/BallUpdatesPerSecond)
	until Hit
	task.cancel(SpeedIncrease)
	game.ReplicatedStorage.CreateBall:FireAllClients(false)
	if #GetCompetitors() > 1 then
		CreateBall()
	end
end

game.Players.PlayerAdded:Connect(function(Player)
	local leaderstats = Instance.new("Folder", Player)
	leaderstats.Name = "leaderstats"
	local wins = Instance.new("NumberValue", leaderstats)
	wins.Name = "Wins"
end)

while true do
	repeat wait() until #game.Players:GetPlayers() > 1
	task.wait(15)
	for _, i in game.Players:GetPlayers() do
		i.Team = Competitors
		if i.Character then
			i.Character:FindFirstChildOfClass("Humanoid").HealthChanged:Connect(function(health)
				if health < 1 then
					i.Team = Lobby
				end
			end)
		end
	end
	CreateBall()
	local Winner = GetCompetitors()[1]
	if Winner then
		Winner.Team = Lobby
		Winner.leaderstats.Wins.Value += 1
	end
end

Script Type: Server (Contains Remote Event Called Block, Name BlockHandler)
Location: StarterCharactersScripts

local Blocking = Instance.new("BoolValue", script.Parent)
Blocking.Name = "Blocking"

local cd = false

local BlockingTime = false

script.Block.OnServerEvent:Connect(function(plr)
	if plr == game.Players:GetPlayerFromCharacter(script.Parent) then
		if cd == false then
			cd = true
			Blocking.Value = true
			BlockingTime = true
			local Parried = Blocking.Changed:Connect(function(value)
				if value == false then
					BlockingTime = false
				end
			end)
			local t = tick()
			repeat task.wait() until tick()-t > 0.5 or BlockingTime == false
			Parried:Disconnect()
			if BlockingTime == false then
				cd = false
			else
				Blocking.Value = false
				task.wait(1)
				cd = false
			end
		end
	end
end)

Script Type: Local
Location: StarterCharacterScripts

game.Players.LocalPlayer:GetMouse().Button1Down:Connect(function()
	script.Parent.BlockHandler:WaitForChild("Block"):FireServer()
end)

Script Type: Local
Location: StarterPlayerScripts

local Player = game.Players.LocalPlayer

local Ball = nil

local ti = TweenInfo.new(0.125,Enum.EasingStyle.Linear)

game.ReplicatedStorage.GetCameraCFrame.OnClientEvent:Connect(function()
	wait()
	game.ReplicatedStorage.GetCameraCFrame:FireServer(game.Workspace.CurrentCamera.CFrame)
end)

game.ReplicatedStorage.CreateBall.OnClientEvent:Connect(function(CD:boolean)
	if CD then
		Ball = game.ReplicatedStorage.Ball:Clone()
		Ball.Parent = game.Workspace
	else
		if Ball then
			Ball:Destroy()
		end
	end
end)

game.ReplicatedStorage.BallTarget.OnClientEvent:Connect(function(Target:Player)
	if Ball then
		if Target == Player.Character then
			Ball.Highlight.FillColor = Color3.new(1,0,0)
		else
			Ball.Highlight.FillColor = Color3.fromRGB(200,200,200)
		end
	end
end)

game.ReplicatedStorage.UpdateBallPos.OnClientEvent:Connect(function(Pos : Vector3)
	if Ball then
		game:GetService("TweenService"):Create(Ball, ti, {Position = Pos}):Play()
	end
end)

Remote Events In Replicated Storage

  • Ball Target
  • UpdateBallPos
  • GetCameraCFrame
  • CreateBall

Items In Replicated Storage
Ball: Sphere, Size = 3, 3, 3
Set CanCollide, CanTouch, CanQuery To False
Create Highlight In Ball, Set FillTransparency to 0

2 Likes

I mean have you tested it to see if it works?