I was thinking of a solution along the lines of what's already been suggested here so didn't bother replying again... until I had a thought about another way it can be achieved: use a collision sphere. :)
It might be a bit of a hacky way of doing it but it seems to work fairly well - and fast. Why do all the hard work when you can get blitz to do it?! ;)
Here's a demo:
;
; Radial targeting demo using a collision sphere i.e. a bit of a hack :P
;
; By Big10p (A.K.A. Chris Chadwick) 2004
;
; Targets are found for any given turret by placing a sphere (with a radius equal to the turret's
; firing range) directly under the turret, then moving it up to surround the turret, and then seeing
; what enemies were hit in the process.
;
; This method also has the benefit of targeting the closest enemies (posing the greatest threat), as
; the sphere will hit them first.
;
; This demo only operates on a single plane but the same method should still be quite effective in
; targetting enemies above/below, too. For a flying turret, you could also do a check by placing the
; collision sphere above it and moving it downwards. This would find enemies below the turret, then.
;
Graphics3D 800,600,32
SetBuffer BackBuffer()
Type turretT
Field ent
Field vx#, vz#
Field shell, shell_dist#, loaded%
Field col_type
Field target, locked
End Type
Type gridT
Field x#,z#
End Type
WireFrame 0
AntiAlias 0
SeedRnd MilliSecs()
Const GROUND_SCALE# = 50.0
Const GROUND_SEG# = 5.0
Const TURRETS_PER_SIDE% = 30
Const RANGE# = 30.0 ; Turrets' firing range.
Const RED_COL% = 1
Const GREEN_COL% = 2
Const LAZER_COL% = 3
Const RANGE_COL% = 4
Global frame_count%
Global fps%
Global slowest_fps%
Global fps_timeout%
Global frame_time%
Global slowest_frame%
Global frame_start%
fps_timer = CreateTimer(60)
slowmo% = False
piv = CreatePivot()
cam = CreateCamera(piv)
PositionEntity cam,0,60,-60
PointEntity cam,piv
light = CreateLight(1,cam)
Global ground = CreateCube()
ScaleMesh ground,GROUND_SCALE,1,GROUND_SCALE
EntityColor ground,100,100,200
PositionEntity ground,0,-2,0
EntityAlpha ground,.4
m = CreateMirror()
PositionEntity m,0,-1,0
Global turret_mesh,shell_mesh
create_meshes()
; Collision sphere used to check for in-range enemies.
; (using sphere for debug - could use a pivot, though)
Global range_sphere = CreateSphere()
ScaleEntity range_sphere,RANGE,RANGE,RANGE
EntityType range_sphere,RANGE_COL
EntityRadius range_sphere,RANGE
;EntityAlpha range_sphere,.5
HideEntity range_sphere
init_turrets()
set_collisions()
this_turret.turretT = First turretT
; --- Main loop ---
While Not KeyHit(1)
frame_start = MilliSecs()
TurnEntity piv,0,.1,0
If KeyDown(205) Then TranslateEntity cam,.5,0,0
If KeyDown(203) Then TranslateEntity cam,-.5,0,0
If KeyDown(200) Then TranslateEntity cam,0,0,.5
If KeyDown(208) Then TranslateEntity cam,0,0,-.5
If KeyDown(30) Then MoveEntity cam,0,0,.5
If KeyDown(44) Then MoveEntity cam,0,0,-.5
If KeyHit(57) Then slowmo = Not slowmo
act_on_collisions()
; Take it in turns to update each turret's target every frame.
get_target(this_turret)
this_turret = After this_turret
If this_turret = Null Then this_turret = First turretT
update_turrets()
UpdateWorld
RenderWorld
frame_time = MilliSecs() - frame_start
show_info()
WaitTimer(fps_timer)
Flip(1)
If slowmo Then Delay 500
Wend
ClearWorld
End
;
;
;
Function act_on_collisions()
For t.turretT = Each turretT
If EntityCollided(t\shell,GREEN_COL) Or EntityCollided(t\shell,RED_COL)
t\shell_dist = 0
t\loaded = True
HideEntity t\shell
EndIf
If EntityCollided(t\ent,GREEN_COL) Or EntityCollided(t\ent,RED_COL)
t\vx = -t\vx
t\vz = -t\vz
EndIf
Next
End Function
;
;
;
Function update_turrets()
For t.turretT = Each turretT
; Turret movement control.
tx# = EntityX(t\ent,1)+t\vx
ty# = EntityY(t\ent,1)
tz# = EntityZ(t\ent,1)+t\vz
PositionEntity t\ent,tx,ty,tz
If Abs(tx) > GROUND_SCALE Then t\vx = -t\vx
If Abs(tz) > GROUND_SCALE Then t\vz = -t\vz
; Turret aiming control.
If t\target
; Consider pitch and yaw in order to aim at targets above/below.
; (only really need yaw for this demo, though)
dp# = DeltaPitch(t\ent,t\target)
dy# = DeltaYaw(t\ent,t\target)
TurnEntity t\ent,dp/10.0,dy/10.0,0
If Abs(dp) < 5.0 And Abs(dy) < 5.0 Then t\locked = True
Else
TurnEntity t\ent,0,1,0
EndIf
; Turret firing control.
If Not t\loaded
MoveEntity t\shell,0,0,1
t\shell_dist = t\shell_dist + 1
EndIf
If t\locked And t\loaded
; FIRE!!!!!!!!!
t\loaded = False
PositionEntity t\shell,EntityX(t\ent,1),EntityY(t\ent,1),EntityZ(t\ent,1)
RotateEntity t\shell,EntityPitch(t\ent,1),EntityYaw(t\ent,1),EntityRoll(t\ent,1)
MoveEntity t\shell,0,0,2.5
ShowEntity t\shell
t\shell_dist = 2.5
EndIf
If t\shell_dist > RANGE
t\shell_dist = 0
t\loaded = True
HideEntity t\shell
EndIf
Next
End Function
;
;
;
Function set_collisions()
ClearCollisions
Collisions RED_COL,RED_COL,1,1
Collisions RED_COL,GREEN_COL,1,1
Collisions GREEN_COL,GREEN_COL,1,1
Collisions GREEN_COL,RED_COL,1,1
Collisions LAZER_COL,GREEN_COL,1,1
Collisions LAZER_COL,RED_COL,1,1
End Function
;
;
;
Function init_turrets()
w# = GROUND_SCALE*2
rc = w/GROUND_SEG
gc = 0
For row = 1 To rc
For col = 1 To rc
g.gridT = New gridT
g\x = (-(w/2) + (((col-1) * GROUND_SEG) + GROUND_SEG/2))+Rnd(-(GROUND_SEG/3),(GROUND_SEG/3))
g\z = ((w/2) - (((row-1) * GROUND_SEG) + GROUND_SEG/2))+Rnd(-(GROUND_SEG/3),(GROUND_SEG/3))
gc = gc + 1
Next
Next
For red = 1 To TURRETS_PER_SIDE
this.gridT = First gridT
rg = Rand(1,gc)
For n = 2 To rg
this = After this
Next
create_turret(RED_COL,this\x,0,this\z)
Delete this
gc = gc - 1
Next
For green = 1 To TURRETS_PER_SIDE
this.gridT = First gridT
rg = Rand(1,gc)
For n = 2 To rg
this = After this
Next
create_turret(GREEN_COL,this\x,0,this\z)
Delete this
gc = gc - 1
Next
Delete Each gridT
End Function
;
;
;
Function get_target(t.turretT)
tx# = EntityX(t\ent,1)
ty# = EntityY(t\ent,1)
tz# = EntityZ(t\ent,1)
If t\col_type = GREEN_COL Then targ_col = RED_COL Else targ_col = GREEN_COL
ClearCollisions
Collisions RANGE_COL,targ_col,1,1
PositionEntity range_sphere,tx,ty-RANGE-1,tz
ShowEntity range_sphere
PositionEntity range_sphere,tx,ty,tz
UpdateWorld 0
new_targ = EntityCollided(range_sphere,targ_col)
If new_targ <> t\target
t\locked = False
t\target = new_targ
EndIf
HideEntity range_sphere
set_collisions()
End Function
;
;
;
Function create_turret(col_type,x#,y#,z#)
t.turretT = New turretT
t\ent = CopyEntity(turret_mesh)
t\col_type = col_type
t\vx = Rnd(-.1,.1)
t\vz = Rnd(-.1,.1)
t\loaded = True
t\locked = False
t\target = 0
t\shell_dist = 0
EntityType t\ent,col_type
EntityRadius t\ent,1
PositionEntity t\ent,x,y,z
t\shell = CopyEntity(shell_mesh)
HideEntity t\shell
EntityType t\shell,LAZER_COL
EntityRadius t\shell,.09
If col_type = GREEN_COL
EntityColor t\ent,0,100,0
EntityColor t\shell,0,255,0
Else
EntityColor t\ent,100,0,0
EntityColor t\shell,255,0,0
EndIf
End Function
;
;
;
Function create_meshes()
turret_mesh = CreateCylinder(16)
gun = CreateCylinder()
ScaleMesh gun,.2,1,.2
RotateMesh gun,-90,0,0
PositionMesh gun,0,0,1
AddMesh gun,turret_mesh
FreeEntity gun
HideEntity turret_mesh
shell_mesh = CreateCylinder()
RotateMesh shell_mesh,-90,0,0
ScaleMesh shell_mesh,.09,.09,1
EntityFX shell_mesh,1
HideEntity shell_mesh
End Function
;
; Display debug info
;
Function show_info()
If fps_timeout
frame_count = frame_count + 1
If MilliSecs() > fps_timeout Then
fps_timeout = MilliSecs() + 1000
fps = frame_count
frame_count = 0
If fps < slowest_fps Or slowest_fps = 0 Then slowest_fps = fps
EndIf
If frame_time > slowest_frame Then slowest_frame = frame_time
Color 0,255,0
Text 10,10," Triangles: " + TrisRendered()
Color 255,255,0
Text 10,25," Millisecs: " + frame_time
Text 10,40," Slowest: " + slowest_frame
Color 0,255,255
Text 10,55," FPS: " + fps
Text 10,70," Worst: " + slowest_fps
Color 255,255,255
Text 10,100,"Total Turrets: " + TURRETS_PER_SIDE*2
Text 10,115,"Press ARROW KEYS to move camera."
Text 10,130,"Press A/Z to zoom camera."
Text 10,145,"Press SPACE to toggle slowmo."
Else
; First call initialization.
fps_timeout = MilliSecs() + 1000
EndIf
End Function