Ball Not Bouncing Correctly

I was making a pong-type game, and I ran into an issue.

Using jaipack17’s GuiCollisionService, I detect if a ball hits one of the “walls”. Once the ball hits the wall it reverses the rotation giving it a bounce affect.

Should I even use rotation in this sort of situation? or use more complex methods (which i’m not aware of)

Problem: The ball(s) aren’t “bouncing” or rotating correctly

Video of what happens currently when reversing the GUI objects rotation:

Code
	local ball = Main.Circle:Clone()
	local speed = 1
	local changable = true
	local changeCooldown = 1
	ball.Parent = Main
	ball.Visible = true
	ball.Rotation = math.random(-180,180)
	group:getHitter(1).CollidersTouched.Event:Connect(function(hits)
		if changable then
			changable = false
			ball.Rotation = -ball.Rotation -- WE CHANGE THE ROTATION HERE!
			task.wait(changeCooldown)
			changable = true
		end
	end)
	RunService.RenderStepped:Connect(function(dt)
		local pos = ball.Position
		local designated =  ball.Position + UDim2.new(
			math.cos(math.rad(ball.Rotation))/Main.AbsoluteSize.X * speed,
			0,
			math.sin(math.rad(ball.Rotation))/Main.AbsoluteSize.Y * speed,
			0
		)
		ball.Position = designated
	end)

once again, should I even use rotation or lean toward more advanced methods? or am I doing something wrong in my code?

I made this place around 2 years ago, I think this might have the effect you are looking for:
Screen Saver Simulator - Roblox

I read through it quite quickly now, and I’m gonna be honest, it is a bit of a headache.

local TS = game:GetService("TweenService")
-- Services ^
math.randomseed(os.time())

--- Appearance
local radius = 250 -- Particle target radis
local ratio = 5 -- How far the shortest distance is (radius/ratio)

local icon = script.Parent
local bg = script:FindFirstAncestorWhichIsA("ScreenGui")
local pos = icon.AbsolutePosition - bg.AbsolutePosition
local size = icon.AbsoluteSize
local bgSize = bg.AbsoluteSize
local angle = 45
local speed = icon.Speed.Value -- Unit is pixels / 0.025 seconds
local lastSize = bgSize

--icon.Position = UDim2.fromOffset((bgSize.X + size.X)/2, (bgSize.Y + size.Y)/2)

local missed = Vector2.new(0, 0)

function bounce(pos)
	lastSize = bgSize
	if pos == "top" then
		pos = UDim2.fromOffset(icon.Position.X.Offset + size.X/2, 0)
	elseif pos == "bot" then
		pos = UDim2.fromOffset(icon.Position.X.Offset + size.X/2, bgSize.Y)
	elseif pos == "left" then
		pos = UDim2.fromOffset(0, icon.Position.Y.Offset + size.Y/2)
	elseif pos == "right" then
		pos = UDim2.fromOffset(bgSize.X, icon.Position.Y.Offset + size.Y/2)
	else
		return
	end
	--[[ -- Doesn't work.
	local p = Instance.new("Frame")
	local a = Instance.new("UIAspectRatioConstraint", p)
	p.Size = UDim2.new(0, 10, 0, 10)
	p.Rotation = 0
	p.Position = pos
	p.BorderSizePixel = 0
	p.Parent = bg
	TS:Create(p, TweenInfo.new(.5), { Size = UDim2.fromOffset(math.random(10, 50), math.random(10, 50)), Rotation = 45 }):Play()
	local t = TS:Create(p, TweenInfo.new(1), { BackgroundTransparency = 1 })
	t:Play()
	t.Completed:Connect(function()
		p:Destroy()
	end)
	]]

	local maxX = pos.X.Offset + radius
	local minX = pos.X.Offset + radius/ratio
	local maxY = pos.Y.Offset + radius
	local minY = pos.Y.Offset + radius/ratio
	if maxX > bgSize.X then
		minX = maxX - 2*radius
		maxX = pos.X.Offset - radius/ratio
	end
	if maxY > bgSize.Y then
		minY = maxY - 2*radius
		maxY = pos.Y.Offset - radius/ratio
	end
	for i=1, 5, 1 do
		local p = Instance.new("Frame")
		local a = Instance.new("UIAspectRatioConstraint", p)
		p.Size = UDim2.new(0, math.random(5,25), 0, math.random(5,25))
		p.Rotation = math.random(0, 90)
		p.Position = pos
		p.BorderSizePixel = 0
		p.Parent = bg
		TS:Create(p, TweenInfo.new(5), { Position = UDim2.fromOffset(math.random(minX, maxX), math.random(minY, maxY)), Rotation = math.random(0, 1080)} ):Play()
		local t = TS:Create(p, TweenInfo.new(3), { BackgroundTransparency = 1 })
		t:Play()
		t.Completed:Connect(function()
			p:Destroy()
		end)
	end
