Pushing parts away from an explosion

I’m scripting a nuke, where the nuke should unanchor parts around it, and push them away from wherever the explosion occurs. What I’m trying to figure out is, what’s the most efficient way to push a large amount of parts away from the explosion? Would it be less laggy to use constraints, apply impulse, .Velocity, or some other method? Here is the script I have right now, which uses :ApplyImpulse()

for i,v in pairs(workspace:GetDescendants()) do
		if v:IsA("Weld") then -- destroys welds, allowing parts to move
			v:Destroy()
		elseif v:IsA("BasePart") and not v.Locked and not v:IsA("SpawnLocation") then
			v.Anchored = false
			task.spawn(function()
				task.wait((v.Position - explosion.Position).Magnitude/10) -- waits longer depending on how far the part is from the explosion
				v:ApplyImpulse((v.Position - explosion.Position).Unit * ExplosionForce * v:GetMass()) -- applies impulse which pushes the part away frmo the explosion
			end)
			if i/100 == math.round(i/100) then -- uses task.wait() every 1 in 100 parts which are unanchored
				task.wait()
			end
		end
	end

hey man thanks for asking me to look at this,
now me personally, i would create a part at the blast location, and make it the size of how large you want the blast to be. then i would use a .Touched event or :GetTouchingParts() to get the parts you want to effect and from that determine what parts to edit. looping through every part in workspace will be very very laggy so i wouldnt recommend it.

i changed up your script alot just to be neater for my eyes personally so i am sorry if you dont like how its written, but basically here is how i would do it.

local explosion = Instance.new('Part')
local blastradius = 100
local ExplosionForce = 3

explosion.Shape = Enum.PartType.Ball
explosion.Size = Vector3.one * blastradius
explosion.Position = Vector3.new(0,0,0) --blah blah wherebver its supposed to go
explosion.Touched:Connect(function(Part)
	if Part:IsA("SpawnLocation") then return end
	if Part.Locked then return end
	if not Part:IsA("BasePart") then
		return
	end
	
	local explosiondist = (Part.Position - explosion.Position)
	task.wait(explosiondist.Magnitude/10)
	for _, weld in Part:GetJoints() do
		weld:Destroy()
	end
	
	Part.Anchored = false
	Part:ApplyImpulse(explosiondist.Unit * ExplosionForce * Part:GetMass())
end)

explosion.Parent = workspace```

I’m not sure how realistic an effect you’re after, but generally speaking, you won’t want to multiply the force by the Part or Assembly mass, since this is going to make the acceleration mass-invariant. This will result in heavy things like vehicles and buildings getting thrown outward at the same velocity as light things like characters, furniture, signs, etc. In otherwords, cancelling inertia.

Instead, a more realistic approximation would be to scale the impulse relative to the area of the thing facing the explosion. Getting the projected area in a specific direction isn’t easy to calculate, but you really just need a crude estimate of the size of the thing. The point is, scaling with dimensional size is better than scaling with mass.

You probably also want to scale inversely with distance, so that things closer to the explosion get hit harder. IRL, the pressure of the blast falls off approximately proportional to the cube of the distance. So your final scale factor would be something like (area / (distance^3))

Lastly, because this is a very large explosion that will affect things even miles away, you should take the travel time of the blast wave into account, so that things farther away get hit with the force later. The exact speed of the shockwave is complicated, but it decays to the speed of sound eventually. And after the supersonic shockwave, comes the thermal expansion blast, which is generally moving slower than the speed of sound. If yo want real numbers for things like the wind speeds or heat, you can look here: https://apps.dtic.mil/dtic/tr/fulltext/u2/a384954.pdf (Los Alamos Laboratory report on nuclear blasts and simulations of them)

1 Like