How would I go about making an AOE Cone Spell like in All Star Tower Defense

Hey everyone.
I’m wondering on how can I make a Cone AOE Effect on my spells.
For exemple, in All Star Tower Defense, they use Cone AOE for a lot of units. It looks like this:
image
It is smaller close to the character and windens with the distance.
How could I make this? I thought about Region3 but I think it is only square tell me if i’m wrong.
Thx for your help.

4 Likes

I would use Region3 to get the initial selection of possible targets. But then use Magnitude to refine the distance. This will turn the Region3 box selection into a spherical selection box.

Magnitude returns the length of a vector so by subtracting two vectors and getting the difference of those two vectors. Which by using Magnitude gets you the length of that vector as one number.

I know how Region3 and Magnitude work.
I can create a rectangular prism using Region3.new(V1, V2). But I don’t understand how can I turn a Region3 box selection to a spherical selection box.

You get the selection of targets in the Region3 and then loop through them to check for distance with magnitude by comparing it to the radius of the sphere you want.

local Point1 = Vector3.new(0,0,0)
local Point2 = Vector3.new(10,10,10)
local Center = Vector3.new(5,5,5)

local Region = Region3.new(Point1,Point2)
for _,Part in pairs(game.Workspace:FindPartsInRegion3(Region,nil,math.huge)) do
  if Part.Position-Center.magnitude <= 5 then
     print(Part.Name.." is in range!")
  end
end

I understand what you mean by Spherical Selection Box.
So this is a spherical box. And it is not a Cone if I’m right.
This can really help me.
Anyway to make a cone too?

So the visual will shows a sphere but the actual range will be a cone? Sorry, I just got confused as I assumed the picture showed the intended shape.

Edit: Are the lines facing outside of the sphere the cone shape you want? As I do know how to figure that out using Dot Products to test if your figure has line of sight to the target.

1 Like

Yes that’s it, on the picture, you can see a sphere around Sasuke. The sphere represent his range. And the two lines is the Cone AOE. So when Sasuke attack, he face the target and all the units in the Cone will take damage.

I’m watching the video.

DotProduct can work I think, if I calculate the FOV, I can change the dotProduct to have the cone I want.
Do you think it is the best way to do a Cone AOE?

1 Like

If it’s crucial that the degree of FOV must be spot on you could also try using math.atan2 but in terms of keeping your code simple, Dot Products are much better.

So to make it simple I should use Dot Products but math.atan2 (I never heard about it) could be better?

If you want to have the most accurate FOV possible and couldn’t determine the dot product value that matches the angle you need for your FOV then I would use math.atan2, if you don’t understand Trigonometry then I would just stick to Dot Products.

I would personally just stick to Dot Products, I just gave the recommendation in case you wanted a different method.

1 Like

Can you give me simple view on what I have to know about trigonometry to use math.atan2 please. I don’t like to take the easiest way.
I think, I should learn atan2 a day.

Yes, let me get an image that can explain it. Since Tribometry is all about triangles.

So Lua’s math library has a function math.atan2(y,x) The two numbers are the coordinates for the third point in a triangle.

image

Now to relate it to finding the angle between your character, Sasuke, and the enemy they are looking at you want to get the position of Sasuke and the position of the enemy. Subtract these Vectors and you’ll get the required y & x values for the math.atan2(y,x) function. This function will return the angle in radiants which can be converted into degrees using math.deg(number). But since this number could come back positive of negative before comparing it to the FOV you need to get it to be the absolute value using math.abs(number).

Note: that this will not be interfered by vertical distance, this function will return true even if the enemy is 50 studs above Sasuke’s head.

local function isInFOV(rootPosition,enemyPositon,fieldOfView)
    local distance = rootPosition - enemyPosition
    local radians = math.atan2(distance.Z,distance,X) --Make sure to use distance.Z so you get the angle for the right plane.
    local degrees = math.abs(math.deg(radians))
    if degees =< FOV/2 then
       return true
    else
       return false
    end
end
1 Like

That’s awesome. You made it so clear to understand for me. I get the point of math.atan2 in this case.
Do I still need Region3 here? I can just take all the potential units, check if they are in the FOV of Sasuke and if they are I find the magnitude between Sasuke and the unit and if the unit is in Sasuke’s range and in FOV I can Damage them.

local function isInFOV(rootPosition,enemyPositon,fieldOfView)
    local distance = rootPosition - enemyPosition
    local radians = math.atan2(distance.Z,distance,X) --Make sure to use distance.Z so you get the angle for the right plane.
    local degrees = math.abs(math.deg(radians))
    if degees =< FOV/2 and (rootPosition - enemyPosition).magnitude <= sasuke:GetAttribute("Range") then -- Note: Sasuke was defined before.
       return true
    else
       return false
    end
end

Is it right? Should I use Region3 to reduce the number of looped Units?

Yes would still recommend using Region3 to decrease the length of your loop, sorry for the late reply.

1 Like

No problem. I’ll try this and I’ll come back to you if I’m facing an issue and even if it works to thank you.
Thank you a lot for your help! I’ll come back to you soon!

Hey! I’m back.
So I did test this code for my AOE Cone and it doesn’t work at all… I’m not using Region3 yet because I want the FOV to work before. And this is what I tried…

function mainFunctions.isInFOV(rootPosition, enemyPosition, FOV)
	local distance = rootPosition - enemyPosition
	local radians = math.atan2(distance.Z, distance.X)
	local degrees = math.abs(math.deg(radians))
	if degrees < FOV/2 then
		print("true")
		return true
	else
		return false
	end
end

In the rootPosition, I send the position of “Sasuke”, in the enemyPosition I send the position of the looped enemies (so all the current enemies in the game) and in the FOV I send the degrees of my Cone so 50 in this case.
And it doesn’t work at all… It damages enemies that are very far from the attack…
I don’t really understand what’s happening. Please help!

To help with debugging could you print the degrees value. Since it’s possible it might need to have an offset added/subtracted to it.

And an error on my end, I forgot that math.atan2 doesn’t return the shortest angle, meaning on it’s own it won’t return a negative angle value. So I added a conditional check to account for this.

function mainFunctions.isInFOV(rootPosition, enemyPosition, FOV)
	local distance = rootPosition - enemyPosition
	local radians = math.atan2(distance.Z, distance.X)
	local degrees = math.deg(radians)
	
	if degrees > 180 then
		degrees = -(360-degrees)
	end
	
	local degrees = math.abs(degrees)

	if degrees < FOV/2 then
		print("true")
		return true
	else
		return false
	end
end

Ok I have some news!
Here is a test I made, I looped all the little balls and change the color to green if they are in the FOV of the blue part. Red means they are outside and green means they are inside.
Here is the result:

The blue part faces the left group of balls. As you can see the FOV is behind the rootPart (blue part wich represents Sasuke). But it works. How can I make it face the otherside (front face)