Check the reply marked as the solution for the latest update added to this topic!
Hello folks!
I am sure you might be having fun with these daily topics I create for 2D game development!
Today,
I created a simple collision response between a circle and a canvas’s boundaries, simulation and thought about making it open sourced!
(I’ll update this tomorrow and make circle ← → circle collision response using Newtons 2nd and 3rd law of motion!) done
Don’t know what collision response is? Check out this wikipedia page!
How does it work?
Well, simple! Theres an initial velocity to the circle. The velocity changes the position of the circle, at every frame, collisions between the circle and the 4 boundaries are checked, if they do collide, I multiply the velocity by -1 which causes the direction of the velocity to be reversed!
For the sake of simplicity:
mass = 1
for all objects in our 2D space
acceleration = constant
constant acceleration throughout! (You can change it in the source code)
To simulate Elastic Collisions, I used newton’s 3rd Law!
Public and Uncopylocked place:
Source code:
Client → Physics and Circle module.
Circle Module:
local Circle = {}
Circle.__index = Circle
function Circle.new(frame, v, m)
local self = setmetatable({
frame = frame,
radius = frame.AbsoluteSize.x/2,
center = frame.AbsolutePosition + frame.AbsoluteSize/2,
velocity = v,
acceleration = Vector2.new(0, 0),
position = frame.AbsolutePosition,
mass = m
}, Circle)
return self
end
function Circle:boundaryCollisions(walls)
local offset = Vector2.new(0, 36)
local bottom = (walls.Bottom.AbsolutePosition + offset).y
local left = (walls.Left.AbsolutePosition + offset).x
local top = (walls.Top.AbsolutePosition + offset).y
local right = (walls.Right.AbsolutePosition + offset).x
if self.position.y + self.radius * 2 >= bottom then
self.position = Vector2.new(self.position.x, bottom - self.radius * 2)
self.velocity = Vector2.new(self.velocity.x, self.velocity.y * -1)
elseif self.position.y <= top then
self.position = Vector2.new(self.position.x, top)
self.velocity = Vector2.new(self.velocity.x, self.velocity.y * -1)
end
if self.position.x + self.radius * 2 >= right then
self.position = Vector2.new(right - self.radius * 2, self.position.y)
self.velocity = Vector2.new(self.velocity.x * -1, self.velocity.y)
elseif self.position.x <= left then
self.position = Vector2.new(left, self.position.y)
self.velocity = Vector2.new(self.velocity.x * -1, self.velocity.y)
end
end
function Circle:circleCollisions(circles)
local colliding = false
local collisions = {}
local u1
local u2
for _, circle in ipairs(circles) do
if circle.frame ~= self.frame then
if ((self.frame.AbsolutePosition + self.frame.AbsoluteSize/2) - (circle.frame.AbsolutePosition + circle.frame.AbsoluteSize/2)).magnitude <= (self.radius + circle.radius) then
colliding = true
collisions[1] = circle
u1 = self.velocity
u2 = circle.velocity
end
end
end
if colliding then
local circle = collisions[1]
local v1 = ((self.mass - circle.mass)/(circle.mass + self.mass)) * u1 + ((2 * circle.mass)/(self.mass + circle.mass)) * u2
local v2 = ((2 * self.mass)/(self.mass + circle.mass)) * u1 + ((circle.mass - self.mass)/(circle.mass + self.mass)) * u2
self.velocity = v1
circle.velocity = v2
end
end
function Circle:move(walls, circles)
game:GetService("RunService").RenderStepped:Connect(function()
self:boundaryCollisions(walls)
self:circleCollisions(circles)
self.velocity += self.acceleration
self.position += self.velocity
self.frame.Position = UDim2.new(0, self.position.x, 0, self.position.y)
end)
end
return Circle
Physics Simulation Module:
local Physics = {}
Physics.__index = Physics
function Physics.new(circles, walls)
local self = setmetatable({
circles = circles,
walls = walls
}, Physics)
return self
end
function Physics:simulate()
for _, circle in ipairs(self.circles) do
circle:move(self.walls, self.circles)
end
end
return Physics
Client handler:
local physics = require(script.Physics)
local circles = require(script.Circle)
local canvas = script.Parent.Canvas
local circleTable = {}
for i = 0, 4 do
local newcircle = game:GetService("ReplicatedStorage").Circle:Clone()
newcircle.Position = UDim2.new(0, math.random(canvas.Walls.Left.AbsolutePosition.X, canvas.Walls.Right.AbsolutePosition.X), 0, math.random(canvas.Walls.Top.AbsolutePosition.Y, canvas.Walls.Bottom.AbsolutePosition.Y))
newcircle.Size = UDim2.new(0, 30, 0, 30)
newcircle.Parent = canvas
local circle = circles.new(newcircle, Vector2.new(math.random(-2, 2), math.random(-2, 2)), 1)
table.insert(circleTable, circle)
end
local init = physics.new(circleTable, {
Top = canvas.Walls.Top,
Bottom = canvas.Walls.Bottom,
Left = canvas.Walls.Left,
Right = canvas.Walls.Right
})
init:simulate()
StarterGui:
That’s all for today! I hope you enjoy this stuff, I am currently developing a 2D Gui Based physics engine for roblox, see ya if not tomorrow but soon with another post!