detecting a 3d conical range in front of an entity

Blitz3D Forums/Blitz3D Programming/detecting a 3d conical range in front of an entity

Anyone know the math, or a trick, for detecting if an entity is within a 3d conical range in front of or at any angle relative to another entity?

I'm trying to write a 3d space sim and I don't know how to check if the target ship is in front of the attacking ship in 3d space. I figured detecting the target within a cone in front of the attacker would be the best approach. Any ideas?



..i would suggest use of trigger(checking entity inside of given primitive parented to for example, head of your character)..use it with physics engines and forge about any problems..thats what i did anyway..

If you want to solve it with maths, you could use this approach:

1. I would take the target's coordinate, and use TFormPoint to convert them from world space into the Attacker's space.

That means that if Target is on the same place as the attacker, x,y,z will be 0,0,0.
If Target is right in front of Attacker, so that means if the Target is on the center axis of the imaginary cone you drew, x and y will still be zero, and z will be the distance between the two objects.
Basically, after using TFormPoint, x and y will give the distance from Target to the center axis of the cone, and z will give the distance from Target to Attacker (from the closest point on the z-axis).

2. Then, you can first check if z is in the range 0 to 2, and if it is, you can calculate if x*x+y*y < z*z.
If that is the case, the coordinates lie within the cone.

sqr(x*x+y*y) is the distance from the Target to the center of the cone.
z*z is the radius of the cone: the further away from Attacker, the bigger the radius of the cone should be. So in this case radius = z.
test = false

;make coordinates relative to attacker
TFormPoint EntityX(target), EntityY(target), EntityZ(target), 0, Attacker
x# = TFormedX()
y# = TFormedY()
z# = TFormedZ()

;check if z is in front of attacker, and not too far away
if (z >= 0) and (z <= 2) then

   ;check if distance between point and center of cone is smaller than 'z'
   ;which means that at the base of the cone, they should be zero, and at
   ;then end of the cone, they should be smaller than 2.
   if (x*x+y*y)<=(z*z) then test = true

end if


Here is a working example:
Graphics3D 800, 600, 0, 2
SetBuffer BackBuffer()

;create mesh
mesh = CreateSphere()
ScaleMesh mesh, 0.1, 0.1, 0.1

;create cone (just for visualisation, not used)
cone = CreateCone()
RotateMesh cone, 90, 0, 0
EntityAlpha cone, 0.1
EntityParent cone, mesh
PositionEntity cone, 0, 0, -1

;create camera
cpv = CreatePivot()
cam = CreateCamera(cpv)
MoveEntity cam, 0, 0, -5

;create base dot model
org = CreateSphere()
ScaleMesh org, 0.02, 0.02, 0.02
HideEntity org

;create several dots
piv = CreatePivot()
For x# = -1 To 1 Step 0.25
For y# = -1 To 1 Step 0.25
For z# = -1 To 1 Step 0.25

	nw = CopyEntity(org, piv)
	PositionEntity nw, x, y, z
	
Next
Next
Next

;main loop
Repeat

	;turn camera with cursor keys
	TurnEntity cpv, KeyDown(208) - KeyDown(200), KeyDown(205) - KeyDown(203), 0

	;loop through all dots (or entities that you want to check)
	For i = 1 To CountChildren(piv)
		
		nw = GetChild(piv, i)
		
		;reset flag
		sel = 0
		
		;check if 'nw' is inside cone
		TFormPoint EntityX(nw), EntityY(nw), EntityZ(nw), 0, mesh
		x# = TFormedX()
		y# = TFormedY()
		z# = TFormedZ()
		;check if 'z' is in cone range (0..-2)
		If (z <= 0) And (z >= -2) Then
			;check if 'x' and 'y' are in cone radius
			z = z / 2.0
			If (x * x + y * y) < z * z Then sel = 1 ;set flag
		End If

		;check flag		
		If sel = 1 Then 
			;make dot red
			EntityColor nw, 255, 0, 0
			EntityAlpha nw, 1.0
		Else
			;make dot semi-invisible
			EntityColor nw, 255, 255, 255
			EntityAlpha nw, 0.02
		End If
		
	Next

	;turn mesh (and cone along with it)
	TurnEntity mesh, 0, 1, 0
	
	;render
	RenderWorld
	Flip

;esc = exit	
Until KeyHit(1)

End


Wow! That's awesome! Thanks!

"fredborg" has a code archive for this too.

So..er...call me stoopid, but could the same be done with a sphere around the origin by simply changing the cone entity to a sphere? or if for whatever weird reasosn,s maybe a cube/cylinder/fish ?

No, each shape should have it's own function.
For a sphere, you can use EntityDistance(), because if the distance between a point and the center of the sphere is smaller than the radius of the sphere, the point lies within the sphere, else it lies on the outside.

For a cube, the comparisation should be more along the lines of:

isoutside = (x < left) or (x > right) or (z < front) or (z > back) or (y < top) or (y > bottom)

For a cylinder, the code would be similair to the cone, except this line:
if (x*x+y*y)<=(z*z) then test = true

should have a fixed radius, like this:
if (x*x+y*y)<=(2*2) then test = true

Because a cylinder has the same radius along it's entire length.

A fish-shaped detection area could maybe best be build up from basic shapes, such as cube,cylinder,sphere etc. Or maybe sin() or cos() if you're thinking about a yin-yang shaped fish:
Graphics 800, 600, 0, 2
SetBuffer BackBuffer()
Flip

LockBuffer()
For i = 0 To 800
For j = 0 To 600

	;sinus
	a = i-400
	b = j-300
	test1 = ((a*a+b*b)<200*200) 
	test = test1
	
	;circle
	test2 = (i < Sin(j-110) * 100 + 400) And test
	If test2 Then test = Not(test)
	
	;eye1
	a = i - 400
	b = j - 200
	test3 = ((a*a+b*b)<20*20) 
	If test3 Then test= Not(test)

	;eye2
	a = i - 400
	b = j - 380
	test3 = ((a*a+b*b)<20*20) 
	If test3 Then test= Not(test)

	;calc. color		
	r = test * 255
	g = (test Or test1) * 255
	b = test * 255
	WritePixelFast i, j, r+g*256+b*65536
	
Next
Next
UnlockBuffer()

Flip

WaitKey
End


Actually, it wasn't "fredborg" - might have been "shambler". I'll see if I can find it.

EDIT: nope, wasn't "shambler".