Clipping issue regarding ApplyImpulse for parabolic movement

Hello devs! I am currently creating a “dig out” type of action movement for my shovel tool, which creates a copy of the item that will be thrown and adds a parabolic movement with the shape of an upside down “U” to that item, in order to visualize the movement to the player.

The issue I am currently having is the existence of a weird scenario where the items which have this impulse applied to, fall down so hard, that they clip through the terrain of my game, while some don’t.

I am gonna show you an example through this video below:

Another weird behavior I noticed, most of the items that were cloned in that fashion, had some weird properties, such as acting like they are black hole-weighted or standing perfectly still mid-air even though they are un-anchored. Video:

The last item being dropped (Legendary Dirt, :smile:), clips through the terrain.

I looked in both Dev hub and tried to minimize the total force, but the unwanted behavior still insisted.

Some solutions I tried:

  1. Making my items larger, which in some cases worked but still is inconsistent.
  2. Setting the NetworkOwner property of the cloned item to nil, so there weren’t any problems regarding part ownership.
  3. Replacing ApplyImpulse with an AssemblyLinearVelocity method. Movement was fairly inconsistent, though, caused less item clipping or anomalous behavior (I may have implemented AssemblyLinearVelocity wrongly, in case that was the solution).

The way I tried to implement this action is, by adding a “SpawnPart” on my shovel which is a simple block part on top of the shovel’s handle (the pink cube on top of the branch) that can’t collide and plays the role of a placeholder position for the items that get cloned to be in, as a starter position.

Below is the Script I used to replicate the throwing action, using ApplyImpulse:

function HandleDigThrow(player: Player, toolName: string, drop)
	-- Dropped item data
	local dropTier = drop.Item.data.tier
	local dropName = drop.Item.name
	local dropSizeName = drop.Size.name
	local dropSizeMultiplier = drop.Size.data.sizeMultiplier
	local dropVariantName = drop.Variant.name
	
	-- Tool that called the function
	local tool = player.Character:FindFirstChild(toolName)
	if not tool then
		warn(`Tool not found: {toolName}`)
		return
	end

	-- Part that Spawns the Item
	local spawnPart = tool:FindFirstChild("SpawnPart")
	if not spawnPart then
		warn("Tool does not have a SpawnPart")
		return
	end

	local spawnPos = spawnPart.Position + Vector3.new(0, 2, 0)
	local humanoidRootPart = player.Character:FindFirstChild("HumanoidRootPart")
	if not humanoidRootPart then
		warn("Player does not have a HumanoidRootPart")
		return
	end

	-- Determine facing direction
	local facingDirection = humanoidRootPart.CFrame.LookVector

	-- Calculate behind-the-player destination
	local offset = -facingDirection * 10 -- n studs behind the player
	local throwDestination = spawnPos + offset

	-- Add some height to the throw
	throwDestination += Vector3.new(0, 2, 0) -- n studs upward

	-- Calculate throw vector and force
	local direction = throwDestination - spawnPos
	local duration = math.log(1.001 + direction.Magnitude * 0.05)
	local force = direction / duration + Vector3.new(0, Workspace.Gravity * duration * 0.5, 0)

	-- Clone the item to be thrown
	local itemToClone = ServerStorage.Items:FindFirstChild(dropName) -- Dynamic selection
	if not itemToClone then
		warn(`{dropName} to clone not found`)
		return
	end

	local clone = itemToClone:Clone()
	clone:ScaleTo(clone:GetScale() * dropSizeMultiplier)
	-- Add trail from folder
	AttachTrail(clone)
	clone.PrimaryPart:FindFirstChild("Trail").Color = ColorSequence.new(Color3.fromHex(`{chatTags[dropTier].Color}`))
	clone.PrimaryPart.Position = spawnPos
	clone.Parent = Workspace

	-- Model will use player's computer to replicate the throw
	--clone.PrimaryPart:SetNetworkOwner(nil)

	-- Apply impulse to simulate throw
	clone.PrimaryPart:ApplyImpulse(force * clone.PrimaryPart.AssemblyMass)

	-- Add rotation impulse
	local rotation = Vector3.new(math.random(-1, 1), math.random(-2, 2), math.random(-1, 1))
	clone.PrimaryPart:ApplyAngularImpulse(rotation * clone.PrimaryPart.AssemblyMass)

	print(`{player.Name} successfully dug out an item!`)

	Debris:AddItem(clone, 15)
	task.delay(14, function() -- Remove the trail slightly before the clone is destroyed
		if clone and clone.Parent then
			RemoveTrail(clone)
		end
	end)
end

P.S: I don’t know if this is a welding issue, but the way I have glued the items together is by using weld constraints, so I don’t think there’s an issue there.

Any advice or guiding steps would be appreciated, thanks a lot!