Detecting collisions for high-velocity objects

In my context, I have parts travelling hundreds or even thousands of studs per second, and these aren’t bullets but missiles, which would then need a part resembling them in workspace.

I’ve written a simple function to detect if there might be an issue with a collision detection:

local function collision_check(p:Part, vel: Vector3, dt: number?): Vector3?
	local tdelta = dt or 1 / workspace:GetRealPhysicsFPS()
	local rc_params = RaycastParams.new()
	rc_params.FilterType = Enum.RaycastFilterType.Exclude
	rc_params.FilterDescendantsInstances = {p}
	
	local cast = workspace:Raycast(p.Position, vel, rc_params)
	if cast then
		if cast.Distance / (vel.Magnitude * tdelta) < 1 then
			return cast.Position
		end
	end
	return
end

It casts a ray at the velocity of the projectile, and if the ray collides with an object it checks if the distance between that object and the projectile can be crossed in a single frame taking in account the velocity.

But this has to be fired every frame for every projectile in my experience, and I’m not sure if that would be most effective.

This is to work alongside the current .touched event for parts, but I’m not sure if this is suffiecent enough.

1 Like

don’t use .touched

Raycasting is extremely efficient, and as long as you move the missile at the same speed in which you raycast it should be fine.

Raycasts are more optimised then you think.

I use linear velocity, which is modified every frame alongside the raycast, and since linear velocities also run every frame, then I guess yes, they’d be at the same speed.

Added this to my heartbeat function:

		local ray = workspace:Raycast(
			projectile.Position, 
			config.vel.VectorVelocity * dt,
			config.params
		)
		if ray then
			local crosses = ray.Distance / (config.vel.VectorVelocity.Magnitude*dt)
			if crosses < 1 then
				projectile.Position = ray.Position
				config.touch(ray.Instance)
			end
		end
1 Like

yeh, Although since you already have a heartbeat, I’d advise against using native roblox physics,

Use position + direction * velocity (set value you can probably change) * dt

part.pos/cframe = that new position (cframe.new(position, position + lookvector))

Here’s the full section of the script for more context:

for projectile, config in pairs(RunningProjs) do
		config.fuel = math.max(config.fuel - config.burn * dt, 0)
		local actv = math.sign(config.fuel)
		local v = config.vel.VectorVelocity.Magnitude
		local rho = frm.air_density(projectile.Position.Y)
		local eUP = (actv * config.lift) - (gravity * config.mass)
		local eFR = (actv * config.thrust) - frm.drag(config.drag_co, rho, v)
		
		config.vel.VectorVelocity = 
			Vector3.yAxis * (eUP / config.mass) 
			+ 
			projectile.CFrame.LookVector * (eFR / config.mass)
		
		local new_target = projectile.Position + config.vel.VectorVelocity * dt
		local ray = workspace:Raycast(
			projectile.Position, 
			config.vel.VectorVelocity * dt,
			config.params
		)
		if ray then
			local crosses = ray.Distance / (config.vel.VectorVelocity.Magnitude*dt)
			if crosses < 1 then
				projectile.Position = ray.Position
				config.touch(ray.Instance)
			end
		end
		
		projectile:PivotTo(CFrame.lookAt(projectile.Position, new_target))
	end
1 Like

The way you’ve said is likely the best way to go about it. An older module called FastCast does the same thing, raycasting every frame and detecting a hit. iirc it was extremely performant so i don’t see much of a reason this wouldn’t result in the same

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.