Aimbot-ParallelEnv/Assets/Script/GameScript/TargetController.cs

413 lines
16 KiB
C#
Raw Permalink Normal View History

using System;
using System.Collections.Generic;
using UnityEngine;
using Random = UnityEngine.Random;
public class TargetController : MonoBehaviour
{
[SerializeField] private GameObject environmentObj;
[SerializeField] private GameObject agentObj;
[SerializeField] private GameObject HUDObj;
[SerializeField] private GameObject sceneBlockContainerObj;
[SerializeField] private GameObject enemyContainerObj;
[SerializeField] private GameObject environmentUIObj;
// area
public GameObject edgeUp;
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;
[System.NonSerialized] public Targets targetType;
[System.NonSerialized] public int gotoLevelNum;
[System.NonSerialized] public int attackLevelNum;
[System.NonSerialized] public float[] targetState = new float[5];
public enum EndType
{ Win, Lose, Running, Num };
[System.NonSerialized] public int targetNum = 0;
private Dictionary<int, float[]> oneHotRarget = new Dictionary<int, float[]>();
private float freeProb;
private float sceneBlockSize;
private int randBlockType = 0;
private int randLevel = 0;
public int inArea = 0;
public Vector3 targetPosition;
private bool firstRewardFlag = true;
public bool targetEnemySpawnFinish = false;
private SceneBlockContainer sceneBlockCon;
private EnemyContainer enemyCon;
private EnvironmentUIControl envUICon;
private CommonParameterContainer commonParamCon;
private CharacterController agentCharaCon;
private HUDController hudCon;
private MessageBoxController messageBoxCon;
// start scene datas 0=train 1=play
private int gamemode;
// Start is called before the first frame update
private void Start()
{
commonParamCon = CommonParameterContainer.Instance;
sceneBlockCon = sceneBlockContainerObj.GetComponent<SceneBlockContainer>();
envUICon = environmentUIObj.GetComponent<EnvironmentUIControl>();
enemyCon = enemyContainerObj.GetComponent<EnemyContainer>();
agentCharaCon = agentObj.GetComponent<CharacterController>();
hudCon = HUDObj.GetComponent<HUDController>();
messageBoxCon = HUDObj.GetComponent<MessageBoxController>();
// get parameter from ParameterContainer
gamemode = commonParamCon.gameMode;
attackProb = commonParamCon.attackProb;
gotoProb = commonParamCon.gotoProb;
defenceProb = commonParamCon.defenceProb;
// initialize spawn area
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;
targetNum = (int)Targets.Num;
gotoLevelNum = commonParamCon.scenePrefabSet.GetLevelNumber(Targets.Go);
attackLevelNum = commonParamCon.scenePrefabSet.GetLevelNumber(Targets.Attack);
if (freeProb < 0)
{
Debug.LogError("TargetController.Start: target percentage wrong");
}
// 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()
{
// if gamemode is play, then time will keep paramCon.timeLimit
if (gamemode == 1)
{
leftTime = commonParamCon.timeLimit;
// print out time
// Debug.Log("Playing Time: " + leftTime);
}
else
{
leftTime = commonParamCon.timeLimit - Time.time + startTime;
}
}
/// <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>
public void RollNewScene()
{
startTime = Time.time;// Reset StartTime as now time
leftTime = commonParamCon.timeLimit - Time.time + startTime;
float randTargetType = UnityEngine.Random.Range(0f, 1f);
if (randTargetType <= gotoProb)
{
// goto target spawn
Debug.Log("GOTO THIS TARGET!");
targetType = Targets.Go;
RandomSpawnSceneBlock(Targets.Go);
// set startDistance
firstRewardFlag = true;
}
else if (randTargetType > gotoProb && randTargetType <= gotoProb + attackProb)
{
// attack target spawn
Debug.Log("ATTACK Mode Start");
targetType = Targets.Attack;
RandomSpawnSceneBlock(Targets.Attack);
// set startDistance
firstRewardFlag = true;
targetEnemySpawnFinish = false;
}
else if (randTargetType > gotoProb + attackProb && randTargetType <= gotoProb + attackProb + defenceProb)
{
// defence target spawn
Debug.Log("DEFENCE Mode Start");
targetType = Targets.Defence;
RandomSpawnSceneBlock(Targets.Defence);
// set startDistance
firstRewardFlag = true;
}
else
{
Debug.Log("Free Mode Start");
targetType = Targets.Free;
enemyCon.DestroyAllEnemys();
enemyCon.RandomInitEnemys(hudCon.enemyNum);
MoveAgentToSpwanArea();
sceneBlockCon.DestroyBlock();
}
UpdateTargetStates();
envUICon.UpdateTargetType(targetType);
}
#region Agent Move Method
/// <summary>
/// Move the agent to the spawn area.
/// 将Agent移动到生成区域。
/// </summary>
private void MoveAgentToSpwanArea()
{
float randX = UnityEngine.Random.Range(minAgentAreaX, maxAgentAreaX); ;
float randZ = 0f;
if (commonParamCon.spawnAgentInAllMap)
{
// 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);
}
int Y = 1;
Vector3 initAgentLoc = new Vector3(randX, Y, randZ);
MoveAgentTo(initAgentLoc);
}
/// <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>
public void MoveAgentTo(Vector3 position)
{
// while using transform.localPosition to move character
// u should turn off character Controller or it won't work
agentCharaCon.enabled = false;
agentObj.transform.localPosition = position;
agentCharaCon.enabled = true;
}
#endregion Agent Move Method
/// <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>
private void RandomSpawnSceneBlock(Targets targetType)
{
randLevel = RollRandomLevelIndex(targetType);
randBlockType = Random.Range(0, commonParamCon.scenePrefabSet.GetBlockNumber(randLevel,targetType));
sceneBlockSize = commonParamCon.scenePrefabSet.GetBlockSize(randLevel, randBlockType, targetType);
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();
sceneBlockCon.CreateNewBlock(targetType, randLevel, randBlockType, targetPosition, commonParamCon.group1Tag, commonParamCon.group2Tag);
enemyCon.DestroyAllEnemys();
enemyCon.RandomInitEnemysExcept(hudCon.enemyNum, targetPosition, sceneBlockSize);
sceneBlockCon.nowBlock.InitBlock(environmentObj);
}
/// <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>
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);
}
#region Play Mode Method
/// <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>
public void PlayModeInitialize()
{
targetType = Targets.Stay;
UpdateTargetStates();
envUICon.UpdateTargetType(targetType);
MoveAgentToSpwanArea();
enemyCon.DestroyAllEnemys();
sceneBlockCon.DestroyBlock();
}
/// <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)
{
targetType = newTargetType;
if(spawnPosition.HasValue)
{
SpawnSceneBlock(targetType, level, blockNum, spawnPosition.Value);
UpdateTargetStates(spawnPosition.Value);
}
else
{
UpdateTargetStates();
}
envUICon.UpdateTargetType(targetType);
}
#endregion Play Mode Method
/// <summary>
/// Gets the target observation states.
/// 获取目标观测状态。
/// </summary>
/// <param name="targetPosition">The target position (optional).</param>
private void UpdateTargetStates(Vector3? targetPosition = null)
{
// targettype, x,y,z, firebasesAreaDiameter
targetState[0] = (int)targetType;
if (targetPosition != null)
{
this.targetPosition = (Vector3)targetPosition;
}
if (targetType == (int)Targets.Free || targetType == Targets.Stay)
{
for (int i = 1; i < targetState.Length; i++)
// set target position state to 0
targetState[i] = 0f;
}
else
{
Vector3 fireBasePosition = sceneBlockCon.nowBlock.firebasesAreaPosition;
Vector3 convertedPosition = fireBasePosition - this.transform.position;
targetState[1] = convertedPosition.x;
targetState[2] = convertedPosition.y;
targetState[3] = convertedPosition.z;
targetState[4] = sceneBlockCon.nowBlock.firebasesAreaDiameter;
}
}
/// <summary>
/// Gets the in-area state.
/// 获取是否在区域内的State
/// </summary>
/// <returns>The in-area state.</returns>
public int GetInAreaState()
{
if (targetType == Targets.Go)
{
return inArea;
}
else
{
return 0;
}
}
/// <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>
public int RollRandomLevelIndex(Targets target)
{
Debug.Log(target);
List<float> targetProbs;
targetProbs = commonParamCon.levelProbs[target];
// 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(
new List<string> { "[ERROR]TargetController:RollRandomLevelIndex", "level index out of range" },
new List<string> { "orange" });
return -1;
}
}