What to slow down cannonball by?

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.

alright, I guess I’ll try that and I’ll update you with results

1 Like

@bruh_specialist results:

Even though I’m multiplying the force by it’s mass, the cannonball is still very slow

FORCE = direction * 95 s/s * mass

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)

bump bump bump bump bump bump bump

Force is acceleration * mass not… that?

FORCE = ((currentSpeed - lastSpeed) / deltaTime) * mass

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?

well the goal is to fire the cannonball from the cannon at specifically 95 studs per second
(also sorry for the hour late reply, I was out somewhere)

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.

n_cb:ApplyImpulse(cannonLook * 95 * n_cb.Mass)

(cannonLook is the LookVector of the cannon, n_cb is the cannonball)

Yes that seems right. What speed are you measuring, if you run this exactly after applying the impulse?
print(n_cb.AssemblyLinearVelocity.Magnitude)

Alright so the firing seems fine but it feels like it loses velocity way too fast, any way to change the rate of velocity loss?

Yes, you could implement something like this:

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
1 Like

Alright yeah made a function:

			local function ModifyFall(factor: number)
				local new_att = Instance.new("Attachment")
				local vForce = Instance.new("VectorForce")
				vForce.Attachment0 = new_att
				vForce.Parent = n_cb
				vForce.ApplyAtCenterOfMass = true
				vForce.RelativeTo = Enum.ActuatorRelativeTo.World
				vForce.Name = "fall_modifier"
				new_att.Parent = n_cb
				local force = Vector3.yAxis * (workspace.Gravity * n_cb.Mass * factor)
				vForce.Force = force
			end

For now I’ll test it out, my testing factor is going to be pi * 0.1, no apparent reason but it sounds like a good number to experiment on

1 Like