Aimbot-ParallelEnv/Assets/Script/InGame/TargetController.cs
Koha9 9585845ba2 Side channel Added
add side channel to let python side know which target got win or lose.
fix update time bug. may cause double gameover check.(got another lose after reset the game.)
2022-11-30 06:39:56 +09:00

419 lines
17 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
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 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 float freeProb;
private float sceneSize;
private float lastDistance;
private Vector3 targetPosition;
private Vector3 targetLocalPosition;
private bool firstRewardFlag = true;
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 + 1f, maxEnemyAreaX - sceneSize - 1f);
float randZ = UnityEngine.Random.Range(minEnemyAreaZ + sceneSize + 1f, maxEnemyAreaZ - sceneSize - 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 + 1f, maxEnemyAreaX - sceneSize - 1f);
float randZ = UnityEngine.Random.Range(minEnemyAreaZ + sceneSize + 1f, maxEnemyAreaZ - sceneSize - 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 + 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 + 1f, maxEnemyAreaX - sceneSize - 1f);
float randZ = UnityEngine.Random.Range(minEnemyAreaZ + sceneSize + 1f, maxEnemyAreaZ - sceneSize - 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();
}
envUICon.updateTargetType(targetTypeInt);
}
// get target observation states
public float[] getTargetStates()
{
// targettype, x,y,z, firebasesAreaDiameter
List<float> targetState = new List<float>();
if (targetTypeInt == (int)Targets.Free)
{
targetState.AddRange(oneHotRarget[targetTypeInt]);
targetState.AddRange(new float[5] { 0f, 0f, 0f, 0f, 0f });
}
else
{
targetState.AddRange(oneHotRarget[targetTypeInt]);
targetState.AddRange(new float[5] { targetPosition.x, targetPosition.y, targetPosition.z, blockCont.thisBlock.firebasesAreaDiameter, blockCont.thisBlock.belongRatio });
}
return targetState.ToArray();
}
// 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;
}
// caulculate sceneReward if close to target then get great reward
public float getSceneReward(float nowDistance)
{
if (firstRewardFlag)
{
(lastDistance, _) = blockCont.getAgentTargetDistanceAndInside(AgentObj.transform.position);
firstRewardFlag = false;
}
float thisSceneReward = 0f;
thisSceneReward = paramCon.distanceReward * (lastDistance - nowDistance);
lastDistance = nowDistance;
return thisSceneReward;
}
// check over and get rewards
// 1 = success,2 = overtime,0 = notover
public (int, float) checkOverAndRewards()
{
int endTypeInt = 0;
float thisReward = 0;
int inArea = 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);
if (blockCont.thisBlock.firebasesBelong >= blockCont.thisBlock.belongMaxPoint)
{
// win
// let the area belongs to me
thisReward = paramCon.goWinReward;
//thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Win;
}
else if (leftTime <= 0)
{
// time out lose
thisReward = paramCon.loseReward;
//thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
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.firebasesBelong >= blockCont.thisBlock.belongMaxPoint && blockCont.thisBlock.getInAreaNumber(group2Tag) <= 0)
{
// win
// let the area belongs to me and kill every enmy in this area.
thisReward = paramCon.attackWinReward;
//thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Win;
}
else if (leftTime <= 0)
{
// time out lose
thisReward = paramCon.loseReward;
//thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Running;
}
break;
case (int)Targets.Defence:
//defence
(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) + getSceneReward(nowDistance);
endTypeInt = (int)EndType.Running;
}
break;
default:
//free kill
if (EnemyContainerObj.transform.childCount <= 0)
{
// win
//thisReward = paramCon.winReward + (paramCon.timeBonusPerSecReward * leftTime);
thisReward = paramCon.freeWinReward;
endTypeInt = (int)EndType.Win;
}
else if (Time.time - startTime >= paramCon.timeLimit)
{
// lose
//thisReward = paramCon.loseReward;
thisReward = paramCon.loseReward;
endTypeInt = (int)EndType.Lose;
}
else
{
// keep on keeping on!
endTypeInt = (int)EndType.Running;
}
break;
}
envUICon.showResult(endTypeInt);
worldUICon.updateChart(targetTypeInt, endTypeInt);
return (endTypeInt, thisReward);
}
// 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 kill
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 hitReward(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;
}
}