2D detection by matrix rotation

This Tutorial is advanced its basically just matrix rotation

by kasicakim

Author Avatar

Matrix rotation can be used for Vector3s and Vector2s. Its about rotateing a Vector around the 0 position. Matrices are constructed by rows and columns, the rotation matrix we are going to use is 2x2 (2 rows and 2 columns) [cos(R) -sin(R).sin(R) cos(R)] the comma is a sign its the next row

When we multipliy the a Vector2 by the roation matrix we get a rotated vector by the angle we want, lets try and rotate a Vector2 by 90 deg:

	local v = Vector2.new(10, 10)
	local Rv = Vector2.new(v.X * math.cos(math.rad(90)) - v.Y * math.sin(math.rad(90)),
							v.X * math.sin(math.rad(90)) + v.Y * math.cos(math.rad(90)))

When calculated Rv = (-10, 10), as expected Vector v was rotated by 90. If we use this formula we can rotate the Frames by 360-R (R = the main frames rotation) and then check if any corner is inside the frame.

Another problem we run into is acually calculating the position of the corners, if a frame is rotated the position of its corners isnt equal to its position + size, we need to use the right triangle formulas and the center of the frame. The center of the frame is its position + its size/2 here is and example of a function to calculate all the corners:

	local function GetCorners(frame)
	
	local pos = frame.AbsolutePosition
	local size = frame.AbsoluteSize
	local rot = frame.AbsoluteRotation
	
	local center = pos + size/2
	local x = Vector2.new(math.cos(math.rad(rot))*(size.X/2), math.sin(math.rad(rot))*(size.X/2))
	local y = Vector2.new(math.cos(math.rad(rot+90))*(size.Y/2), math.sin(math.rad(rot+90))*(size.Y/2))
	
	local crs = {center - x - y,
				center + x - y,
				center - x + y,
				center + x + y}	

	return crs	
	
end

as we caluclated the corners we can now check if its inside the cube:

	local function GetCorners(frame)

	local pos = frame.AbsolutePosition
	local size = frame.AbsoluteSize
	local rot = frame.AbsoluteRotation

	local center = pos + size/2
	local x = Vector2.new(math.cos(math.rad(rot))*(size.X/2), math.sin(math.rad(rot))*(size.X/2))
	local y = Vector2.new(math.cos(math.rad(rot+90))*(size.Y/2), math.sin(math.rad(rot+90))*(size.Y/2))

	local crs = {center - x - y,
		center + x - y,
		center - x + y,
		center + x + y}	

	return crs	

end

local function CheckIfInsideRect(v1, cr1, cr2)
	
	-- V1 is the position we want to check
	-- cr1 is the top-right corner
	-- cr2 = is the lower-left corner
	
	if v1.X > cr1.X and v1.Y > cr1.Y then
		if v1.X < cr2.X and v1.Y < cr2.Y then
			return true
		end
	end
	return false
end

local function GetRotatedVector(angle, v)
	
	return Vector2.new(v.X*math.cos(math.rad(angle))-v.Y*math.sin(math.rad(angle))
		, v.X*math.sin(math.rad(angle))+v.Y*math.cos(math.rad(angle)))
	
	-- Just the matrix rotation
	
end

local cornerCollisions = {}

local function CheckRect(obj1, obj2)
	local angle = 360-obj2.AbsoluteRotation
	
	-- angle is equal to the rotation we need to rotate for the obj2s corners to be rotated back to zero
	
	local cr1 = GetCorners(obj1)
	local cr2 = GetCorners(obj2)
	
	local cr11 = GetRotatedVector(angle, cr1[1])
	local cr12 = GetRotatedVector(angle, cr1[2])
	local cr13 = GetRotatedVector(angle, cr1[3])
	local cr14 = GetRotatedVector(angle, cr1[4])

	local cr21 = GetRotatedVector(angle, cr2[1])
	local cr24 = GetRotatedVector(angle, cr2[4])
	
	-- all of the rotated angles
	
	local o1 = CheckIfInsideRect(cr11, cr21, cr24)
	local o2 = CheckIfInsideRect(cr12, cr21, cr24)
	local o3 = CheckIfInsideRect(cr13, cr21, cr24)
	local o4 = CheckIfInsideRect(cr14, cr21, cr24)
	
	-- check if the rotated corners of obj1 is inside obj2
	
	if o1 == true or o2 == true or o3 == true or o4 == true then
		return true
	end
	
	-- return true if any corners and inside obj2
	
	return false
end

local function CollisionTest(obj1, obj2)
	local o1 = CheckRect(obj2, obj1)
	local o2 = CheckRect(obj1, obj2)
	
	if o1 == true or o2 == true then
		return true
	end
	return false
end

works alright tho there is 100% faster code out there :p. hope this was helpfull :D

View in-game to comment, award, and more!