Progress AI_PATROLZONE

This commit is contained in:
Sven Van de Velde 2016-08-21 14:22:05 +02:00
parent a800531ea0
commit 91d0507b4d
4 changed files with 127 additions and 97 deletions

View File

@ -4,7 +4,7 @@
--
-- 1) @{#AI_PATROLZONE} class, extends @{StateMachine#STATEMACHINE}
-- ================================================================
-- The @{#AI_PATROLZONE} class implements the core functions to patrol a @{Zone} by an AIR @{Group}.
-- The @{#AI_PATROLZONE} class implements the core functions to patrol a @{Zone} by an AIR @{Controllable}.
-- The patrol algorithm works that for each airplane patrolling, upon arrival at the patrol zone,
-- a random point is selected as the route point within the 3D space, within the given boundary limits.
-- The airplane will fly towards the random 3D point within the patrol zone, using a random speed within the given altitude and speed limits.
@ -19,22 +19,22 @@
--
-- 1.2) AI\_PATROLZONE state machine:
-- ----------------------------------
-- The AI\_PATROLZONE is a state machine: it manages the different events and states of the AIGroup it is controlling.
-- The AI\_PATROLZONE is a state machine: it manages the different events and states of the AIControllable it is controlling.
--
-- ### 1.2.1) AI\_PATROLZONE Events:
--
-- * @{#AI_PATROLZONE.Route}( AIGroup ): A new 3D route point is selected and the AIGroup will fly towards that point with the given speed.
-- * @{#AI_PATROLZONE.Patrol}( AIGroup ): The AIGroup reports it is patrolling. This event is called every 30 seconds.
-- * @{#AI_PATROLZONE.RTB}( AIGroup ): The AIGroup will report return to base.
-- * @{#AI_PATROLZONE.End}( AIGroup ): The end of the AI\_PATROLZONE process.
-- * @{#AI_PATROLZONE.Dead}( AIGroup ): The AIGroup is dead. The AI\_PATROLZONE process will be ended.
-- * @{#AI_PATROLZONE.Route}( AIControllable ): A new 3D route point is selected and the AIControllable will fly towards that point with the given speed.
-- * @{#AI_PATROLZONE.Patrol}( AIControllable ): The AIControllable reports it is patrolling. This event is called every 30 seconds.
-- * @{#AI_PATROLZONE.RTB}( AIControllable ): The AIControllable will report return to base.
-- * @{#AI_PATROLZONE.End}( AIControllable ): The end of the AI\_PATROLZONE process.
-- * @{#AI_PATROLZONE.Dead}( AIControllable ): The AIControllable is dead. The AI\_PATROLZONE process will be ended.
--
-- ### 1.2.2) AI\_PATROLZONE States:
--
-- * **Route**: A new 3D route point is selected and the AIGroup will fly towards that point with the given speed.
-- * **Patrol**: The AIGroup is patrolling. This state is set every 30 seconds, so every 30 seconds, a state transition function can be used.
-- * **RTB**: The AIGroup reports it wants to return to the base.
-- * **Dead**: The AIGroup is dead ...
-- * **Route**: A new 3D route point is selected and the AIControllable will fly towards that point with the given speed.
-- * **Patrol**: The AIControllable is patrolling. This state is set every 30 seconds, so every 30 seconds, a state transition function can be used.
-- * **RTB**: The AIControllable reports it wants to return to the base.
-- * **Dead**: The AIControllable is dead ...
-- * **End**: The process has come to an end.
--
-- ### 1.2.3) AI\_PATROLZONE state transition functions:
@ -45,8 +45,8 @@
-- * **Before** the state transition.
-- The state transition function needs to start with the name **OnBefore + the name of the state**.
-- If the state transition function returns false, then the processing of the state transition will not be done!
-- If you want to change the behaviour of the AIGroup at this event, return false,
-- but then you'll need to specify your own logic using the AIGroup!
-- If you want to change the behaviour of the AIControllable at this event, return false,
-- but then you'll need to specify your own logic using the AIControllable!
--
-- * **After** the state transition.
-- The state transition function needs to start with the name **OnAfter + the name of the state**.
@ -61,14 +61,14 @@
-- local PatrolGroup = PatrolSpawn:Spawn()
--
-- local Patrol = AI_PATROLZONE:New( PatrolZone, 3000, 6000, 300, 600 )
-- Patrol:AddGroup( PatrolGroup )
-- Patrol:SetControllable( PatrolGroup )
-- Patrol:ManageFuel( 0.2, 60 )
--
-- **OnBefore**RTB( AIGroup ) will be called by the AI\_PATROLZONE object when the AIGroup reports RTB, but **before** the RTB default action is processed by the AI_PATROLZONE object.
--
-- --- State transition function for the AI\_PATROLZONE **Patrol** object
-- -- @param #AI_PATROLZONE self
-- -- @param Group#GROUP AIGroup
-- -- @param Controllable#CONTROLLABLE AIGroup
-- -- @return #boolean If false is returned, then the OnAfter state transition function will not be called.
-- function Patrol:OnBeforeRTB( AIGroup )
-- AIGroup:MessageToRed( "Returning to base", 20 )
@ -78,26 +78,27 @@
--
-- --- State transition function for the AI\_PATROLZONE **Patrol** object
-- -- @param #AI_PATROLZONE self
-- -- @param Group#GROUP AIGroup
-- -- @return #Group#GROUP The new AIGroup object that is set to be patrolling the zone.
-- -- @param Controllable#CONTROLLABLE AIGroup
-- -- @return #Controllable#CONTROLLABLE The new AIGroup object that is set to be patrolling the zone.
-- function Patrol:OnAfterRTB( AIGroup )
-- return PatrolSpawn:Spawn()
-- end
--
-- 1.3) Modify the AI\_PATROLZONE parameters:
-- --------------------------------------
-- 1.3) Manage the AI\_PATROLZONE parameters:
-- ------------------------------------------
-- The following methods are available to modify the parameters of a AI\_PATROLZONE object:
--
-- * @{#AI_PATROLZONE.SetGroup}(): Set the AI Patrol Group.
-- * @{#AI_PATROLZONE.SetControllable}(): Set the AIControllable.
-- * @{#AI_PATROLZONE.GetControllable}(): Get the AIControllable.
-- * @{#AI_PATROLZONE.SetSpeed}(): Set the patrol speed of the AI, for the next patrol.
-- * @{#AI_PATROLZONE.SetAltitude}(): Set altitude of the AI, for the next patrol.
--
-- 1.3) Manage the out of fuel in the AI\_PATROLZONE:
-- ----------------------------------------------
-- When the PatrolGroup is out of fuel, it is required that a new PatrolGroup is started, before the old PatrolGroup can return to the home base.
-- When the AIControllable is out of fuel, it is required that a new AIControllable is started, before the old AIControllable can return to the home base.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
-- When the fuel treshold is reached, the PatrolGroup will continue for a given time its patrol task in orbit, while a new PatrolGroup is targetted to the AI\_PATROLZONE.
-- Once the time is finished, the old PatrolGroup will return to the base.
-- When the fuel treshold is reached, the AIControllable will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI\_PATROLZONE.
-- Once the time is finished, the old AIControllable will return to the base.
-- Use the method @{#AI_PATROLZONE.ManageFuel}() to have this proces in place.
--
-- ====
@ -124,10 +125,11 @@
-- ### Contributions:
--
-- * **DutchBaron**: Testing.
-- * **Pikey**: Testing and API concept review.
--
-- ### Authors:
--
-- * **FlightControl**: Design & Programming
-- * **FlightControl**: Design & Programming.
--
--
-- @module AI_PatrolZone
@ -136,13 +138,13 @@
--- AI\_PATROLZONE class
-- @type AI_PATROLZONE
-- @field Group#GROUP PatrolGroup The @{Group} patrolling.
-- @field Controllable#CONTROLLABLE AIControllable The @{Controllable} patrolling.
-- @field Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @field DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @field DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @field DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @field DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @extends StateMachine#StateMachine
-- @field DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @field DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @extends StateMachine#STATEMACHINE_CONTROLLABLE
AI_PATROLZONE = {
ClassName = "AI_PATROLZONE",
}
@ -154,11 +156,11 @@ AI_PATROLZONE = {
-- @param Zone#ZONE_BASE PatrolZone The @{Zone} where the patrol needs to be executed.
-- @param DCSTypes#Altitude PatrolFloorAltitude The lowest altitude in meters where to execute the patrol.
-- @param DCSTypes#Altitude PatrolCeilingAltitude The highest altitude in meters where to execute the patrol.
-- @param DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @param DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @return #AI_PATROLZONE self
-- @usage
-- -- Define a new AI_PATROLZONE Object. This PatrolArea will patrol a group within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
-- -- Define a new AI_PATROLZONE Object. This PatrolArea will patrol an AIControllable within PatrolZone between 3000 and 6000 meters, with a variying speed between 600 and 900 km/h.
-- PatrolZone = ZONE:New( 'PatrolZone' )
-- PatrolSpawn = SPAWN:New( 'Patrol Group' )
-- PatrolArea = AI_PATROLZONE:New( PatrolZone, 3000, 6000, 600, 900 )
@ -174,16 +176,10 @@ function AI_PATROLZONE:New( PatrolZone, PatrolFloorAltitude, PatrolCeilingAltitu
{ name = 'End', from = '*', to = 'End' },
{ name = 'Dead', from = '*', to = 'End' },
},
callbacks = {
onenterRoute = self._EnterRoute,
onenterPatrol = self._EnterPatrol,
onenterRTB = self._EnterRTB,
onenterEnd = self._EnterEnd,
},
}
-- Inherits from BASE
local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) )
local self = BASE:Inherit( self, STATEMACHINE_CONTROLLABLE:New( FSMT ) )
self.PatrolZone = PatrolZone
self.PatrolFloorAltitude = PatrolFloorAltitude
@ -196,24 +192,11 @@ end
--- Set the @{Group} to act as the Patroller.
-- @param #AI_PATROLZONE self
-- @param Group#GROUP PatrolGroup The @{Group} patrolling.
-- @return #AI_PATROLZONE self
function AI_PATROLZONE:SetGroup( PatrolGroup )
self.PatrolGroup = PatrolGroup
self.PatrolGroupTemplateName = PatrolGroup:GetName()
return self
end
--- Sets (modifies) the minimum and maximum speed of the patrol.
-- @param #AI_PATROLZONE self
-- @param DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Group} in km/h.
-- @param DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Group} in km/h.
-- @param DCSTypes#Speed PatrolMinSpeed The minimum speed of the @{Controllable} in km/h.
-- @param DCSTypes#Speed PatrolMaxSpeed The maximum speed of the @{Controllable} in km/h.
-- @return #AI_PATROLZONE self
function AI_PATROLZONE:SetSpeed( PatrolMinSpeed, PatrolMaxSpeed )
self:F2( { PatrolMinSpeed, PatrolMaxSpeed } )
@ -238,24 +221,24 @@ end
--- @param Group#GROUP PatrolGroup
function _NewPatrolRoute( PatrolGroup )
--- @param Controllable#CONTROLLABLE AIControllable
function _NewPatrolRoute( AIControllable )
PatrolGroup:T( "NewPatrolRoute" )
local PatrolZone = PatrolGroup:GetState( PatrolGroup, "PatrolZone" ) -- PatrolZone#AI_PATROLZONE
PatrolZone:__Route( 1, PatrolGroup )
AIControllable:T( "NewPatrolRoute" )
local PatrolZone = AIControllable:GetState( AIControllable, "PatrolZone" ) -- PatrolZone#AI_PATROLZONE
PatrolZone:__Route( 1 )
end
--- When the PatrolGroup is out of fuel, it is required that a new PatrolGroup is started, before the old PatrolGroup can return to the home base.
--- When the AIControllable is out of fuel, it is required that a new AIControllable is started, before the old AIControllable can return to the home base.
-- Therefore, with a parameter and a calculation of the distance to the home base, the fuel treshold is calculated.
-- When the fuel treshold is reached, the PatrolGroup will continue for a given time its patrol task in orbit, while a new PatrolGroup is targetted to the AI\_PATROLZONE.
-- Once the time is finished, the old PatrolGroup will return to the base.
-- When the fuel treshold is reached, the AIControllable will continue for a given time its patrol task in orbit, while a new AIControllable is targetted to the AI\_PATROLZONE.
-- Once the time is finished, the old AIControllable will return to the base.
-- @param #AI_PATROLZONE self
-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the PatrolGroup is considered to get out of fuel.
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel PatrolGroup will orbit before returning to the base.
-- @param #number PatrolFuelTresholdPercentage The treshold in percentage (between 0 and 1) when the AIControllable is considered to get out of fuel.
-- @param #number PatrolOutOfFuelOrbitTime The amount of seconds the out of fuel AIControllable will orbit before returning to the base.
-- @return #AI_PATROLZONE self
function AI_PATROLZONE:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuelOrbitTime )
@ -266,22 +249,22 @@ function AI_PATROLZONE:ManageFuel( PatrolFuelTresholdPercentage, PatrolOutOfFuel
return self
end
--- Defines a new patrol route using the @{PatrolZone} parameters and settings.
--- Defines a new patrol route using the @{AI_PatrolZone} parameters and settings.
-- @param #AI_PATROLZONE self
-- @return #AI_PATROLZONE self
function AI_PATROLZONE:_EnterRoute( AIGroup )
function AI_PATROLZONE:onenterRoute()
self:F2()
local PatrolRoute = {}
if self.PatrolGroup:IsAlive() then
--- Determine if the PatrolGroup is within the PatrolZone.
-- If not, make a waypoint within the to that the PatrolGroup will fly at maximum speed to that point.
if self.Controllable:IsAlive() then
--- Determine if the AIControllable is within the PatrolZone.
-- If not, make a waypoint within the to that the AIControllable will fly at maximum speed to that point.
-- --- Calculate the current route point.
-- local CurrentVec2 = self.PatrolGroup:GetVec2()
-- local CurrentAltitude = self.PatrolGroup:GetUnit(1):GetAltitude()
-- local CurrentVec2 = self.Controllable:GetVec2()
-- local CurrentAltitude = self.Controllable:GetUnit(1):GetAltitude()
-- local CurrentPointVec3 = POINT_VEC3:New( CurrentVec2.x, CurrentAltitude, CurrentVec2.y )
-- local CurrentRoutePoint = CurrentPointVec3:RoutePointAir(
-- POINT_VEC3.RoutePointAltType.BARO,
@ -295,7 +278,7 @@ function AI_PATROLZONE:_EnterRoute( AIGroup )
self:T2( PatrolRoute )
if self.PatrolGroup:IsNotInZone( self.PatrolZone ) then
if self.Controllable:IsNotInZone( self.PatrolZone ) then
--- Find a random 2D point in PatrolZone.
local ToPatrolZoneVec2 = self.PatrolZone:GetRandomVec2()
self:T2( ToPatrolZoneVec2 )
@ -348,40 +331,40 @@ function AI_PATROLZONE:_EnterRoute( AIGroup )
PatrolRoute[#PatrolRoute+1] = ToTargetRoutePoint
--- Now we're going to do something special, we're going to call a function from a waypoint action at the PatrolGroup...
self.PatrolGroup:WayPointInitialize( PatrolRoute )
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
self.Controllable:WayPointInitialize( PatrolRoute )
--- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the PatrolGroup in a temporary variable ...
self.PatrolGroup:SetState( self.PatrolGroup, "PatrolZone", self )
self.PatrolGroup:WayPointFunction( #PatrolRoute, 1, "_NewPatrolRoute" )
--- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the AIControllable in a temporary variable ...
self.Controllable:SetState( self.Controllable, "PatrolZone", self )
self.Controllable:WayPointFunction( #PatrolRoute, 1, "_NewPatrolRoute" )
--- NOW ROUTE THE GROUP!
self.PatrolGroup:WayPointExecute( 1 )
self.Controllable:WayPointExecute( 1 )
self:__Patrol( 30, self.PatrolGroup )
self:__Patrol( 30 )
end
end
--- @param #AI_PATROLZONE self
function AI_PATROLZONE:_EnterPatrol( AIGroup )
function AI_PATROLZONE:onenterPatrol()
self:F2()
if self.PatrolGroup and self.PatrolGroup:IsAlive() then
if self.Controllable and self.Controllable:IsAlive() then
local Fuel = self.PatrolGroup:GetUnit(1):GetFuel()
local Fuel = self.Controllable:GetUnit(1):GetFuel()
if Fuel < self.PatrolFuelTresholdPercentage then
local OldPatrolGroup = self.PatrolGroup
local PatrolGroupTemplate = self.PatrolGroup:GetTemplate()
local OldAIControllable = self.Controllable
local AIControllableTemplate = self.Controllable:GetTemplate()
local OrbitTask = OldPatrolGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = OldPatrolGroup:TaskControlled( OrbitTask, OldPatrolGroup:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
OldPatrolGroup:SetTask( TimedOrbitTask, 10 )
local OrbitTask = OldAIControllable:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = OldAIControllable:TaskControlled( OrbitTask, OldAIControllable:TaskCondition(nil,nil,nil,nil,self.PatrolOutOfFuelOrbitTime,nil ) )
OldAIControllable:SetTask( TimedOrbitTask, 10 )
self:RTB( self.PatrolGroup )
self:RTB()
else
self:__Patrol( 30, self.PatrolGroup ) -- Execute the Patrol event after 30 seconds.
self:__Patrol( 30 ) -- Execute the Patrol event after 30 seconds.
end
end

View File

@ -95,7 +95,7 @@ end
function STATEMACHINE:_call_handler(handler, params)
if handler then
return handler(unpack(params))
return handler( self, unpack(params) )
end
end
@ -110,7 +110,7 @@ function STATEMACHINE._handler( self, EventName, ... )
if can then
local from = self.current
local params = { self, ..., EventName, from, to }
local params = { ..., EventName, from, to }
if self:_call_handler(self["onbefore" .. EventName], params) == false
or self:_call_handler(self["onleave" .. from], params) == false then
@ -317,3 +317,50 @@ function STATEMACHINE_TASK:_call_handler( handler, params )
return handler( self.Task, self.TaskUnit, unpack( params ) )
end
end
--- STATEMACHINE_CONTROLLABLE class
-- @type STATEMACHINE_CONTROLLABLE
-- @field Controllable#CONTROLLABLE Controllable
-- @extends StateMachine#STATEMACHINE
STATEMACHINE_CONTROLLABLE = {
ClassName = "STATEMACHINE_CONTROLLABLE",
}
--- Creates a new STATEMACHINE_CONTROLLABLE object.
-- @param #STATEMACHINE_CONTROLLABLE self
-- @param #table FSMT Finite State Machine Table
-- @param Controllable#CONTROLLABLE Controllable (optional) The CONTROLLABLE object that the STATEMACHINE_CONTROLLABLE governs.
-- @return #STATEMACHINE_CONTROLLABLE
function STATEMACHINE_CONTROLLABLE:New( FSMT, Controllable )
-- Inherits from BASE
local self = BASE:Inherit( self, STATEMACHINE:New( FSMT ) ) -- StateMachine#STATEMACHINE_CONTROLLABLE
if Controllable then
self:SetControllable( Controllable )
end
return self
end
--- Sets the CONTROLLABLE object that the STATEMACHINE_CONTROLLABLE governs.
-- @param #STATEMACHINE_CONTROLLABLE self
-- @param Controllable#CONTROLLABLE Controllable
-- @return #STATEMACHINE_CONTROLLABLE
function STATEMACHINE_CONTROLLABLE:SetControllable( FSMControllable )
self:F( FSMControllable )
self.Controllable = FSMControllable
end
--- Gets the CONTROLLABLE object that the STATEMACHINE_CONTROLLABLE governs.
-- @param #STATEMACHINE_CONTROLLABLE self
-- @return Controllable#CONTROLLABLE
function STATEMACHINE_CONTROLLABLE:GetControllable()
return self.Controllable
end
function STATEMACHINE_CONTROLLABLE:_call_handler( handler, params )
if handler then
return handler( self, self.Controllable, unpack( params ) )
end
end

View File

@ -1,7 +1,7 @@
-- This test mission models the behaviour of the AI_PATROLZONE class.
--
-- It creates a 2 AI_PATROLZONE objects with the name Patrol1 and Patrol2.
-- Patrol1 will goven a GROUP object to patrol the zone defined by PatrolZone1, within 3000 meters and 6000 meters, within a speed of 400 and 600 km/h.
-- Patrol1 will govern a GROUP object to patrol the zone defined by PatrolZone1, within 3000 meters and 6000 meters, within a speed of 400 and 600 km/h.
-- When the GROUP object that is assigned to Patrol has fuel below 20%, the GROUP object will orbit for 60 secondes, before returning to base.
--
-- Patrol2 will goven a GROUP object to patrol the zone defined by PatrolZone2, within 600 meters and 1000 meters, within a speed of 300 and 400 km/h.
@ -25,8 +25,8 @@ local PatrolGroup = PatrolSpawn:Spawn()
local Patrol1 = AI_PATROLZONE:New( PatrolZone1, 3000, 6000, 400, 600 )
Patrol1:ManageFuel( 0.2, 60 )
Patrol1:SetGroup( PatrolGroup )
Patrol1:__Start( 1, PatrolGroup )
Patrol1:SetControllable( PatrolGroup )
Patrol1:__Start( 5 )
local Patrol2 = AI_PATROLZONE:New( PatrolZone2, 600, 1000, 300, 400 )
Patrol2:ManageFuel( 0.2, 0 )
@ -44,8 +44,8 @@ end
-- @param Group#GROUP AIGroup
function Patrol1:OnAfterRTB( AIGroup )
local NewGroup = PatrolSpawn:Spawn()
Patrol2:SetGroup( NewGroup )
Patrol2:__Start( 1, NewGroup )
Patrol2:SetControllable( NewGroup )
Patrol2:__Start( 1 )
end
--- State transition function for the AI\_PATROLZONE **Patrol1** object
@ -68,8 +68,8 @@ end
-- @param Group#GROUP AIGroup
function Patrol2:OnAfterRTB( AIGroup )
local NewGroup = PatrolSpawn:Spawn()
Patrol1:SetGroup( NewGroup )
Patrol1:__Start( 1, NewGroup )
Patrol1:SetControllable( NewGroup )
Patrol1:__Start( 1 )
end
--- State transition function for the AI\_PATROLZONE **Patrol2** object