Physics with GUI only?

So I have been working on a system that has basically a ball that bounces off the wall, its working great but for some reason even when you make it go at an angle it just goes back in the same angle opposite and then back in opposite of that angle (and basically just goes back and forth forever) even tho it should have some variations and change angles like go from right to left to more right if that makes sense

Video of it: Watch newvideo | Streamable

Code:

local PhysicsFrame = script.Parent
local Ball = PhysicsFrame:WaitForChild("Ball")
local Walls = PhysicsFrame:WaitForChild("Walls"):GetChildren()

local SPEED = 500 
local velocity = Vector2.new(5, 1).Unit * SPEED 

local function getAbsolutePosition(guiObject)
	return guiObject.AbsolutePosition, guiObject.AbsoluteSize
end

local function checkCollision(ballPos, ballSize, wallPos, wallSize)
	return ballPos.X < wallPos.X + wallSize.X and
		ballPos.X + ballSize.X > wallPos.X and
		ballPos.Y < wallPos.Y + wallSize.Y and
		ballPos.Y + ballSize.Y > wallPos.Y
end

local function updatePhysics()
	local deltaTime = game:GetService("RunService").RenderStepped:Wait()

	local newPosition = Ball.Position + UDim2.new(
		velocity.X * deltaTime / PhysicsFrame.AbsoluteSize.X,
		0,
		velocity.Y * deltaTime / PhysicsFrame.AbsoluteSize.Y,
		0
	)

	local ballPos, ballSize = getAbsolutePosition(Ball)
	local newBallPos = Vector2.new(
		newPosition.X.Scale * PhysicsFrame.AbsoluteSize.X,
		newPosition.Y.Scale * PhysicsFrame.AbsoluteSize.Y
	)

	for _, wall in pairs(Walls) do
		local wallPos, wallSize = getAbsolutePosition(wall)

		if checkCollision(newBallPos, ballSize, wallPos, wallSize) then

			velocity = -velocity
			break 
		end
	end

	newPosition = UDim2.new(
		math.clamp(newPosition.X.Scale, 0, 1 - Ball.Size.X.Scale),
		0,
		math.clamp(newPosition.Y.Scale, 0, 1 - Ball.Size.Y.Scale),
		0
	)

	Ball.Position = newPosition
end

game:GetService("RunService").RenderStepped:Connect(updatePhysics)
1 Like

Read this article then:

Getting the normal would be hard but you could just use some basic maths to find it out, like if the ball’s position is on the right side of the gui you can just see if the X difference between the GUI and the ball is greater than zero and the same goes for left. Same goes for up and down but with Y axis.

1 Like

Hm well now its working but for some reason the walls collision is off? like for some reason the walls collission isnt lined up correctly

Its going out here and its not glitching its just thinking that its following the rules

local PhysicsFrame = script.Parent
local Ball = PhysicsFrame:WaitForChild("Ball")
local Walls = PhysicsFrame:WaitForChild("Walls"):GetChildren()

local SPEED = 500 
local velocity = Vector2.new(5, 1).Unit * SPEED 

local RunService = game:GetService("RunService")

local function getAbsolutePosition(guiObject)
	if guiObject then
		return guiObject.AbsolutePosition, guiObject.AbsoluteSize
	else
		return Vector2.new(0, 0), Vector2.new(0, 0)
	end
end

local function checkCollision(ballPos, ballSize, wallPos, wallSize)
	return ballPos.X < wallPos.X + wallSize.X and
		ballPos.X + ballSize.X > wallPos.X and
		ballPos.Y < wallPos.Y + wallSize.Y and
		ballPos.Y + ballSize.Y > wallPos.Y
end

local function reflectVelocity(wallName)
	if wallName == "LeftWall" or wallName == "RightWall" then
		velocity = Vector2.new(-velocity.X, velocity.Y)
	elseif wallName == "TopWall" or wallName == "BottomWall" then
		velocity = Vector2.new(velocity.X, -velocity.Y)
	end
end

local function updatePhysics()
	local deltaTime = RunService.RenderStepped:Wait()

	local newPosition = Ball.Position + UDim2.new(
		velocity.X * deltaTime / PhysicsFrame.AbsoluteSize.X,
		0,
		velocity.Y * deltaTime / PhysicsFrame.AbsoluteSize.Y,
		0
	)

	local ballPos, ballSize = getAbsolutePosition(Ball)
	local newBallPos = Vector2.new(
		newPosition.X.Scale * PhysicsFrame.AbsoluteSize.X,
		newPosition.Y.Scale * PhysicsFrame.AbsoluteSize.Y
	)

	for _, wall in pairs(Walls) do
		local wallPos, wallSize = getAbsolutePosition(wall)

		if checkCollision(newBallPos, ballSize, wallPos, wallSize) then
			reflectVelocity(wall.Name)
			break 
		end
	end

	newPosition = UDim2.new(
		math.clamp(newPosition.X.Scale, 0, 1 - Ball.Size.X.Scale),
		0,
		math.clamp(newPosition.Y.Scale, 0, 1 - Ball.Size.Y.Scale),
		0
	)

	Ball.Position = newPosition
end

RunService.RenderStepped:Connect(updatePhysics)

It’s your maths. It’s wrong.

local function CheckCollissions(Gui1:GuiObject,Gui2:GuiObject)
	local Gui1_TopLeft,Gui2_TopLeft = Gui1.AbsolutePosition,Gui2.AbsolutePosition
	local Gui1_BottomRight,Gui2_BottomRight = Gui1_TopLeft + Gui1.AbsoluteSize,Gui2_TopLeft + Gui2.AbsoluteSize

	return Gui1_BottomRight.X > Gui2_TopLeft.X and Gui1_BottomRight.Y > Gui2_TopLeft.Y and Gui1_TopLeft.Y < Gui2_BottomRight.Y and Gui1_TopLeft.X < Gui2_BottomRight.X
end

Here is mine, it’s correct.

Maybe. But just try out my version to see if it works.

1 Like

Well it actually made it work but also not work for some reason

Now the collision is working (like the position and size of the box)

but its just glitching in the wall instead of bouncing off for some reason
CrosshairX_sEh1vqNjba

its like staying on the outer place?

That’s because of your bouncing code part, The ball simply doesn’t get enough time to get out of collission to continue it’s path. I think a neat fix to this would be just blacklist said wall until the projectile collides again. Something like:

local blackLists = {}
local function reflectVelocity(wallName)
	if table.find(blackLists,wallName) then return end
	table.clear(blackLists)
	table.insert(blackLists,wallName)
	if wallName == "LeftWall" or wallName == "RightWall" then
		velocity = Vector2.new(-velocity.X, velocity.Y)
	elseif wallName == "TopWall" or wallName == "BottomWall" then
		velocity = Vector2.new(velocity.X, -velocity.Y)
	end
end
1 Like

it works perfectly now you are a genius

Thanks. I just make 2d games a lot.

1 Like

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