Progress on Route

This commit is contained in:
FlightControl 2016-07-03 07:49:26 +02:00
parent 4ac962a87a
commit 23ea389b8f
16 changed files with 506 additions and 97 deletions

View File

@ -153,7 +153,7 @@ function AIBALANCER:_ClientAliveMonitorScheduler()
-- If there is no CLIENT within the self.ReturnTresholdRange, then the unit will return to the Airbase return method selected.
local PlayerInRange = { Value = false }
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetPointVec2(), self.ReturnTresholdRange )
local RangeZone = ZONE_RADIUS:New( 'RangeZone', AIGroup:GetVec2(), self.ReturnTresholdRange )
self:E( RangeZone )
@ -183,7 +183,7 @@ function AIBALANCER:_ClientAliveMonitorScheduler()
else
-- Okay, we need to send this Group back to the nearest base of the Coalition of the AI.
--TODO: i need to rework the POINT_VEC2 thing.
local PointVec2 = POINT_VEC2:New( AIGroup:GetPointVec2().x, AIGroup:GetPointVec2().y )
local PointVec2 = POINT_VEC2:New( AIGroup:GetVec2().x, AIGroup:GetVec2().y )
local ClosestAirbase = self.ReturnAirbaseSet:FindNearestAirbaseFromPointVec2( PointVec2 )
self:T( ClosestAirbase.AirbaseName )
AIGroup:MessageToRed( "Returning to " .. ClosestAirbase:GetName().. " ...", 30 )

View File

@ -588,7 +588,7 @@ function CONTROLLABLE:TaskOrbitCircle( Altitude, Speed )
local DCSControllable = self:GetDCSObject()
if DCSControllable then
local ControllablePoint = self:GetPointVec2()
local ControllablePoint = self:GetVec2()
return self:TaskOrbitCircleAtVec2( ControllablePoint, Altitude, Speed )
end
@ -765,7 +765,7 @@ function CONTROLLABLE:TaskLandAtZone( Zone, Duration, RandomPoint )
if RandomPoint then
Point = Zone:GetRandomVec2()
else
Point = Zone:GetPointVec2()
Point = Zone:GetVec2()
end
local DCSTask = self:TaskLandAtVec2( Point, Duration )
@ -1365,7 +1365,7 @@ end
function CONTROLLABLE:TaskRouteToVec2( Point, Speed )
self:F2( { Point, Speed } )
local ControllablePoint = self:GetUnit( 1 ):GetPointVec2()
local ControllablePoint = self:GetUnit( 1 ):GetVec2()
local PointFrom = {}
PointFrom.x = ControllablePoint.x
@ -1504,7 +1504,7 @@ function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
if DCSControllable then
local ControllablePoint = self:GetPointVec2()
local ControllablePoint = self:GetVec2()
local PointFrom = {}
PointFrom.x = ControllablePoint.x
@ -1520,7 +1520,7 @@ function CONTROLLABLE:TaskRouteToZone( Zone, Randomize, Speed, Formation )
if Randomize then
ZonePoint = Zone:GetRandomVec2()
else
ZonePoint = Zone:GetPointVec2()
ZonePoint = Zone:GetVec2()
end
PointTo.x = ZonePoint.x
@ -1602,7 +1602,7 @@ function CONTROLLABLE:RouteReturnToAirbase( ReturnAirbase, Speed )
if DCSControllable then
local ControllablePoint = self:GetPointVec2()
local ControllablePoint = self:GetVec2()
local ControllableVelocity = self:GetMaxVelocity()
local PointFrom = {}
@ -1614,7 +1614,7 @@ function CONTROLLABLE:RouteReturnToAirbase( ReturnAirbase, Speed )
local PointTo = {}
local AirbasePoint = ReturnAirbase:GetPointVec2()
local AirbasePoint = ReturnAirbase:GetVec2()
PointTo.x = AirbasePoint.x
PointTo.y = AirbasePoint.y

View File

