How to script collisions for moving objects in 2d engine?

I have a game that uses a custom 2d engine to simulate circles going around, being controlled by players, sorta like agar.io, however, I ran into a problem when scripting the behaviour of circles when they start colliding with other circles.

What do you want to achieve?

New Project

In this scenario, both dots are going in the same direction, but the one on the bottom is going 3 times faster than the first one, and it’s also colliding with it, thus pushing it. What should technically happen is the bottom dot starts pushing the first one and eventually slides around it, but making it behave that way would be too resource intensive for the game, so all I need to do is make the top one get pushed and make sure they don’t clip

What is the issue?

Implementing this in the current script is very difficult. The way it works right now is each tick it loops for every dot and takes the angle a player gives to it and calculates it’s next position.

The full script:

local TickSpeed = 1/15 --How many ticks a second

while true do
	local NewPositions = {}

	for Plr, Properties in pairs(ListOfPlayers) do
		local MainFolder = Baseplate.Blobs[Plr.Name]

		local Angle = math.rad(Properties["Angle"])
		local Speed = Properties["Speed"]

		if Speed > 2 then Speed = 2 end

		for _, Blob in pairs(MainFolder:GetChildren()) do
			local Count = CountToTable(Blob)

			--COLLISIONS
			local HitBox = Blob.HitBox

			local Parts = HitBox:GetTouchingParts()
			
			local WallCollisions = ""
			local BlobCollisions = {}

			for _, Item in pairs(Parts) do
				if Item.Parent.Name == "Walls" then
					WallCollisions = WallCollisions..string.split(Item.Name, "Wall")[2]
				end
				
				if Item.Parent.Parent.Name == "Blobs" then
					table.insert(BlobCollisions, #BlobCollisions+1, Item.Parent)
				end
			end

			local FrictionX, FrictionY = Friction(WallCollisions, Angle)

			local OldPos = Properties["Position"][Count]
			local NewPos = Vector3.new(OldPos.X + math.sin(Angle) * Speed * SlowdownX, 1 , OldPos.Z + math.cos(Angle) * Speed * SlowdownY)
				
			if BlobCollisions then
				--change the newpos to account for collisions
			end
				
			Properties["Position"][Count] = NewPos
			HitBox.Position = Properties["Position"][Count]

			table.insert(NewPositions, #NewPositions+1, {Plr.Name, Properties["Position"]})
		end
	end

	InterpEvent:FireAllClients(NewPositions)

	wait(TickSpeed)
end

My issues are the maths behind the speed changes, the fact that you have to keep track of collisions outside the loop, and making sure the dots don’t clip through eachother. I don’t know how I should go about doing these

What solutions have you tried so far?

I’ve tried taking the distance between the dots and correcting the positions, but it was clunky, probably not compatible with the rest of the script, and I simply got stuck at the other two

Any help on this would be appreciated, thanks!