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

464 lines
18 KiB
C#
Raw Normal View History

using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using UnityEngine;
using Random = UnityEngine.Random;
public class TargetController : MonoBehaviour
{
public GameObject EnvironmentObj;
public GameObject AgentObj;
public GameObject SceneBlockContainerObj;
public GameObject EnemyContainerObj;
public GameObject ParameterContainerObj;
public GameObject EnvironmentUIObj;
public GameObject WorldUIObj;
// area
public GameObject edgeUp;
public GameObject edgeDown;
public GameObject edgeLeft;
public GameObject edgeRight;
public GameObject edgeAgent_Enemy;
//group
public string group1Tag = "Player";
public string group2Tag = "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 int targetTypeInt;
public float[] targetState = new float[6];
public enum Targets { Free, Go, Attack, Defence, Num };// Num is use for get total target bumber
public enum EndType { Win, Lose, Running, Num };
[System.NonSerialized] public int targetNum = 0;
private Dictionary<int, float[]> oneHotRarget = new Dictionary<int, float[]>();
private int inArea = 0;
private float freeProb;
private float sceneSize;
private float lastDistance;
public Vector3 targetPosition;
private Vector3 targetLocalPosition;
private bool firstRewardFlag = true;
private bool targetEnemySpawnFinish = false;
private SceneBlockContainer blockCont;
private EnemyContainer enemyCont;
private EnvironmentUIControl envUICon;
private ParameterContainer paramCon;
private CharacterController agentCharaCon;
private WorldUIController worldUICon;
// Start is called before the first frame update
void Start()
{
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;
blockCont = SceneBlockContainerObj.GetComponent<SceneBlockContainer>();
envUICon = EnvironmentUIObj.GetComponent<EnvironmentUIControl>();
enemyCont = EnemyContainerObj.GetComponent<EnemyContainer>();
agentCharaCon = AgentObj.GetComponent<CharacterController>();
paramCon = ParameterContainerObj.GetComponent<ParameterContainer>();
worldUICon = WorldUIObj.GetComponent<WorldUIController>();
freeProb = 1 - attackProb - gotoProb - defenceProb;
targetNum = (int)Targets.Num;
if (freeProb < 0)
{
Debug.LogError("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()
{
leftTime = paramCon.timeLimit - Time.time + startTime;
}
public void rollNewScene()
{
startTime = Time.time;// Reset StartTime as now time
leftTime = paramCon.timeLimit - Time.time + startTime;
float randTargetType = UnityEngine.Random.Range(0f, 1f);
if (randTargetType <= gotoProb)
{
// goto target spawn
Debug.Log("GOTO THIS TARGET!");
targetTypeInt = (int)Targets.Go;
int randBlockType = Random.Range(0, blockCont.goBlockPrefabs.Length);
// get choosed scene size
sceneSize = blockCont.goBlockPrefabs[randBlockType].GetComponent<SceneBlock>().blockSize;
float randX = UnityEngine.Random.Range(minEnemyAreaX + sceneSize/2 + 1f, maxEnemyAreaX - sceneSize/2 - 1f);
float randZ = UnityEngine.Random.Range(minEnemyAreaZ + sceneSize/2 + 1f, maxEnemyAreaZ - sceneSize/2 - 1f);
targetPosition = new Vector3(randX, 0f, randZ);
// Init Agent position
moveAgentToSpwanArea();
// init scene block
blockCont.destroyBlock();
blockCont.createNewBlock(targetTypeInt, randBlockType, targetPosition, group1Tag, group2Tag);
enemyCont.destroyAllEnemys();
enemyCont.randomInitEnemysExcept(paramCon.enemyNum, targetPosition, sceneSize);
blockCont.thisBlock.initBlock(EnvironmentObj);
// set startDistance
firstRewardFlag = true;
}
else if (randTargetType > gotoProb && randTargetType <= gotoProb + attackProb)
{
// attack target spawn
Debug.Log("ATTACK!");
targetTypeInt = (int)Targets.Attack;
int randBlockType = Random.Range(0, blockCont.attackBlockPrefabs.Length);
// get choosed scene size
sceneSize = blockCont.attackBlockPrefabs[randBlockType].GetComponent<SceneBlock>().blockSize;
float randX = UnityEngine.Random.Range(minEnemyAreaX + sceneSize/2 + 1f, maxEnemyAreaX - sceneSize/2 - 1f);
float randZ = UnityEngine.Random.Range(minEnemyAreaZ + sceneSize/2 + 1f, maxEnemyAreaZ - sceneSize/2 - 1f);
targetPosition = new Vector3(randX, 0f, randZ);
// Init Agent position
moveAgentToSpwanArea();
// init scene block
blockCont.destroyBlock();
blockCont.createNewBlock(targetTypeInt, randBlockType, targetPosition, group1Tag, group2Tag);
enemyCont.destroyAllEnemys();
enemyCont.randomInitEnemysExcept(paramCon.enemyNum, targetPosition, sceneSize);
blockCont.thisBlock.initBlock(EnvironmentObj);
// set startDistance
firstRewardFlag = true;
targetEnemySpawnFinish = false;
}
else if (randTargetType > gotoProb + attackProb && randTargetType <= gotoProb + attackProb + defenceProb)
{
// defence target spawn
Debug.Log("DEFENCE!");
targetTypeInt = (int)Targets.Defence;
int randBlockType = Random.Range(0, blockCont.attackBlockPrefabs.Length);
// get choosed scene size
sceneSize = blockCont.defencePrefabs[randBlockType].GetComponent<SceneBlock>().blockSize;
float randX = UnityEngine.Random.Range(minEnemyAreaX + sceneSize/2 + 1f, maxEnemyAreaX - sceneSize/2 - 1f);
float randZ = UnityEngine.Random.Range(minEnemyAreaZ + sceneSize/2 + 1f, maxEnemyAreaZ - sceneSize/2 - 1f);
targetPosition = new Vector3(randX, 0f, randZ);
// Init Agent position
moveAgentTo(targetPosition);
// init scene block
blockCont.destroyBlock();
blockCont.createNewBlock(targetTypeInt, randBlockType, targetPosition, group1Tag, group2Tag);
enemyCont.destroyAllEnemys();
enemyCont.randomInitEnemysExcept(paramCon.enemyNum, targetPosition, sceneSize);
blockCont.thisBlock.initBlock(EnvironmentObj);
// set startDistance
firstRewardFlag = true;
}
else
{
Debug.Log("Free");
targetTypeInt = (int)Targets.Free;
enemyCont.destroyAllEnemys();
enemyCont.randomInitEnemys(paramCon.enemyNum);
moveAgentToSpwanArea();
blockCont.destroyBlock();
}
updateTargetStates();
envUICon.updateTargetType(targetTypeInt);
}
// get target observation states
public void updateTargetStates()
{
// targettype, x,y,z, firebasesAreaDiameter
if (targetTypeInt == (int)Targets.Free)
{
targetState[0] = targetTypeInt;
for(int i = 1; i < targetState.Length; i++)
targetState[i] = 0f;
}
else
{
targetState[0] = targetTypeInt;
targetState[1] = targetPosition.x;
targetState[2] = targetPosition.y;
targetState[3] = targetPosition.z;
targetState[4] = blockCont.thisBlock.firebasesAreaDiameter;
targetState[5] = blockCont.thisBlock.belongRatio;
}
}
// move Agent into Agent Spawn Area
public void moveAgentToSpwanArea()
{
float randX = UnityEngine.Random.Range(minAgentAreaX, maxAgentAreaX);
float randZ = UnityEngine.Random.Range(minAgentAreaZ, maxAgentAreaZ);
int Y = 1;
Vector3 initAgentLoc = new Vector3(randX, Y, randZ);
moveAgentTo(initAgentLoc);
}
// move Agent to this position
public void moveAgentTo(Vector3 thisPosition)
{
// while using transform.localPosition to move character
// u should turn off character Controller or it won't work
agentCharaCon.enabled = false;
AgentObj.transform.localPosition = thisPosition;
agentCharaCon.enabled = true;
}
// check over and get rewards
// 1 = success,2 = overtime,0 = notover
public (int, float,float) checkOverAndRewards()
{
int endTypeInt = 0;
float thisReward = 0;
float endReward = 0;
float nowDistance = 0f;
switch (targetTypeInt)
{
case (int)Targets.Go:
// goto
(nowDistance, inArea) = blockCont.getAgentTargetDistanceAndInside(AgentObj.transform.position);
envUICon.updateTargetGauge(blockCont.thisBlock.firebasesBelong, blockCont.thisBlock.belongMaxPoint);
float areaTargetReward = getDistanceReward(nowDistance, inArea);
// if (blockCont.thisBlock.firebasesBelong >= blockCont.thisBlock.belongMaxPoint)
if(inArea != 0)
{
// win
// let the area belongs to me
thisReward = areaTargetReward;
endReward = paramCon.goWinReward;
//thisReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance);
endTypeInt = (int)EndType.Win;
}
else if (leftTime <= 0)
{
// time out lose
thisReward = areaTargetReward;
endReward = paramCon.loseReward;
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
thisReward = areaTargetReward;
endReward = 0;
endTypeInt = (int)EndType.Running;
}
break;
case (int)Targets.Attack:
// attack
(nowDistance, inArea) = blockCont.getAgentTargetDistanceAndInside(AgentObj.transform.position);
envUICon.updateTargetGauge(blockCont.thisBlock.firebasesBelong, blockCont.thisBlock.belongMaxPoint);
if (blockCont.thisBlock.getInAreaNumber(group2Tag) <= 0 && targetEnemySpawnFinish)
{
// win
// let the area belongs to me and kill every enmy in this area.
thisReward = 0;
endReward = paramCon.attackWinReward;
//thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Win;
}
else if (leftTime <= 0 && targetEnemySpawnFinish)
{
// time out lose
thisReward = 0;
endReward = paramCon.loseReward;
//thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
// thisReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance);
thisReward = 0;
endReward = 0;
targetEnemySpawnFinish = true;
endTypeInt = (int)EndType.Running;
}
break;
case (int)Targets.Defence:
//defence
// !!! DIDN't FINISH!!!
(nowDistance, inArea) = blockCont.getAgentTargetDistanceAndInside(AgentObj.transform.position);
envUICon.updateTargetGauge(blockCont.thisBlock.firebasesBelong, blockCont.thisBlock.belongMaxPoint);
if (leftTime <= 0 && blockCont.thisBlock.firebasesBelong >= 0f)
{
// win
// time over and the area still mine
thisReward = paramCon.defenceWinReward;
//thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Win;
}
else if (blockCont.thisBlock.firebasesBelong <= blockCont.thisBlock.belongMaxPoint)
{
// lost area lose
thisReward = paramCon.loseReward;
//thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
// thisReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance);
endTypeInt = (int)EndType.Running;
}
break;
default:
//free kill
if (EnemyContainerObj.transform.childCount <= 0)
{
// win
//thisReward = paramCon.winReward + (paramCon.timeBonusPerSecReward * leftTime);
thisReward = 0;
endReward = paramCon.freeWinReward;
endTypeInt = (int)EndType.Win;
}
else if (Time.time - startTime >= paramCon.timeLimit)
{
// lose
//thisReward = paramCon.loseReward;
thisReward = 0;
endReward = paramCon.loseReward;
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
thisReward = 0;
endReward = 0;
endTypeInt = (int)EndType.Running;
}
break;
}
envUICon.showResult(endTypeInt);
worldUICon.updateChart(targetTypeInt, endTypeInt);
return (endTypeInt, thisReward,endReward);
}
// caulculate sceneReward if close to target then get great reward
public float getDistanceReward(float nowDistance,int inarea)
{
if (firstRewardFlag)
{
(lastDistance, _) = blockCont.getAgentTargetDistanceAndInside(AgentObj.transform.position);
firstRewardFlag = false;
}
float thisSceneReward = 0f;
if (inarea != 0)
{
thisSceneReward = paramCon.inAreaReward;
}
else
{
thisSceneReward = paramCon.distanceReward * (lastDistance - nowDistance);
}
lastDistance = nowDistance;
return thisSceneReward;
}
// calculate kill reward base on killed enemy's position
public float killReward(Vector3 enemyPosition)
{
float thisKillReward = 0f;
if (targetTypeInt == (int)Targets.Attack)
{
// attack mode
(_, int isInArea) = blockCont.thisBlock.getDist_inArea(enemyPosition);
if (isInArea == 1)
{
// kill in area enemy
thisKillReward = paramCon.killTargetEnemyReward;
}
else
{
thisKillReward = paramCon.killReward;
}
}
else if (targetTypeInt == (int)Targets.Free)
{
// free mode hit
thisKillReward = paramCon.killTargetEnemyReward;
}
else
{
// goto & defence
thisKillReward = paramCon.killReward;
}
return thisKillReward;
}
// calculate hit reward base on killed enemy's position and now mode
public float hitEnemyReward(Vector3 enemyPosition)
{
float thisHitReward = 0f;
if (targetTypeInt == (int)Targets.Attack)
{
// attack mode
(_, int isInArea) = blockCont.thisBlock.getDist_inArea(enemyPosition);
if (isInArea == 1)
{
// hit in area enemy
thisHitReward = paramCon.hitTargetReward;
}
else
{
// hit not in area enemy
thisHitReward = paramCon.hitReward;
}
}
else if (targetTypeInt == (int)Targets.Free)
{
// free mode hit
thisHitReward = paramCon.hitTargetReward;
}
else
{
// goto & defence
thisHitReward = paramCon.hitReward;
}
return thisHitReward;
}
// get in area state
public int getInAreaState()
{
if(targetTypeInt == (int)Targets.Go)
{
return inArea;
}
else
{
return 0;
}
}
}