2023-09-08 13:05:43 +00:00
using System ;
2022-11-28 22:54:08 +00:00
using System.Collections.Generic ;
using UnityEngine ;
using Random = UnityEngine . Random ;
public class TargetController : MonoBehaviour
{
2023-10-23 18:34:15 +00:00
[SerializeField] private GameObject environmentObj ;
[SerializeField] private GameObject agentObj ;
[SerializeField] private GameObject HUDObj ;
[SerializeField] private GameObject sceneBlockContainerObj ;
[SerializeField] private GameObject enemyContainerObj ;
[SerializeField] private GameObject environmentUIObj ;
2023-06-30 09:30:12 +00:00
2022-11-28 22:54:08 +00:00
// area
public GameObject edgeUp ;
2023-08-15 10:47:14 +00:00
2022-11-28 22:54:08 +00:00
public GameObject edgeDown ;
public GameObject edgeLeft ;
public GameObject edgeRight ;
public GameObject edgeAgent_Enemy ;
public float minEnemyAreaX ;
[System.NonSerialized] public float maxEnemyAreaX ;
[System.NonSerialized] public float minEnemyAreaZ ;
[System.NonSerialized] public float maxEnemyAreaZ ;
[System.NonSerialized] public float minAgentAreaX ;
[System.NonSerialized] public float maxAgentAreaX ;
[System.NonSerialized] public float minAgentAreaZ ;
[System.NonSerialized] public float maxAgentAreaZ ;
[System.NonSerialized] public float startTime = 0f ;
[System.NonSerialized] public float leftTime = 0f ;
[SerializeField, Range(0f, 1f)] public float attackProb = 0.2f ;
[SerializeField, Range(0f, 1f)] public float gotoProb = 0.2f ;
[SerializeField, Range(0f, 1f)] public float defenceProb = 0.2f ;
2023-10-24 19:05:50 +00:00
[System.NonSerialized] public Targets targetType ;
2023-09-07 22:15:24 +00:00
[System.NonSerialized] public int gotoLevelNum ;
[System.NonSerialized] public int attackLevelNum ;
2024-01-04 18:46:52 +00:00
[System.NonSerialized] public float [ ] targetState = new float [ 5 ] ;
2023-06-30 09:30:12 +00:00
public enum EndType
{ Win , Lose , Running , Num } ;
2022-11-28 22:54:08 +00:00
[System.NonSerialized] public int targetNum = 0 ;
private Dictionary < int , float [ ] > oneHotRarget = new Dictionary < int , float [ ] > ( ) ;
private float freeProb ;
2023-07-09 17:51:44 +00:00
private float sceneBlockSize ;
2023-08-22 17:58:50 +00:00
private int randBlockType = 0 ;
private int randLevel = 0 ;
2023-10-23 18:34:15 +00:00
public int inArea = 0 ;
2022-12-05 05:56:18 +00:00
public Vector3 targetPosition ;
2022-11-28 22:54:08 +00:00
private bool firstRewardFlag = true ;
2023-10-23 18:34:15 +00:00
public bool targetEnemySpawnFinish = false ;
2023-10-22 16:54:30 +00:00
2023-07-28 10:44:02 +00:00
private SceneBlockContainer sceneBlockCon ;
private EnemyContainer enemyCon ;
2022-11-28 22:54:08 +00:00
private EnvironmentUIControl envUICon ;
2023-10-22 16:54:30 +00:00
private CommonParameterContainer commonParamCon ;
2022-11-28 22:54:08 +00:00
private CharacterController agentCharaCon ;
2022-12-09 09:53:53 +00:00
private HUDController hudCon ;
2023-08-22 17:58:50 +00:00
private MessageBoxController messageBoxCon ;
2023-06-30 09:30:12 +00:00
2023-06-29 06:18:10 +00:00
// start scene datas 0=train 1=play
private int gamemode ;
2022-11-28 22:54:08 +00:00
// Start is called before the first frame update
2023-06-30 09:30:12 +00:00
private void Start ( )
2022-11-28 22:54:08 +00:00
{
2023-11-03 03:56:44 +00:00
commonParamCon = CommonParameterContainer . Instance ;
2023-07-28 10:44:02 +00:00
sceneBlockCon = sceneBlockContainerObj . GetComponent < SceneBlockContainer > ( ) ;
2023-07-08 14:22:31 +00:00
envUICon = environmentUIObj . GetComponent < EnvironmentUIControl > ( ) ;
2023-07-28 10:44:02 +00:00
enemyCon = enemyContainerObj . GetComponent < EnemyContainer > ( ) ;
2023-07-08 14:22:31 +00:00
agentCharaCon = agentObj . GetComponent < CharacterController > ( ) ;
hudCon = HUDObj . GetComponent < HUDController > ( ) ;
2023-08-22 17:58:50 +00:00
messageBoxCon = HUDObj . GetComponent < MessageBoxController > ( ) ;
2023-07-08 14:22:31 +00:00
// get parameter from ParameterContainer
2023-10-22 16:54:30 +00:00
gamemode = commonParamCon . gameMode ;
attackProb = commonParamCon . attackProb ;
gotoProb = commonParamCon . gotoProb ;
defenceProb = commonParamCon . defenceProb ;
2023-07-08 14:22:31 +00:00
// initialize spawn area
2022-11-28 22:54:08 +00:00
minEnemyAreaX = edgeLeft . transform . localPosition . x + 1.0f ;
maxEnemyAreaX = edgeRight . transform . localPosition . x - 1.0f ;
minEnemyAreaZ = edgeAgent_Enemy . transform . localPosition . z + 1.0f ;
maxEnemyAreaZ = edgeUp . transform . localPosition . z - 1.0f ;
minAgentAreaX = edgeLeft . transform . localPosition . x + 1.0f ;
maxAgentAreaX = edgeRight . transform . localPosition . x - 1.0f ;
minAgentAreaZ = edgeDown . transform . localPosition . z + 1.0f ;
maxAgentAreaZ = edgeAgent_Enemy . transform . localPosition . z - 1.0f ;
freeProb = 1 - attackProb - gotoProb - defenceProb ;
2023-09-14 11:13:53 +00:00
targetNum = ( int ) Targets . Num ;
2023-10-22 16:54:30 +00:00
gotoLevelNum = commonParamCon . scenePrefabSet . GetLevelNumber ( Targets . Go ) ;
attackLevelNum = commonParamCon . scenePrefabSet . GetLevelNumber ( Targets . Attack ) ;
2022-11-28 22:54:08 +00:00
if ( freeProb < 0 )
{
2023-07-28 10:44:02 +00:00
Debug . LogError ( "TargetController.Start: target percentage wrong" ) ;
2022-11-28 22:54:08 +00:00
}
// initialize a simple fake onehot encoder.
for ( int i = 0 ; i < targetNum ; i + + )
{
float [ ] onehotList = new float [ targetNum ] ;
for ( int j = 0 ; j < targetNum ; j + + )
{
onehotList [ j ] = 0 ;
}
onehotList [ i ] = 1 ;
oneHotRarget . Add ( i , onehotList ) ;
}
}
private void Update ( )
{
2023-06-29 06:18:10 +00:00
// if gamemode is play, then time will keep paramCon.timeLimit
if ( gamemode = = 1 )
{
2023-10-22 16:54:30 +00:00
leftTime = commonParamCon . timeLimit ;
2023-06-29 06:18:10 +00:00
// print out time
2023-07-28 10:44:02 +00:00
// Debug.Log("Playing Time: " + leftTime);
2023-06-29 06:18:10 +00:00
}
else
{
2023-10-22 16:54:30 +00:00
leftTime = commonParamCon . timeLimit - Time . time + startTime ;
2023-06-29 06:18:10 +00:00
}
2022-11-28 22:54:08 +00:00
}
2023-09-08 13:05:43 +00:00
/// <summary>
/// Generates a new scene configuration by selecting a random target type and spawning related scene blocks.
/// </summary>
/// <remarks>
/// This method is responsible for creating a new scene configuration, which involves selecting a target type
/// (Go, Attack, Defence, or Free) based on predefined probabilities. Depending on the chosen target type,
/// the method spawns the associated scene blocks, updates various flags, and informs the user interface about
/// the selected target type.
/// </remarks>
2023-06-30 09:30:12 +00:00
public void RollNewScene ( )
2022-11-28 22:54:08 +00:00
{
startTime = Time . time ; // Reset StartTime as now time
2023-10-22 16:54:30 +00:00
leftTime = commonParamCon . timeLimit - Time . time + startTime ;
2022-11-28 22:54:08 +00:00
float randTargetType = UnityEngine . Random . Range ( 0f , 1f ) ;
if ( randTargetType < = gotoProb )
{
// goto target spawn
Debug . Log ( "GOTO THIS TARGET!" ) ;
2023-10-24 19:05:50 +00:00
targetType = Targets . Go ;
2023-09-14 11:13:53 +00:00
RandomSpawnSceneBlock ( Targets . Go ) ;
2022-11-28 22:54:08 +00:00
// set startDistance
firstRewardFlag = true ;
}
else if ( randTargetType > gotoProb & & randTargetType < = gotoProb + attackProb )
{
// attack target spawn
2023-10-08 14:56:11 +00:00
Debug . Log ( "ATTACK Mode Start" ) ;
2023-10-24 19:05:50 +00:00
targetType = Targets . Attack ;
2023-09-14 11:13:53 +00:00
RandomSpawnSceneBlock ( Targets . Attack ) ;
2022-11-28 22:54:08 +00:00
// set startDistance
firstRewardFlag = true ;
2022-12-01 10:52:52 +00:00
targetEnemySpawnFinish = false ;
2022-11-28 22:54:08 +00:00
}
else if ( randTargetType > gotoProb + attackProb & & randTargetType < = gotoProb + attackProb + defenceProb )
{
// defence target spawn
2023-10-08 14:56:11 +00:00
Debug . Log ( "DEFENCE Mode Start" ) ;
2023-10-24 19:05:50 +00:00
targetType = Targets . Defence ;
2023-09-14 11:13:53 +00:00
RandomSpawnSceneBlock ( Targets . Defence ) ;
2022-11-28 22:54:08 +00:00
// set startDistance
firstRewardFlag = true ;
}
else
{
2023-10-08 14:56:11 +00:00
Debug . Log ( "Free Mode Start" ) ;
2023-10-24 19:05:50 +00:00
targetType = Targets . Free ;
2023-07-28 10:44:02 +00:00
enemyCon . DestroyAllEnemys ( ) ;
enemyCon . RandomInitEnemys ( hudCon . enemyNum ) ;
2023-06-30 09:30:12 +00:00
MoveAgentToSpwanArea ( ) ;
2023-07-28 10:44:02 +00:00
sceneBlockCon . DestroyBlock ( ) ;
2022-11-28 22:54:08 +00:00
}
2023-06-30 09:30:12 +00:00
UpdateTargetStates ( ) ;
2023-10-24 19:05:50 +00:00
envUICon . UpdateTargetType ( targetType ) ;
2022-11-28 22:54:08 +00:00
}
2023-08-15 10:47:14 +00:00
#region Agent Move Method
2022-11-28 22:54:08 +00:00
2023-09-08 13:05:43 +00:00
/// <summary>
/// Move the agent to the spawn area.
/// 将Agent移动到生成区域。
/// </summary>
2023-07-09 17:51:44 +00:00
private void MoveAgentToSpwanArea ( )
2022-11-28 22:54:08 +00:00
{
2022-12-07 21:24:51 +00:00
float randX = UnityEngine . Random . Range ( minAgentAreaX , maxAgentAreaX ) ; ;
float randZ = 0f ;
2023-10-22 16:54:30 +00:00
if ( commonParamCon . spawnAgentInAllMap )
2022-12-07 21:24:51 +00:00
{
// spawn agent in all around map
randZ = UnityEngine . Random . Range ( minAgentAreaZ , maxEnemyAreaZ ) ;
}
else
{
// spawn agent in only agent spawn area
randZ = UnityEngine . Random . Range ( minAgentAreaZ , maxAgentAreaZ ) ;
}
2022-11-28 22:54:08 +00:00
int Y = 1 ;
Vector3 initAgentLoc = new Vector3 ( randX , Y , randZ ) ;
2023-06-30 09:30:12 +00:00
MoveAgentTo ( initAgentLoc ) ;
2022-11-28 22:54:08 +00:00
}
2023-09-08 13:05:43 +00:00
/// <summary>
/// Move the agent to the specified position.
/// 将代理移动到指定位置。
/// </summary>
/// <param name="position">要移动到的位置。</param>
/// <remarks>
/// When moving the character using transform.localPosition,
/// must disable the character controller, or it won't work properly.
/// 使用 transform.localPosition 移动角色时,
/// 必须禁用角色控制器,否则它将无法正常工作。
/// </remarks>
2023-08-22 17:58:50 +00:00
public void MoveAgentTo ( Vector3 position )
2022-11-28 22:54:08 +00:00
{
// while using transform.localPosition to move character
// u should turn off character Controller or it won't work
agentCharaCon . enabled = false ;
2023-08-22 17:58:50 +00:00
agentObj . transform . localPosition = position ;
2022-11-28 22:54:08 +00:00
agentCharaCon . enabled = true ;
}
2023-08-15 10:47:14 +00:00
#endregion Agent Move Method
2023-09-08 13:05:43 +00:00
/// <summary>
/// Randomly spawns a scene block based on the target type.
/// 根据目标类型随机生成场景块。
/// </summary>
/// <param name="targetType">要生成的场景块的目标类型。The target type of the scene block to be generated.</param>
/// <remarks>
/// This method generates a random scene block based on the target type and spawns enemies at the specified location.
/// 此方法根据目标类型生成一个随机场景块,并在指定位置生成敌人。
/// </remarks>
2023-09-14 11:13:53 +00:00
private void RandomSpawnSceneBlock ( Targets targetType )
2023-08-15 10:47:14 +00:00
{
2023-09-09 12:04:57 +00:00
randLevel = RollRandomLevelIndex ( targetType ) ;
2023-10-22 16:54:30 +00:00
randBlockType = Random . Range ( 0 , commonParamCon . scenePrefabSet . GetBlockNumber ( randLevel , targetType ) ) ;
sceneBlockSize = commonParamCon . scenePrefabSet . GetBlockSize ( randLevel , randBlockType , targetType ) ;
2023-08-15 10:47:14 +00:00
float randX = UnityEngine . Random . Range ( minEnemyAreaX + sceneBlockSize / 2 + 1f , maxEnemyAreaX - sceneBlockSize / 2 - 1f ) ;
float randZ = UnityEngine . Random . Range ( minEnemyAreaZ + sceneBlockSize / 2 + 1f , maxEnemyAreaZ - sceneBlockSize / 2 - 1f ) ;
targetPosition = new Vector3 ( randX , 0 , randZ ) ;
// init scene block
sceneBlockCon . DestroyBlock ( ) ;
2023-10-23 18:34:15 +00:00
sceneBlockCon . CreateNewBlock ( targetType , randLevel , randBlockType , targetPosition , commonParamCon . group1Tag , commonParamCon . group2Tag ) ;
2023-08-15 10:47:14 +00:00
enemyCon . DestroyAllEnemys ( ) ;
enemyCon . RandomInitEnemysExcept ( hudCon . enemyNum , targetPosition , sceneBlockSize ) ;
2023-08-22 17:58:50 +00:00
sceneBlockCon . nowBlock . InitBlock ( environmentObj ) ;
2023-08-15 10:47:14 +00:00
}
2024-01-09 10:18:16 +00:00
/// <summary>
/// Spawns a scene block at a specified position.
/// </summary>
/// <param name="targetType">The type of the target, determining the type of block to generate.</param>
/// <param name="level">The level of the block, affecting its properties.</param>
/// <param name="blockNum">The number of the block, used to distinguish different blocks of the same level.</param>
/// <param name="blockPosition">The position of the block in the scene.</param>
/// <remarks>
/// This method first destroys the current block in the scene, then creates a new block based on the provided parameters and initializes it.
/// 'sceneBlockCon' is responsible for managing the creation, destruction, and initialization of scene blocks.
/// 'commonParamCon' provides additional parameters required for block creation.
/// 'environmentObj' is used during the initialization process of the block.
/// </remarks>
2024-01-04 18:46:52 +00:00
private void SpawnSceneBlock ( Targets targetType , int level , int blockNum , Vector3 blockPosition )
{
sceneBlockCon . DestroyBlock ( ) ;
sceneBlockCon . CreateNewBlock ( targetType , level , blockNum , blockPosition , commonParamCon . group1Tag , commonParamCon . group2Tag ) ;
sceneBlockCon . InitializeBlock ( environmentObj ) ;
}
2023-08-15 10:47:14 +00:00
#region Play Mode Method
2023-06-29 06:18:10 +00:00
2023-09-08 13:05:43 +00:00
/// <summary>
/// Initializes the game in play mode.
/// 初始化游戏playMode。
/// </summary>
/// <remarks>
/// This method is used to initialize the game in play mode,
/// including setting the target type, updating target states,
/// updating UI display, moving the agent to the spawn area,
/// destroying all enemies, and scene blocks.
/// 该方法用于初始化游戏播放模式, 包括设置目标类型、更新目标状态、更新UI显示、
/// 将代理移动到生成区域、销毁所有敌人和场景块。
/// </remarks>
2024-01-04 18:46:52 +00:00
public void PlayModeInitialize ( )
2023-06-29 06:18:10 +00:00
{
2023-10-24 19:05:50 +00:00
targetType = Targets . Stay ;
2023-07-28 10:44:02 +00:00
UpdateTargetStates ( ) ;
2023-10-24 19:05:50 +00:00
envUICon . UpdateTargetType ( targetType ) ;
2023-06-30 09:30:12 +00:00
MoveAgentToSpwanArea ( ) ;
2023-07-28 10:44:02 +00:00
enemyCon . DestroyAllEnemys ( ) ;
sceneBlockCon . DestroyBlock ( ) ;
2023-06-29 06:18:10 +00:00
}
2024-01-04 18:46:52 +00:00
/// <summary>
/// Changes the target type in play mode and updates the game environment accordingly.
/// </summary>
/// <param name="newTargetType">The new target type to be set.</param>
/// <param name="spawnPosition">Spawn position for scene blocks.</param>
/// <param name="level">Level parameter for spawning scene blocks.</param>
/// <param name="blockNum">Number of blocks to spawn.</param>
/// <remarks>
/// This method updates the target type to the specified new target. If a spawn position is provided, it spawns scene blocks at that position
/// with the specified level and block number. The target states are then updated based on the new setup. The UI is also refreshed to reflect the new target type.
/// </remarks>
public void PlayTargetChange ( Targets newTargetType , Vector3 ? spawnPosition = null , int level = 0 , int blockNum = 0 )
2023-06-29 06:18:10 +00:00
{
2024-01-04 18:46:52 +00:00
targetType = newTargetType ;
if ( spawnPosition . HasValue )
{
SpawnSceneBlock ( targetType , level , blockNum , spawnPosition . Value ) ;
UpdateTargetStates ( spawnPosition . Value ) ;
}
else
{
UpdateTargetStates ( ) ;
}
2023-10-24 19:05:50 +00:00
envUICon . UpdateTargetType ( targetType ) ;
2023-06-29 06:18:10 +00:00
}
2023-08-15 10:47:14 +00:00
#endregion Play Mode Method
2023-09-08 13:05:43 +00:00
/// <summary>
/// Gets the target observation states.
/// 获取目标观测状态。
/// </summary>
/// <param name="targetPosition">The target position (optional).</param>
2023-08-22 17:58:50 +00:00
private void UpdateTargetStates ( Vector3 ? targetPosition = null )
2023-08-15 10:47:14 +00:00
{
// targettype, x,y,z, firebasesAreaDiameter
2023-10-24 19:05:50 +00:00
targetState [ 0 ] = ( int ) targetType ;
2023-08-22 17:58:50 +00:00
if ( targetPosition ! = null )
2023-08-15 10:47:14 +00:00
{
2023-08-22 17:58:50 +00:00
this . targetPosition = ( Vector3 ) targetPosition ;
2023-08-15 10:47:14 +00:00
}
2023-10-24 19:05:50 +00:00
if ( targetType = = ( int ) Targets . Free | | targetType = = Targets . Stay )
2023-08-15 10:47:14 +00:00
{
for ( int i = 1 ; i < targetState . Length ; i + + )
// set target position state to 0
targetState [ i ] = 0f ;
}
else
{
2024-01-04 18:46:52 +00:00
V ector3 fireBasePosition = sceneBlockCon . nowBlock . firebasesAreaPosition ;
Vector3 convertedPosition = fireBasePosition - this . transform . position ;
targetState [ 1 ] = convertedPosition . x ;
targetState [ 2 ] = convertedPosition . y ;
targetState [ 3 ] = convertedPosition . z ;
2023-08-22 17:58:50 +00:00
targetState [ 4 ] = sceneBlockCon . nowBlock . firebasesAreaDiameter ;
2023-08-15 10:47:14 +00:00
}
}
2023-09-08 13:05:43 +00:00
/// <summary>
/// Gets the in-area state.
/// 获取是否在区域内的State
/// </summary>
/// <returns>The in-area state.</returns>
2023-08-15 10:47:14 +00:00
public int GetInAreaState ( )
{
2023-10-24 19:05:50 +00:00
if ( targetType = = Targets . Go )
2023-08-15 10:47:14 +00:00
{
return inArea ;
}
else
{
return 0 ;
}
}
2023-08-22 17:58:50 +00:00
2023-09-08 13:05:43 +00:00
/// <summary>
/// Gets a random level index based on the target type.
/// 根据目标类型获取随机关卡索引。
/// </summary>
/// <param name="target">The target type.</param>
/// <returns>A random level index.</returns>
2023-09-14 11:13:53 +00:00
public int RollRandomLevelIndex ( Targets target )
2023-08-22 17:58:50 +00:00
{
2023-11-15 16:03:54 +00:00
Debug . Log ( target ) ;
2023-08-22 17:58:50 +00:00
List < float > targetProbs ;
2023-11-17 04:44:07 +00:00
targetProbs = commonParamCon . levelProbs [ target ] ;
2023-08-22 17:58:50 +00:00
// sample random level depends on the target probabilities
float randomNum = UnityEngine . Random . Range ( 0f , 1f ) ;
float sumProb = 0f ;
for ( int i = 0 ; i < targetProbs . Count ; i + + )
{
sumProb + = targetProbs [ i ] ;
if ( randomNum < sumProb )
{
return i ;
}
}
// If no level was returned, log an error and return -1
messageBoxCon . PushMessage (
2023-11-15 16:03:54 +00:00
new List < string > { "[ERROR]TargetController:RollRandomLevelIndex" , "level index out of range" } ,
2023-08-22 17:58:50 +00:00
new List < string > { "orange" } ) ;
return - 1 ;
}
2023-06-30 09:30:12 +00:00
}