Aimbot-ParallelEnv/Assets/Script/GameScript/TargetController.cs
2024-01-09 19:18:16 +09:00

413 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}