A simple cannonball, perfect sphere, radius of 0.5 studs. How can I get the rate at which it should slow down per second taking in account its velocity? My current system just decreases the velocity by 5% every second, but that isn’t a realistic method.

I am using LinearVelocity here, I’ve already got gravity sorted

You might want to use ApplyImpulse() as it
“applies an instant force impulse” to a part’s assembly. This would automatically decrease the velocity in relation to the balls mass and speed. Manually decreasing the ball’s mass would make the ball fly longer time in the air i assume. (If not, you can quickly script an upwards vector force that goes against gravity to achieve same effect)

I’ve attempted using ApplyImpulse before using LinearVelocity. For my case applyImpulse is simply not fit for what I’m trying to do.

A main issue for ApplyImpulse is that the cannonball is launched from the the back of the cannon (to the direction of the cannon’s lookVector obviously), instead of being launched from the front. This means that if gravity is being accounted in the split seconds where the cannonball is still in the chamber, it would fall down and then collide with the chamber, I’ve resolved this by using LinearVelocities, where for the first one third of a second, no physics (i.e gravity, lift and drag) are accounted on the cannonball.

Also using GPT, I’ve found this equation, not sure if it is correct but it sure is worth a shot:

function calculateForces(velocity, mass, radius)
-- Constants for air density and coefficients (values can be adjusted)
local airDensity = 1.225 -- Density of air in kg/m^3
local dragCoefficient = 0.47 -- Drag coefficient for a sphere
local liftCoefficient = 0.2 -- Assumed lift coefficient for a sphere
-- Gravity constant
local gravity = 9.81 -- Standard gravity in m/s^2
-- Calculate cross-sectional area
local crossSectionalArea = math.pi * radius ^ 2
-- Calculate forces
local drag = 0.5 * airDensity * velocity ^ 2 * dragCoefficient * crossSectionalArea
local lift = 0.5 * airDensity * velocity ^ 2 * liftCoefficient * crossSectionalArea
return {drag = drag, lift = lift}
end

You could tween the cannonball with the expected speed out of the chamber, and apply physics to it only, when it is away from colliding objects. I did something very similar before, and the effect looks completely natural, if just you get the speed right. (Alternatively, you could assign the cannonballs not to collide with its own ship using collision groups or just the chamber itself with NoCollisionConstraint.

No idea ws the original erter butchered the fps, but here is the original recording files that is running at normal fps: robloxapp-20231029-1436008.wmv (1.1 MB)

Am i right if i understand slow as in not shooting far enough? In which case, can’t you just multiply the force with 10 or something? Or do you need the ball to land at a specific point?

Isn’t your code already doing that? I tested with this setup:

local cannonball = workspace.Cannonball
local direction = Vector3.new(1, 1, 0).Unit
local startVelocity = 95
local vector = direction * startVelocity * cannonball:GetMass()
cannonball:ApplyImpulse(vector)
task.wait()
print(cannonball.AssemblyLinearVelocity.Magnitude) --Prints 87.807...

I know it quite inaccurate, but the higher start velocity, the higher accuracy:
StartVelocity = 1000 → 993.087… s/s
Perhaps it’s possible to make a function that will account for these inaccuracies.

local cannonball = script.Parent
local function ChangeObjectGravity(object, factor: number) --factor of 0 means no change, 1 means no gravity
if object:IsA("BasePart") and tonumber(factor) then
factor = math.clamp(factor, 0, 1)
local force = Vector3.yAxis * object.Mass * workspace.Gravity
local vectorForceName = "Anti-Gravity"
local vectorForce = object:FindFirstChild(vectorForceName)
if vectorForce then
vectorForce.Force = force * factor
else
local attachment = Instance.new("Attachment", object)
local vectorForce = Instance.new("VectorForce")
vectorForce.Name = vectorForceName
vectorForce.RelativeTo = Enum.ActuatorRelativeTo.World
vectorForce.ApplyAtCenterOfMass = true
vectorForce.Force = force * factor
vectorForce.Attachment0 = attachment
vectorForce.Parent = object
end
else
error("One or more arguments were not valid")
end
end
ChangeObjectGravity(cannonball, .5)

Examples:

factor of 1 → cannonball is unaffected by gravity (it would never loose velocity)

factor of 0.5 → cannonball is 50% affected by gravity

factor of 0 → cannonball is 100% affected by gravity