What can i optimize in this tower defense range checking?

Soo today i thought about making range system similar to TDX, i decided to check if enemy is in range with tower, and if it is i’ll use this code to check if tower can shoot without obstructions

-- Settings
local Radius = 32
local Triangles = 64

local Indicator = workspace.Indicator

local function IsInPolygon(Points: {Vector3}, part: BasePart): boolean
	local intersections = 0
	local x, y = part.Position.X, part.Position.Z

	for i = 1, #Points do
		local x1, y1 = Points[i].X, Points[i].Z

		local nextVertex = Points[i+1] or Points[1]
		local x2, y2 = nextVertex.X, nextVertex.Z

		if (y < y1) ~= (y < y2) and x < (x2 - x1)*(y - y1)/(y2-y1)+x1 then
			intersections += 1
		end
	end

	return intersections % 2 == 1
end

local function GetFinishPoints(start: Vector3): {Vector3}
	local Points = {}
	for i = 1, Triangles do
		local angle = i * (math.pi*2/Triangles)
		Points[i] = start + Vector3.new(math.sin(angle) * Radius, 0, math.cos(angle) * Radius)
	end
	
	return Points
end

local function Visualize(Points: {Vector3})
	local result
	for i, position in Points do
		local previousPoint = Points[i - 1] or Points[#Points]
		local currentPoint = Points[i]
		local nextPoint = Points[i + 1] or Points[1]
		
		local Line = Instance.new("Part")
		Line.Name = "Line"..i

		Line.Anchored = true
		Line.CanCollide = false
		Line.CanQuery = false
		Line.CastShadow = false

		Line.Color = Color3.new(0.333333, 0.666667, 1)
		Line.Material = Enum.Material.Neon

		Line.Size = Vector3.new(0.5,0.5,(currentPoint - nextPoint).Magnitude)
		Line.CFrame = CFrame.lookAt(currentPoint, nextPoint)
		Line.Position = (currentPoint:Lerp(nextPoint,0.5))

		Line.Parent = script.Parent.Parts
		
		local Line2 = Instance.new("Part")
		Line2.Name = "Line"..i

		Line2.Anchored = true
		Line2.CanCollide = false
		Line2.CanQuery = false
		Line2.CastShadow = false

		Line2.Color = Color3.new(1, 0, 0.498039)
		Line2.Material = Enum.Material.Neon

		Line2.Size = Vector3.new(4/Triangles,4/Triangles,(script.Parent.Position - currentPoint).Magnitude)
		Line2.CFrame = CFrame.lookAt(script.Parent.Position, currentPoint)
		Line2.Position = (script.Parent.Position:Lerp(currentPoint,0.5))

		Line2.Parent = script.Parent.Parts
	
	end
	local result = IsInPolygon(Points, Indicator)
	if result then
		Indicator.Material = Enum.Material.Neon
	else
		Indicator.Material = Enum.Material.SmoothPlastic
	end
end

local function GetObstacles(start: Vector3, Points: Vector3): {Vector3}
	local FixedPoints = {}
	for i, position in Points do
		local finish
		
		local raycastResult = workspace:Raycast(start, (position - start))
		if raycastResult then
			finish = raycastResult.Position
		end
		FixedPoints[i] = finish or position
		
	end

	return FixedPoints
end


while true do
	script.Parent.Parts:ClearAllChildren()
	local Points = GetFinishPoints(script.Parent.Position)
	local Fixed = GetObstacles(script.Parent.Position, Points)
	Visualize(Fixed)
	
	task.wait(0)
end

I used raycasting algorithm from this and of course some visual checking, i only ask if i can optimize it soo it can run few hundred times per second without performance issues on server, consider that triangle count will be around 16

Here is a video of how system looks for now:

thx for help

1 Like

I’ve tried to optimize this code further but your code seems to be in the best version it can be :sweat_smile:
Love the even–odd rule implementation btw.

Though I’m wondering why wouldn’t a simple raycast suffice? If you won’t be using this type of visualizing in live servers of course. This code wants to check if another object is obstructing the main object’s view of the target.

Except, if I’m missing another use case here.

2 Likes

thx for reply, i managed to optimize it by logic xd, i decided that i should first distance check using spatial grid (most of time it would be 5-7 cells of grid) and then raycast check if object is really in our tower’s view, thx again

2 Likes