end

wait(1.5)

function corner()
	if lastSize ~= bgSize then return end
	bg.Highlight.Visible = true
	local prevColor = bg.Background.BackgroundColor3
	local t = TS:Create(bg.Background, TweenInfo.new(.1), { BackgroundColor3 = Color3.fromRGB(100, 100, 100)})
	t:Play()
	t.Completed:Connect(function()
		TS:Create(bg.Background, TweenInfo.new(1), { BackgroundColor3 = prevColor}):Play()
		for _, bar in pairs(bg.Highlight:GetChildren()) do
			TS:Create(bar, TweenInfo.new(2), { BackgroundTransparency = 1}):Play()
		end
		wait(2)
		bg.Highlight.Visible = false
		for _, bar in pairs(bg.Highlight:GetChildren()) do
			bar.BackgroundTransparency = 0
		end
	end)
	bg.Background.cornerhits.Text = game.ReplicatedStorage.MasterFunc:InvokeServer("Cornerhit")
end

spawn(function()
	while wait(0.025) do
		-- Update variables
		pos = icon.AbsolutePosition - script:FindFirstAncestorWhichIsA("ScreenGui").AbsolutePosition
		size = icon.AbsoluteSize
		bgSize = bg.AbsoluteSize
		speed = icon.Speed.Value
		angle = angle%360
		-----------------------------
		-- Movement
		local newPos = Vector2.new((speed * math.cos(math.rad(angle)) + (missed.X%1)), (speed * math.sin(math.rad(angle)) + (missed.Y%1)))
		icon.Position = icon.Position + UDim2.fromOffset(newPos.X, newPos.Y)
		missed = missed - Vector2.new(missed.X%1, missed.Y%1)
		missed = missed + Vector2.new(newPos.X%1, newPos.Y%1)
		----------------------------
		-- Corner
		if pos.Y <= 0 or pos.Y + size.Y >= bgSize.Y then
			if pos.X <= 0 or pos.X + size.X >= bgSize.X then
				corner()
			end
		end
		----------------------------
		-- Bounce
		if pos.Y + size.Y >= bgSize.Y then -- Bottom
			angle = 360 - angle
			icon.Position = UDim2.fromOffset(icon.Position.X.Offset, bgSize.Y - size.Y - 1)
			bounce("bot")
		elseif pos.Y <= 0 then -- Top
			angle = 360 - angle
			icon.Position = UDim2.fromOffset(icon.Position.X.Offset, 1)
			bounce("top")
		elseif pos.X + size.X >= bgSize.X then
			angle = 180 - angle
			icon.Position = UDim2.fromOffset(bgSize.X - size.X - 1, icon.Position.Y.Offset)
			bounce("right")
		elseif pos.X <= 0 then
			bounce("left")
			angle = 180 - angle
			icon.Position = UDim2.fromOffset(1, icon.Position.Y.Offset)
		end
	end
end)

I (of course) didn’t leave any comments for my future self, but from reading through the code it looks like I changed the angle by using Axis - angle or something.

But the principles of the bounce is that the outgoing angle should be the same as the incoming one, except flipped on whichever axis you are at.

1 Like