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 HUDObj; 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 EndType { Win, Lose, Running, Num }; [System.NonSerialized] public int targetNum = 0; private Dictionary oneHotRarget = new Dictionary(); 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; private HUDController hudCon; private RaySensors raySensors; private StartSeneData startSceneData; // start scene datas 0=train 1=play private int gamemode; // 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(); envUICon = EnvironmentUIObj.GetComponent(); enemyCont = EnemyContainerObj.GetComponent(); agentCharaCon = AgentObj.GetComponent(); paramCon = ParameterContainerObj.GetComponent(); worldUICon = WorldUIObj.GetComponent(); hudCon = HUDObj.GetComponent(); raySensors = AgentObj.GetComponent(); freeProb = 1 - attackProb - gotoProb - defenceProb; targetNum = (int)SceneBlockContainer.Targets.Num; if (freeProb < 0) { Debug.LogError("target percentage wrong"); } // initialize startSceneData & datas // while GameObject StartSceneDataTransfer is exist try { startSceneData = GameObject.Find("StartSceneDataTransfer").GetComponent(); gamemode = startSceneData.gamemode; } // while GameObject StartSceneDataTransfer is not exist catch { Debug.LogError("Run WithOut StartScreen"); gamemode = 1; } // 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 = paramCon.timeLimit; // print out time Debug.Log("Playing Time: " + leftTime); } else { 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)SceneBlockContainer.Targets.Go; int randBlockType = Random.Range(0, blockCont.goBlockPrefabs.Length); // get choosed scene size sceneSize = blockCont.goBlockPrefabs[randBlockType].GetComponent().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(SceneBlockContainer.Targets.Go, randBlockType, targetPosition, group1Tag, group2Tag); enemyCont.destroyAllEnemys(); enemyCont.randomInitEnemysExcept(hudCon.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)SceneBlockContainer.Targets.Attack; int randBlockType = Random.Range(0, blockCont.attackBlockPrefabs.Length); // get choosed scene size sceneSize = blockCont.attackBlockPrefabs[randBlockType].GetComponent().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(SceneBlockContainer.Targets.Attack, randBlockType, targetPosition, group1Tag, group2Tag); enemyCont.destroyAllEnemys(); enemyCont.randomInitEnemysExcept(hudCon.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)SceneBlockContainer.Targets.Defence; int randBlockType = Random.Range(0, blockCont.attackBlockPrefabs.Length); // get choosed scene size sceneSize = blockCont.defencePrefabs[randBlockType].GetComponent().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(SceneBlockContainer.Targets.Defence, randBlockType, targetPosition, group1Tag, group2Tag); enemyCont.destroyAllEnemys(); enemyCont.randomInitEnemysExcept(hudCon.enemyNum, targetPosition, sceneSize); blockCont.thisBlock.initBlock(EnvironmentObj); // set startDistance firstRewardFlag = true; } else { //Debug.Log("Free"); targetTypeInt = (int)SceneBlockContainer.Targets.Free; enemyCont.destroyAllEnemys(); enemyCont.randomInitEnemys(hudCon.enemyNum); moveAgentToSpwanArea(); blockCont.destroyBlock(); } updateTargetStates(); envUICon.updateTargetType(targetTypeInt); } // get target observation states public void updateTargetStates() { // targettype, x,y,z, firebasesAreaDiameter if (targetTypeInt == (int)SceneBlockContainer.Targets.Free) { targetState[0] = targetTypeInt; for(int i = 1; i < targetState.Length; i++) targetState[i] = 0f; } else { targetState[0] = targetTypeInt; /* targetState[1] = targetPosition.x / raySensors.viewDistance; // normalization targetState[2] = targetPosition.y / raySensors.viewDistance; targetState[3] = targetPosition.z / raySensors.viewDistance;*/ targetState[1] = targetPosition.x; // normalization targetState[2] = targetPosition.y; targetState[3] = targetPosition.z; targetState[4] = blockCont.thisBlock.firebasesAreaDiameter / raySensors.viewDistance; targetState[5] = blockCont.thisBlock.belongRatio; } } // move Agent into Agent Spawn Area public void moveAgentToSpwanArea() { float randX = UnityEngine.Random.Range(minAgentAreaX, maxAgentAreaX); ; float randZ = 0f; if (paramCon.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); } // 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)SceneBlockContainer.Targets.Go: // goto (nowDistance, inArea) = blockCont.getAgentTargetDistanceAndInside(AgentObj.transform.position); envUICon.updateTargetGauge(blockCont.thisBlock.firebasesBelong, blockCont.thisBlock.belongMaxPoint); float areaTargetReward = getDistanceReward(nowDistance, inArea); //if(inArea != 0) if (blockCont.thisBlock.firebasesBelong >= blockCont.thisBlock.belongMaxPoint) { // 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)SceneBlockContainer.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) { Debug.Log(blockCont.thisBlock.getInAreaNumber(group2Tag)); // 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; targetEnemySpawnFinish = false; } else if (leftTime <= 0 && targetEnemySpawnFinish) { // time out lose thisReward = 0; endReward = paramCon.loseReward; //thisReward = (paramCon.inAreaReward * inArea) + getSceneReward(nowDistance); endTypeInt = (int)EndType.Lose; targetEnemySpawnFinish = false; } else { // keep on keeping on! // thisReward = (paramCon.inAreaReward * inArea) + getDistanceReward(nowDistance); thisReward = 0; endReward = 0; targetEnemySpawnFinish = true; endTypeInt = (int)EndType.Running; } break; case (int)SceneBlockContainer.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; case (int)SceneBlockContainer.Targets.Stay: // Stay // endless thisReward = 0; endReward = 0; 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 (leftTime <= 0) { // 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) { // first distance record (lastDistance, _) = blockCont.getAgentTargetDistanceAndInside(AgentObj.transform.position); firstRewardFlag = false; } float thisSceneReward = 0f; if (inarea != 0) { // in area thisSceneReward = paramCon.inAreaReward; } else { // out of area // thisSceneReward = paramCon.distanceReward * Math.Clamp(lastDistance - nowDistance, 0, 100); 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)SceneBlockContainer.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)SceneBlockContainer.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)SceneBlockContainer.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)SceneBlockContainer.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)SceneBlockContainer.Targets.Go) { return inArea; } else { return 0; } } // Play Mode method // Initialize Play mode public void playInitialize() { targetTypeInt = (int)SceneBlockContainer.Targets.Stay; envUICon.updateTargetType(targetTypeInt); moveAgentToSpwanArea(); enemyCont.destroyAllEnemys(); blockCont.destroyBlock(); } // change to attack mode public void attackModeChange() { targetTypeInt = (int)SceneBlockContainer.Targets.Attack; envUICon.updateTargetType(targetTypeInt); } // change to free mode public void freeModeChange() { targetTypeInt = (int)SceneBlockContainer.Targets.Free; envUICon.updateTargetType(targetTypeInt); } // change to goto mode public void gotoModeChange() { targetTypeInt = (int)SceneBlockContainer.Targets.Go; envUICon.updateTargetType(targetTypeInt); } // change to stay mode public void stayModeChange() { targetTypeInt = (int)SceneBlockContainer.Targets.Stay; envUICon.updateTargetType(targetTypeInt); } }