@ -674,7 +674,7 @@ function ESCORT._HoldPosition( MenuParam )
PointFrom.alt = GroupPoint.y
PointFrom.alt_type = AI.Task.AltitudeType.BARO
local OrbitPoint = OrbitUnit:GetPointVec2()
local OrbitPoint = OrbitUnit:GetVec2()
local PointTo = {}
PointTo.x = OrbitPoint.x
PointTo.y = OrbitPoint.y
@ -867,7 +867,7 @@ function ESCORT._AttackTarget( MenuParam )
SCHEDULER:New( EscortGroup,
EscortGroup.PushTask,
{ EscortGroup:TaskCombo(
{ EscortGroup:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 )
{ EscortGroup:TaskFireAtPoint( AttackUnit:GetVec2(), 50 )
}
)
}, 10
@ -907,7 +907,7 @@ function ESCORT._AssistTarget( MenuParam )
SCHEDULER:New( EscortGroupAttack,
EscortGroupAttack.PushTask,
{ EscortGroupAttack:TaskCombo(
{ EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetPointVec2(), 50 )
{ EscortGroupAttack:TaskFireAtPoint( AttackUnit:GetVec2(), 50 )
}
)
}, 10

View File

@ -475,12 +475,12 @@ end
--- Returns the current point (Vec2 vector) of the first DCS Unit in the DCS Group.
-- @param #GROUP self
-- @return DCSTypes#Vec2 Current Vec2 point of the first DCS Unit of the DCS Group.
function GROUP:GetPointVec2()
function GROUP:GetVec2()
self:F2( self.GroupName )
local UnitPoint = self:GetUnit(1)
UnitPoint:GetPointVec2()
local GroupPointVec2 = UnitPoint:GetPointVec2()
UnitPoint:GetVec2()
local GroupPointVec2 = UnitPoint:GetVec2()
self:T3( GroupPointVec2 )
return GroupPointVec2
end

View File

@ -138,7 +138,7 @@ function PATROLZONE:NewPatrolRoute()
-- If not, make a waypoint within the to that the PatrolGroup will fly at maximum speed to that point.
-- --- Calculate the current route point.
-- local CurrentVec2 = self.PatrolGroup:GetPointVec2()
-- local CurrentVec2 = self.PatrolGroup:GetVec2()
-- local CurrentAltitude = self.PatrolGroup:GetUnit(1):GetAltitude()
-- local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
-- local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(

View File

@ -4,6 +4,9 @@
-- ===============================================
-- The @{Point#POINT_VEC3} class defines a 3D point in the simulator.
--
-- **Important Note:** Most of the functions in this section were taken from MIST, and reworked to OO concepts.
-- In order to keep the credibility of the the author, I want to emphasize that the of the MIST framework was created by Grimes, who you can find on the Eagle Dynamics Forums.
--
-- 1.1) POINT_VEC3 constructor
-- ---------------------------
--
@ -28,6 +31,7 @@
--- The POINT_VEC3 class
-- @type POINT_VEC3
-- @extends Base#BASE
-- @field DCSTypes#Vec3 PointVec3
-- @field #POINT_VEC3.SmokeColor SmokeColor
-- @field #POINT_VEC3.FlareColor FlareColor
-- @field #POINT_VEC3.RoutePointAltType RoutePointAltType
@ -48,6 +52,7 @@ POINT_VEC3 = {
White = trigger.flareColor.White,
Yellow = trigger.flareColor.Yellow
},
Metric = true,
RoutePointAltType = {
BARO = "BARO",
},
@ -114,6 +119,148 @@ function POINT_VEC3:New( x, y, z )
end
--- Return the coordinates of the POINT_VEC3 in Vec3 format.
-- @param #POINT_VEC3 self
-- @return DCSTypes#Vec3 The Vec3 coodinate.
function POINT_VEC3:GetVec3()
return self.PointVec3
end
--- Return the x coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number The x coodinate.
function POINT_VEC3:GetX()
return self.PointVec3.x
end
--- Return the y coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number The y coodinate.
function POINT_VEC3:GetY()
return self.PointVec3.y
end
--- Return the z coordinate of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number The z coodinate.
function POINT_VEC3:GetZ()
return self.PointVec3.z
end
--- Return a direction vector Vec3 from POINT_VEC3 to the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3 TargetPointVec3 The target PointVec3.
-- @return DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format.
function POINT_VEC3:GetDirectionVec3( TargetPointVec3 )
return { x = TargetPointVec3:GetX() - self:GetX(), y = TargetPointVec3:GetY() - self:GetY(), z = TargetPointVec3:GetZ() - self:GetZ() }
end
--- Get a correction in radians of the real magnetic north of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #number CorrectionRadians The correction in radians.
function POINT_VEC3:GetNorthCorrectionRadians()
local TargetVec3 = self:GetVec3()
local lat, lon = coord.LOtoLL(TargetVec3)
local north_posit = coord.LLtoLO(lat + 1, lon)
return math.atan2( north_posit.z - TargetVec3.z, north_posit.x - TargetVec3.x )
end
--- Return a direction in radians from the POINT_VEC3 using a direction vector in Vec3 format.
-- @param #POINT_VEC3 self
-- @param DCSTypes#Vec3 DirectionVec3 The direction vector in Vec3 format.
-- @return #number DirectionRadians The direction in radians.
function POINT_VEC3:GetDirectionRadians( DirectionVec3 )
local DirectionRadians = math.atan2( DirectionVec3.z, DirectionVec3.x )
DirectionRadians = DirectionRadians + self:GetNorthCorrectionRadians()
if DirectionRadians < 0 then
DirectionRadians = DirectionRadians + 2 * math.pi -- put dir in range of 0 to 2*pi ( the full circle )
end
return DirectionRadians
end
--- Return the 2D distance in meters between the target POINT_VEC3 and the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3 TargetPointVec3 The target PointVec3.
-- @return DCSTypes#Distance Distance The distance in meters.
function POINT_VEC3:Get2DDistance( TargetPointVec3 )
local TargetVec3 = TargetPointVec3:GetVec3()
local SourceVec3 = self:GetVec3()
return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5
end
--- Return the 3D distance in meters between the target POINT_VEC3 and the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3 TargetPointVec3 The target PointVec3.
-- @return DCSTypes#Distance Distance The distance in meters.
function POINT_VEC3:Get3DDistance( TargetPointVec3 )
local TargetVec3 = TargetPointVec3:GetVec3()
local SourceVec3 = self:GetVec3()
return ( ( TargetVec3.x - SourceVec3.x ) ^ 2 + ( TargetVec3.y - SourceVec3.y ) ^ 2 + ( TargetVec3.z - SourceVec3.z ) ^ 2 ) ^ 0.5
end
--- Provides a Bearing / Range string
-- @param #POINT_VEC3 self
-- @param #number AngleRadians The angle in randians
-- @param #number Distance The distance
-- @return #string The BR Text
function POINT_VEC3:ToStringBR( AngleRadians, Distance )
AngleRadians = UTILS.Round( UTILS.ToDegree( AngleRadians ), 0 )
if self:IsMetric() then
Distance = UTILS.Round( Distance / 1000, 2 )
else
Distance = UTILS.Round( UTILS.MetersToNM( Distance ), 2 )
end
local s = string.format( '%03d', AngleRadians ) .. ' for ' .. Distance
s = s .. self:GetAltitudeText() -- When the POINT is a VEC2, there will be no altitude shown.
return s
end
--- Return the altitude text of the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @return #string Altitude text.
function POINT_VEC3:GetAltitudeText()
if self:IsMetric() then
return ' at ' .. UTILS.Round( self:GetY(), 0 )
else
return ' at ' .. UTILS.Round( UTILS.MetersToFeet( self:GetY() ), 0 )
end
end
--- Return a BR string from a POINT_VEC3 to the POINT_VEC3.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3 TargetPointVec3 The target PointVec3.
-- @return #string The BR text.
function POINT_VEC3:GetBRText( TargetPointVec3 )
local DirectionVec3 = self:GetDirectionVec3( TargetPointVec3 )
local AngleRadians = self:GetDirectionRadians( DirectionVec3 )
local Distance = self:Get2DDistance( TargetPointVec3 )
return self:ToStringBR( AngleRadians, Distance )
end
--- Sets the POINT_VEC3 metric or NM.
-- @param #POINT_VEC3 self
-- @param #boolean Metric true means metric, false means NM.
function POINT_VEC3:SetMetric( Metric )
self.Metric = Metric
end
--- Gets if the POINT_VEC3 is metric or NM.
-- @param #POINT_VEC3 self
-- @return #boolean Metric true means metric, false means NM.
function POINT_VEC3:IsMetric()
return self.Metric
end
--- Build an air type route point.
-- @param #POINT_VEC3 self
-- @param #POINT_VEC3.RoutePointAltType AltType The altitude type.
@ -299,3 +446,10 @@ function POINT_VEC2:DistanceFromVec2( Vec2Reference )
end
--- Return no text for the altitude of the POINT_VEC2.
-- @param #POINT_VEC2 self
-- @return #string Empty string.
function POINT_VEC2:GetAltitudeText()
return ''
end

View File

@ -71,7 +71,7 @@ end
-- @param Positionable#POSITIONABLE self
-- @return DCSTypes#Vec2 The 2D point vector of the DCS Positionable.
-- @return #nil The DCS Positionable is not existing or alive.
function POSITIONABLE:GetPointVec2()
function POSITIONABLE:GetVec2()
self:F2( self.PositionableName )
local DCSPositionable = self:GetDCSObject()
@ -137,7 +137,7 @@ function POSITIONABLE:IsAboveRunway()
if DCSPositionable then
local PointVec2 = self:GetPointVec2()
local PointVec2 = self:GetVec2()
local SurfaceType = land.getSurfaceType( PointVec2 )
local IsAboveRunway = SurfaceType == land.SurfaceType.RUNWAY

View File

@ -245,22 +245,6 @@ end
-- From http://lua-users.org/wiki/SimpleRound
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place
routines.utils.round = function(num, idp)
local mult = 10^(idp or 0)
return math.floor(num * mult + 0.5) / mult
end
-- porting in Slmod's dostring
routines.utils.dostring = function(s)
local f, err = loadstring(s)
if f then
return true, f()
else
return false, err
end
end
--3D Vector manipulation

View File

@ -399,9 +399,9 @@ function SET_BASE:FindNearestObjectFromPointVec2( PointVec2 )
for ObjectID, ObjectData in pairs( self.Set ) do
if NearestObject == nil then
NearestObject = ObjectData
ClosestDistance = PointVec2:DistanceFromVec2( ObjectData:GetPointVec2() )
ClosestDistance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() )
else
local Distance = PointVec2:DistanceFromVec2( ObjectData:GetPointVec2() )
local Distance = PointVec2:DistanceFromVec2( ObjectData:GetVec2() )
if Distance < ClosestDistance then
NearestObject = ObjectData
ClosestDistance = Distance

View File

@ -563,7 +563,7 @@ function SPAWN:SpawnFromUnit( HostUnit, OuterRadius, InnerRadius, SpawnIndex )
if SpawnTemplate then
local UnitPoint = HostUnit:GetPointVec2()
local UnitPoint = HostUnit:GetVec2()
self:T( { "Current point of ", self.SpawnTemplatePrefix, UnitPoint } )
@ -646,7 +646,7 @@ function SPAWN:SpawnInZone( Zone, ZoneRandomize, SpawnIndex )
if ZoneRandomize == true then
ZonePoint = Zone:GetRandomVec2()
else
ZonePoint = Zone:GetPointVec2()
ZonePoint = Zone:GetVec2()
end
SpawnTemplate.route.points[1].x = ZonePoint.x

View File

@ -0,0 +1,83 @@
--- @module Task_Route
--- TASK2_ROUTE_CLIENT class
-- @type TASK2_ROUTE_CLIENT
-- @field Mission#MISSION Mission
-- @field Client#CLIENT Client
-- @field Zone#ZONE_BASE TargetZone
-- @extends Task2#TASK2
TASK2_ROUTE_CLIENT = {
ClassName = "TASK2_ROUTE_CLIENT",
}
--- Creates a new routing state machine. The task will route a CLIENT to a ZONE until the CLIENT is within that ZONE.
-- @param #TASK2_ROUTE_CLIENT self
-- @param Mission#MISSION Mission
-- @param Client#CLIENT Client
-- @return #TASK2_ROUTE_CLIENT self
function TASK2_ROUTE_CLIENT:New( Mission, Client, TargetZone )
-- Inherits from BASE
local self = BASE:Inherit( self, TASK2:New( Mission, Client ) ) -- #TASK2_ROUTE_CLIENT
self.TargetZone = TargetZone
self.DisplayInterval = 30
self.DisplayCount = 1
self.DisplayMessage = true
self.DisplayTime = 10 -- 10 seconds is the default
self.DisplayCategory = "Route" -- Route is the default display category
self.Fsm = STATEMACHINE_TASK:New( self, {
initial = 'Unarrived',
events = {
{ name = 'Route', from = 'UnArrived', to = 'Arrived' },
{ name = 'Fail', from = 'UnArrived', to = 'Failed' },
},
callbacks = {
onleaveUnarrived = self.OnBeforeRoute,
onFail = self.OnFail,
},
endstates = {
'Arrived', 'Failed'
},
} )
return self
end
--- Task Events
--- StateMachine callback function for a TASK2
-- @param #TASK2_ROUTE_CLIENT self
-- @param StateMachine#STATEMACHINE_TASK Fsm
-- @param #string Event
-- @param #string From
-- @param #string To
function TASK2_ROUTE_CLIENT:OnBeforeRoute( Fsm, Event, From, To )
self:E( { Event, From, To, self.Client.ClientName } )
local IsInZone = self.Client:IsInZone( self.TargetZone )
if self.DisplayCount >= self.DisplayInterval then
if not IsInZone then
local ZoneVec2 = self.TargetZone:GetVec2()
local ZonePointVec2 = POINT_VEC2:New( ZoneVec2.x, ZoneVec2.y )
local ClientVec2 = self.Client:GetVec2()
local ClientPointVec2 = POINT_VEC2:New( ClientVec2.x, ClientVec2.y )
local RouteText = ClientPointVec2:GetBRText( ZonePointVec2 )
self.Client:Message( RouteText, self.DisplayTime, self.DisplayCategory )
end
self.DisplayCount = 1
else
self.DisplayCount = self.DisplayCount + 1
end
if not IsInZone then
self:NextEvent( Fsm.Route )
end
return IsInZone -- if false, then the event will not be executed...
end

View File

@ -0,0 +1,176 @@
--- Utilities static class.
-- @type UTILS
UTILS = {}
--from http://lua-users.org/wiki/CopyTable
UTILS.DeepCopy = function(object)
local lookup_table = {}
local function _copy(object)
if type(object) ~= "table" then
return object
elseif lookup_table[object] then
return lookup_table[object]
end
local new_table = {}
lookup_table[object] = new_table
for index, value in pairs(object) do
new_table[_copy(index)] = _copy(value)
end
return setmetatable(new_table, getmetatable(object))
end
local objectreturn = _copy(object)
return objectreturn
end
-- porting in Slmod's serialize_slmod2
UTILS.OneLineSerialize = function( tbl ) -- serialization of a table all on a single line, no comments, made to replace old get_table_string function
lookup_table = {}
local function _Serialize( tbl )
if type(tbl) == 'table' then --function only works for tables!
if lookup_table[tbl] then
return lookup_table[object]
end
local tbl_str = {}
lookup_table[tbl] = tbl_str
tbl_str[#tbl_str + 1] = '{'
for ind,val in pairs(tbl) do -- serialize its fields
local ind_str = {}
if type(ind) == "number" then
ind_str[#ind_str + 1] = '['
ind_str[#ind_str + 1] = tostring(ind)
ind_str[#ind_str + 1] = ']='
else --must be a string
ind_str[#ind_str + 1] = '['
ind_str[#ind_str + 1] = routines.utils.basicSerialize(ind)
ind_str[#ind_str + 1] = ']='
end
local val_str = {}
if ((type(val) == 'number') or (type(val) == 'boolean')) then
val_str[#val_str + 1] = tostring(val)
val_str[#val_str + 1] = ','
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
elseif type(val) == 'string' then
val_str[#val_str + 1] = routines.utils.basicSerialize(val)
val_str[#val_str + 1] = ','
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
elseif type(val) == 'nil' then -- won't ever happen, right?
val_str[#val_str + 1] = 'nil,'
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
elseif type(val) == 'table' then
if ind == "__index" then
-- tbl_str[#tbl_str + 1] = "__index"
-- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
val_str[#val_str + 1] = _Serialize(val)
val_str[#val_str + 1] = ',' --I think this is right, I just added it
tbl_str[#tbl_str + 1] = table.concat(ind_str)
tbl_str[#tbl_str + 1] = table.concat(val_str)
end
elseif type(val) == 'function' then
-- tbl_str[#tbl_str + 1] = "function " .. tostring(ind)
-- tbl_str[#tbl_str + 1] = ',' --I think this is right, I just added it
else
-- env.info('unable to serialize value type ' .. routines.utils.basicSerialize(type(val)) .. ' at index ' .. tostring(ind))
-- env.info( debug.traceback() )
end
end
tbl_str[#tbl_str + 1] = '}'
return table.concat(tbl_str)
else
return tostring(tbl)
end
end
local objectreturn = _Serialize(tbl)
return objectreturn
end
--porting in Slmod's "safestring" basic serialize
UTILS.BasicSerialize = function(s)
if s == nil then
return "\"\""
else
if ((type(s) == 'number') or (type(s) == 'boolean') or (type(s) == 'function') or (type(s) == 'table') or (type(s) == 'userdata') ) then
return tostring(s)
elseif type(s) == 'string' then
s = string.format('%q', s)
return s
end
end
end
UTILS.ToDegree = function(angle)
return angle*180/math.pi
end
UTILS.ToRadian = function(angle)
return angle*math.pi/180
end
UTILS.MetersToNM = function(meters)
return meters/1852
end
UTILS.MetersToFeet = function(meters)
return meters/0.3048
end
UTILS.NMToMeters = function(NM)
return NM*1852
end
UTILS.FeetToMeters = function(feet)
return feet*0.3048
end
UTILS.MpsToKnots = function(mps)
return mps*3600/1852
end
UTILS.MpsToKmph = function(mps)
return mps*3.6
end
UTILS.KnotsToMps = function(knots)
return knots*1852/3600
end
UTILS.KmphToMps = function(kmph)
return kmph/3.6
end
--- From http://lua-users.org/wiki/SimpleRound
-- use negative idp for rounding ahead of decimal place, positive for rounding after decimal place
function UTILS.Round( num, idp )
local mult = 10 ^ ( idp or 0 )
return math.floor( num * mult + 0.5 ) / mult
end
-- porting in Slmod's dostring
function UTILS.DoString( s )
local f, err = loadstring( s )
if f then
return true, f()
else
return false, err
end
end

View File

@ -101,10 +101,10 @@ end
--- Returns if a location is within the zone.
-- @param #ZONE_BASE self
-- @param DCSTypes#Vec2 PointVec2 The location to test.
-- @param DCSTypes#Vec2 Vec2 The location to test.
-- @return #boolean true if the location is within the zone.
function ZONE_BASE:IsPointVec2InZone( PointVec2 )
self:F2( PointVec2 )
function ZONE_BASE:IsPointVec2InZone( Vec2 )
self:F2( Vec2 )
return false
end
@ -121,18 +121,27 @@ function ZONE_BASE:IsPointVec3InZone( PointVec3 )
return InZone
end
--- Returns the Vec2 coordinate of the zone.
-- @param #ZONE_BASE self
-- @return #nil.
function ZONE_BASE:GetVec2()
self:F2( self.ZoneName )
return nil
end
--- Define a random @{DCSTypes#Vec2} within the zone.
-- @param #ZONE_BASE self
-- @return DCSTypes#Vec2 The Vec2 coordinates.
-- @return #nil The Vec2 coordinates.
function ZONE_BASE:GetRandomVec2()
return { x = 0, y = 0 }
return nil
end
--- Get the bounding square the zone.
-- @param #ZONE_BASE self
-- @return #ZONE_BASE.BoundingSquare The bounding square.
-- @return #nil The bounding square.
function ZONE_BASE:GetBoundingSquare()
return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 }
--return { x1 = 0, y1 = 0, x2 = 0, y2 = 0 }
return nil
end
@ -147,7 +156,7 @@ end
--- The ZONE_RADIUS class, defined by a zone name, a location and a radius.
-- @type ZONE_RADIUS
-- @field DCSTypes#Vec2 PointVec2 The current location of the zone.
-- @field DCSTypes#Vec2 Vec2 The current location of the zone.
-- @field DCSTypes#Distance Radius The radius of the zone.
-- @extends Zone#ZONE_BASE
ZONE_RADIUS = {
@ -157,15 +166,15 @@ ZONE_RADIUS = {
--- Constructor of ZONE_RADIUS, taking the zone name, the zone location and a radius.
-- @param #ZONE_RADIUS self
-- @param #string ZoneName Name of the zone.
-- @param DCSTypes#Vec2 PointVec2 The location of the zone.
-- @param DCSTypes#Vec2 Vec2 The location of the zone.
-- @param DCSTypes#Distance Radius The radius of the zone.
-- @return #ZONE_RADIUS self
function ZONE_RADIUS:New( ZoneName, PointVec2, Radius )
function ZONE_RADIUS:New( ZoneName, Vec2, Radius )
local self = BASE:Inherit( self, ZONE_BASE:New( ZoneName ) )
self:F( { ZoneName, PointVec2, Radius } )
self:F( { ZoneName, Vec2, Radius } )
self.Radius = Radius
self.PointVec2 = PointVec2
self.Vec2 = Vec2
return self
end
@ -179,7 +188,7 @@ function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
self:F2( SmokeColor )
local Point = {}
local PointVec2 = self:GetPointVec2()
local Vec2 = self:GetVec2()
Points = Points and Points or 360
@ -188,8 +197,8 @@ function ZONE_RADIUS:SmokeZone( SmokeColor, Points )
for Angle = 0, 360, 360 / Points do
local Radial = Angle * RadialBase / 360
Point.x = PointVec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = PointVec2.y + math.sin( Radial ) * self:GetRadius()
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
POINT_VEC2:New( Point.x, Point.y ):Smoke( SmokeColor )
end
@ -207,7 +216,7 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth )
self:F2( { FlareColor, Azimuth } )
local Point = {}
local PointVec2 = self:GetPointVec2()
local Vec2 = self:GetVec2()
Points = Points and Points or 360
@ -216,8 +225,8 @@ function ZONE_RADIUS:FlareZone( FlareColor, Points, Azimuth )
for Angle = 0, 360, 360 / Points do
local Radial = Angle * RadialBase / 360
Point.x = PointVec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = PointVec2.y + math.sin( Radial ) * self:GetRadius()
Point.x = Vec2.x + math.cos( Radial ) * self:GetRadius()
Point.y = Vec2.y + math.sin( Radial ) * self:GetRadius()
POINT_VEC2:New( Point.x, Point.y ):Flare( FlareColor, Azimuth )
end
@ -251,26 +260,26 @@ end
--- Returns the location of the zone.
-- @param #ZONE_RADIUS self
-- @return DCSTypes#Vec2 The location of the zone.
function ZONE_RADIUS:GetPointVec2()
function ZONE_RADIUS:GetVec2()
self:F2( self.ZoneName )
self:T2( { self.PointVec2 } )
self:T2( { self.Vec2 } )
return self.PointVec2
return self.Vec2
end
--- Sets the location of the zone.
-- @param #ZONE_RADIUS self
-- @param DCSTypes#Vec2 PointVec2 The new location of the zone.
-- @param DCSTypes#Vec2 Vec2 The new location of the zone.
-- @return DCSTypes#Vec2 The new location of the zone.
function ZONE_RADIUS:SetPointVec2( PointVec2 )
function ZONE_RADIUS:SetPointVec2( Vec2 )
self:F2( self.ZoneName )
self.PointVec2 = PointVec2
self.Vec2 = Vec2
self:T2( { self.PointVec2 } )
self:T2( { self.Vec2 } )
return self.PointVec2
return self.Vec2
end
--- Returns the point of the zone.
@ -280,9 +289,9 @@ end
function ZONE_RADIUS:GetPointVec3( Height )
self:F2( self.ZoneName )
local PointVec2 = self:GetPointVec2()
local Vec2 = self:GetVec2()
local PointVec3 = { x = PointVec2.x, y = land.getHeight( self:GetPointVec2() ) + Height, z = PointVec2.y }
local PointVec3 = { x = Vec2.x, y = land.getHeight( self:GetVec2() ) + Height, z = Vec2.y }
self:T2( { PointVec3 } )
@ -292,14 +301,14 @@ end
--- Returns if a location is within the zone.
-- @param #ZONE_RADIUS self
-- @param DCSTypes#Vec2 PointVec2 The location to test.
-- @param DCSTypes#Vec2 Vec2 The location to test.
-- @return #boolean true if the location is within the zone.
function ZONE_RADIUS:IsPointVec2InZone( PointVec2 )
self:F2( PointVec2 )
function ZONE_RADIUS:IsPointVec2InZone( Vec2 )
self:F2( Vec2 )
local ZonePointVec2 = self:GetPointVec2()
local ZoneVec2 = self:GetVec2()
if (( PointVec2.x - ZonePointVec2.x )^2 + ( PointVec2.y - ZonePointVec2.y ) ^2 ) ^ 0.5 <= self:GetRadius() then
if (( Vec2.x - ZoneVec2.x )^2 + ( Vec2.y - ZoneVec2.y ) ^2 ) ^ 0.5 <= self:GetRadius() then
return true
end
@ -310,10 +319,10 @@ end
-- @param #ZONE_RADIUS self
-- @param DCSTypes#Vec3 PointVec3 The point to test.
-- @return #boolean true if the point is within the zone.
function ZONE_RADIUS:IsPointVec3InZone( PointVec3 )
self:F2( PointVec3 )
function ZONE_RADIUS:IsPointVec3InZone( Vec3 )
self:F2( Vec3 )
local InZone = self:IsPointVec2InZone( { x = PointVec3.x, y = PointVec3.z } )
local InZone = self:IsPointVec2InZone( { x = Vec3.x, y = Vec3.z } )
return InZone
end
@ -325,11 +334,11 @@ function ZONE_RADIUS:GetRandomVec2()
self:F( self.ZoneName )
local Point = {}
local PointVec2 = self:GetPointVec2()
local Vec2 = self:GetVec2()
local angle = math.random() * math.pi*2;
Point.x = PointVec2.x + math.cos( angle ) * math.random() * self:GetRadius();
Point.y = PointVec2.y + math.sin( angle ) * math.random() * self:GetRadius();
Point.x = Vec2.x + math.cos( angle ) * math.random() * self:GetRadius();
Point.y = Vec2.y + math.sin( angle ) * math.random() * self:GetRadius();
self:T( { Point } )
@ -383,8 +392,8 @@ ZONE_UNIT = {
-- @param DCSTypes#Distance Radius The radius of the zone.
-- @return #ZONE_UNIT self
function ZONE_UNIT:New( ZoneName, ZoneUNIT, Radius )
local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetPointVec2(), Radius ) )
self:F( { ZoneName, ZoneUNIT:GetPointVec2(), Radius } )
local self = BASE:Inherit( self, ZONE_RADIUS:New( ZoneName, ZoneUNIT:GetVec2(), Radius ) )
self:F( { ZoneName, ZoneUNIT:GetVec2(), Radius } )
self.ZoneUNIT = ZoneUNIT
@ -395,14 +404,14 @@ end
--- Returns the current location of the @{Unit#UNIT}.
-- @param #ZONE_UNIT self
-- @return DCSTypes#Vec2 The location of the zone based on the @{Unit#UNIT}location.
function ZONE_UNIT:GetPointVec2()
function ZONE_UNIT:GetVec2()
self:F( self.ZoneName )
local ZonePointVec2 = self.ZoneUNIT:GetPointVec2()
local ZoneVec2 = self.ZoneUNIT:GetVec2()
self:T( { ZonePointVec2 } )
self:T( { ZoneVec2 } )
return ZonePointVec2
return ZoneVec2
end
-- Polygons
@ -492,10 +501,10 @@ end
--- Returns if a location is within the zone.
-- Source learned and taken from: https://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
-- @param #ZONE_POLYGON_BASE self
-- @param DCSTypes#Vec2 PointVec2 The location to test.
-- @param DCSTypes#Vec2 Vec2 The location to test.
-- @return #boolean true if the location is within the zone.
function ZONE_POLYGON_BASE:IsPointVec2InZone( PointVec2 )
self:F2( PointVec2 )
function ZONE_POLYGON_BASE:IsPointVec2InZone( Vec2 )
self:F2( Vec2 )
local Next
local Prev
@ -506,8 +515,8 @@ function ZONE_POLYGON_BASE:IsPointVec2InZone( PointVec2 )
while Next <= #self.Polygon do
self:T( { Next, Prev, self.Polygon[Next], self.Polygon[Prev] } )
if ( ( ( self.Polygon[Next].y > PointVec2.y ) ~= ( self.Polygon[Prev].y > PointVec2.y ) ) and
( PointVec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( PointVec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x )
if ( ( ( self.Polygon[Next].y > Vec2.y ) ~= ( self.Polygon[Prev].y > Vec2.y ) ) and
( Vec2.x < ( self.Polygon[Prev].x - self.Polygon[Next].x ) * ( Vec2.y - self.Polygon[Next].y ) / ( self.Polygon[Prev].y - self.Polygon[Next].y ) + self.Polygon[Next].x )
) then
InPolygon = not InPolygon
end

View File

@ -8,7 +8,7 @@ local Client = CLIENT:FindByName( "Test SEAD" )
local TargetSet = SET_UNIT:New():FilterPrefixes( "US Hawk SR" ):FilterStart()
local Task_Menu = TASK2_CLIENT_MENU:New( Client, Mission, "SEAD" )
--local Task_Route = TASK2_ROUTE:New( Client, Mission ) -- Zone is dynamically defined in state machine
local Task_Route = TASK2_ROUTE:New( Client, Mission ) -- The target location is dynamically defined in state machine
local Task_Client_Sead = TASK2_SEAD:New( Client, Mission, TargetSet )
Task_Client_Sead:AddScore( "Destroy", "Destroyed RADAR", 25 )
@ -17,17 +17,20 @@ Task_Client_Sead:AddScore( "Success", "Destroyed all radars!!!", 100 )
local Task_Sead = STATEMACHINE:New( {
initial = 'None',
events = {
{ name = 'Start', from = 'None', to = 'Unassigned' },
{ name = 'Next', from = 'Unassigned', to = 'Assigned' },
-- { name = 'Route', from = 'Assigned', to = 'Arrived' },
{ name = 'Next', from = 'Assigned', to = 'Success' },
{ name = 'Failed', from = 'Assigned', to = 'Failed' },
{ name = 'Start', from = 'None', to = 'Unassigned' },
{ name = 'Next', from = 'Unassigned', to = 'Assigned' },
{ name = 'Next', from = 'Assigned', to = 'Arrived' },
{ name = 'Next', from = 'Arrived', to = 'Success' },
{ name = 'Fail', from = 'Assigned', to = 'Failed' },
{ name = 'Fail', from = 'Arrived', to = 'Failed' }
},
subs = {
Menu = { onstateparent = 'Unassigned', oneventparent = 'Start', fsm = Task_Menu.Fsm, event = 'Menu', returnevents = { 'Next' } },
--Assigned = { onstateparent = 'Assigned', oneventparent = 'Assign', fsm = Task_Route.Fsm, event = 'Route' },
Sead = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = Task_Client_Sead.Fsm, event = 'Await', returnevents = { 'Next' } }
Menu = { onstateparent = 'Unassigned', oneventparent = 'Start', fsm = Task_Menu.Fsm, event = 'Menu', returnevents = { 'Next' } },
Route = { onstateparent = 'Assigned', oneventparent = 'Next', fsm = Task_Route.Fsm, event = 'Route', returnevents = { 'Next' } },
Sead = { onstateparent = 'Arrived', oneventparent = 'Next', fsm = Task_Client_Sead.Fsm, event = 'Await', returnevents = { 'Next' } }
}
} )
Task_Sead:Start()