Ball Curve and Physics

Hi, i’ve been trying to make a football system (similar to the game Rematch) where you choose where your ball curves, I did it with bezier curves, but when the ball reaches the last point of the bezier curve it suddenly stops and falls straight down instead of continuing it’s trajectory (first video). The problem has something to do with physics, so i thought of some solutions. Do I make custom physics for the ball (calculating where the ball will bounce and stuff) ? Or just fix the bug (somehow idk) and keep the roblox physics ? (both of the methods are in combination with bezier curves) or I just make it full custom physics without bezier curves (I tried this and it didn’t work very well it’s like the ball would curve based off the world origin, also the green points don’t go through the red circle which is also a problem (2nd video), for this i followed this 1st part of a tutorial https://www.youtube.com/watch?v=279r8beQPeE&t=1002s)? I would like to be able to predict where the ball will end up being or landing, at all times (Because I want to make an indicator where the ball will land, like in Rematch) so what method would you recommend me using in order to achieve this ? Do I stop using bezier curves ? Maybe try with vector forces ? Also feel free recommend some tutorials that I could follow.

Script where I calculate the bezier and where I apply the custom physics module script


local CurvePoints = {}

local Ball = script.Parent

local function CreateKeyPart(Part: Part, Pos, Player: Player)
	Part.Shape = "Ball"
	Part.Size = Vector3.new(1.25, 1.25, 1.25)
	Part.Anchored = true
	Part.CanCollide = false
	Part.Material = Enum.Material.Neon
	Part.Color = Color3.fromRGB(255, 0, 0)
	Part.Transparency = 0.5
	Part.Parent = game.Workspace.Map
	Part.Position = Pos
end

local function lerp(t,a,b)
	return a+(b-a)*t
end

local function quadBezier(t,p0,p1,p2)
	local l1 = lerp(t,p0,p1)
	local l2 = lerp(t,p1,p2)
	local quad = lerp(t,l1,l2)
	return quad
end

local function CreateCurve(p0: BasePart, p1: BasePart, p2: BasePart)
	
	for i = 0, 1, 0.1 do
		local Part = Instance.new("Part")
		Part.Color = Color3.new(0, 1, 0)
		Part.CanCollide = false
		Part.Size = Vector3.new(0.25,0.25,0.25)
		Part.Anchored = true
		Part.Shape = "Ball"
		Part.CFrame = CFrame.new(quadBezier(i,p0.Position, p1.Position, p2.Position))
		Part.Parent = TrashFolder
		Debris:AddItem(Part, 0.25)
		
		table.insert(CurvePoints, Part.Position)
	end
	
	return CurvePoints
end

local BallPhysics = require(game.ServerScriptService.Modules.BallPhysics).new(true) --Physics Without Bezier

function BallMotion(Attachment, CenterPart, CursorPart, Ball)
	BallPhysics:Cast(Attachment.Position, CursorPart.Position, Ball) -- Without Bezier
	--CurvePoints = CreateCurve(Attachment, CenterPart, CursorPart) -- With Bezier
	
	--for i = 1, #CurvePoints do
	--	Ball.CFrame = CFrame.new(CurvePoints[i])
	--	wait()		
	--end
	
	--CurvePoints = {}
end

ShootRemote.OnServerEvent:Connect(function(Player, CenterPos, CursorPos)
	
	if Ball:GetAttribute("Possesion") == false then return end
	
	local Attachment = Character:WaitForChild("Attachment")
	local CenterPart = Instance.new("Part")
	local CursorPart = Instance.new("Part")
	
	CenterPart.Name = "CenterPart"
	CursorPart.Name = "CursorPart"
	CreateKeyPart(CenterPart, CenterPos, Player)
	if CursorPos then
		CreateKeyPart(CursorPart, CursorPos, Player)
	end
	
	Weld:Destroy()
	Ball.CanCollide = true
	Ball:SetAttribute("Possesion", false)
	Debaunce = false
	BallMotion(Attachment, CenterPart, CursorPart, Ball)
	task.wait(0.5)
	Debaunce = true
	CenterPart:Destroy()
	CursorPart:Destroy()

end)

custom physics module script (the script from the video)

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

local BallPhysics = {}

function BallPhysics.new(Visualize)
	local NewPhysics = {}
	
	NewPhysics.Params = RaycastParams.new()
	NewPhysics.Params.FilterType = Enum.RaycastFilterType.Include
	NewPhysics.Params.FilterDescendantsInstances = workspace.Map:GetChildren()
	
	function NewPhysics:Cast(Start, Dest, Ball)

		--t = time
		--a = acceleration
		
		local VForce = (Dest-Start).Unit * 200

		local t = 0
		local CurrentPos = Start
		local RayResult = nil
		local Found = false
		
		local a = Vector3.new(-workspace.Gravity, -workspace.Gravity, -workspace.Gravity)
		
		local Connection = RunService.Heartbeat:Connect(function(dt)
			if not Found then
				t += dt

				local ProjectPos = Vector3.new(
					Start.X + VForce.X*t + 0.5*a.X*t*t,
					Start.Y + VForce.Y*t + 0.5*a.Y*t*t,
					Start.Z + VForce.Z*t + 0.5*a.Z*t*t
				)

				RayResult = workspace:Raycast(CurrentPos, ProjectPos - CurrentPos, self.Params)
				
				CurrentPos = ProjectPos

				if Visualize then
					local Part = Instance.new("Part")
					Part.Size = Vector3.new(0.25,0.25,0.25)
					Part.Position = ProjectPos
					Ball.Position = ProjectPos
					Part.Anchored = true
					Part.CanCollide = false
					Part.Material = Enum.Material.Neon
					Part.Color = Color3.fromRGB(0, 255, 0)
					Part.Shape = "Ball"
					Part.Parent = game.Workspace.TrashFolder

					--Debris:AddItem(Part, 0.2)
				end
				
				if RayResult or t > 1 then
					Found = true
				end
				
			end

		end)
		
		while not Found do
			task.wait()
		end

		Connection:Disconnect()

	end
	
	return NewPhysics
end

return BallPhysics

video with bezier

video without bezier

the video tutorial is probably the best way to do this
and the curve is probably because your acceleration is in all three dimensions instead of just going down

the tutorial code is already using a prediction of where the ball is going to end up with

local ProjectPos = Vector3.new(
					Start.X + VForce.X*t + 0.5*a.X*t*t,
					Start.Y + VForce.Y*t + 0.5*a.Y*t*t,
					Start.Z + VForce.Z*t + 0.5*a.Z*t*t
				)

if you want to calculate the final position then you would just use this same formula, but you would have to calculate the final time with a kinematic equation

reddit post says t=(-Vf+-sqrt(Vf^2 -2gd))/-g
https://www.reddit.com/r/AskPhysics/comments/5xl0vj/kinematics_how_to_isolate_for_time_in_the

2 Likes

Did you anchor the Football ball in the Bezier Curve method?

No, should I ? If yes, where ?

It can cause lag, also it can intersect with your own Ball Physics module’s Physics and create a nonsensical movement

1 Like

Ok thx, but I don’t want the ball to go only down, I want it to also curve left or right

i’ve created a ball for each version so it won’t intersect, it is less laggier while anchored but that doesn’t fix the problem

by the way is the speed you use on Physics module Equal to the Speed you have on the Bezier?

Idk, probably not, either way i don’t think that matters because I didn’t combine the scripts, there is a ball with the bezier script and one with the physics module script. Do you want me to combine the scripts ?

No but in the first media it’s blatantly visible the Ball loses it’s speed at the Bezier curve once it reaches the destination, which is not what you want. If you want it you should set the Ball’s speed to Bezier curve’s speed to achieve what you want.

How do I get the speed ? In the script I set the ball CFrame to each bezier point.

get the distance between each curvepoint and divide it by 0.25(this is a reference to the 0.25 debris time you use in your code)

1 Like

How can I apply speed to the ball ? With AssemblyLinearVelocity ? I don’t see a speed property in the ball. And don’t I need to only calculate the distance between the last 2 curve points ? I don’t see why should I calculate it for all of them.

in the second code area, you have a code that says this:
local VForce = (Dest-Start).Unit * 200
replace the “200” with the speed you got. also yeah you’re right it should be only 2 points i got it wrong

1 Like

So… I do combine the scripts ? In the normal script I create the bezier curves and in the module I make the ball go through them ?

No just input the Bezier speed to the ball physics via a parameter
like this:

	function NewPhysics:Cast(Start, Dest, Ball,Speed)

Ok for that i have to unacnhor the ball, and the ball just doesn’t have enough force and just goes down. Creating the bezier doesn’t affect the module script, that’s why i keep asking if i need to combine the scripts, the module creates it’s on trajectory, do I need to replace the module script trajectory with the bezier points trajectory ?

1 Like

No, just apply the speed of bezier to the physics module.
Alternatively you can use the physics way in the first reply

also the physics way in the first reply only curves the ball down and I want it to also curve left and right