private void EnterState(eAIState newState) { m_currentState = newState; switch (newState) { case eAIState.ATTACK: m_theta = Mathf.Asin(-1 * m_vecToTarget.z); if (-1 * m_vecToTarget.x < 0) { m_theta = (Mathf.PI) - m_theta; } break; } }
public override void TakeDamage(float damageAmount, Ship attacker, Vector2 hitlocation) { base.TakeDamage(damageAmount, attacker, hitlocation); if (isAlive) { //todo //do a chance check and maybe check fearfulness (doesn't exist yet) //check current health as well if (Random.Range(0, 50) > 40) { aggressor = attacker; switch (stateAI) { case eAIState.Hunting: { //go into a strafing flee, dont just turn directly around //set the target location float coinToss = Random.Range(0, 2); if (coinToss >= 1) { targetLocation = new Vector2(transform.position.x, transform.position.y) + (forward.normalized * 5) + new Vector2(forward.y, -forward.x).normalized *Random.Range(2, 7); } else { targetLocation = new Vector2(transform.position.x, transform.position.y) + (forward.normalized * 5) + new Vector2(-forward.y, forward.x).normalized *Random.Range(2, 7); } fleeOffsetTime = 0; fleeOffsetMaxTime = Random.Range(6, 12); stateAI = eAIState.StrafingToFlee; } break; default: { stateAI = eAIState.Fleeing; RecalulateFleeOffset(); } break; } ; } } }
void Start() { firingTimerReset = firingTimer; acceleration = new Vector2(); myBody = gameObject.GetComponent <Rigidbody2D>(); GameObject playerManagerObject = GameObject.Find("PlayerManagerMain"); playerManager = playerManagerObject.GetComponent <PlayerManager>(); playerManager.ships.Add(this); stateAI = eAIState.Travelling; fleeOffset = new Vector2(); targetLocation = transform.position; new Vector2(transform.up.x, transform.up.y); shipId = playerManager.AssignShip(); base.LateStart(); }
public static IEnumerator EvaluateAI(Character mCharacter) { Debug.Log("Starte AI für " + mCharacter.pName + " Faction:" + mCharacter.pFaction + " Pat:" + mCharacter.pPatrouilleSelection); //mCharacter.pApCurrent = mCharacter.pAp; eAIState pAIState = eAIState.Patrouille; Character pActiveTarget = null; List <Tile> pSteps = new List <Tile>(); #region AI v2 while (mCharacter.pApCurrent > 9) { Debug.Log("AI current AP " + mCharacter.pApCurrent); yield return(new WaitForSeconds(0.5f)); // blocks debug stepping. Remove if nessesary switch (pAIState) { case eAIState.Patrouille: #region Patrouille pActiveTarget = AIfindTarget(mCharacter); if (pActiveTarget != null) { pAIState = eAIState.Fight; Debug.Log("AI switching from patrol to fight mode"); break; } if (mCharacter.pPatrouilleSelection == ePatrouilleSelection.Static) // wenn statischer gegner ohne wegpunkte, early exit { mCharacter.pApCurrent = 0; Debug.Log("AI Nothing to do, skipping turn"); break; } Tile patrolTile; if (mCharacter.pFaction == eFactions.AI1) { if (mCharacter.pPatrouilleSelection == ePatrouilleSelection.A) { patrolTile = GridManager.pInstance.GetTileAt(GridManager.pInstance.pCurrentLevel.pAI1PatrouilleA[mCharacter.mPatWaypointID]); } else { patrolTile = GridManager.pInstance.GetTileAt(GridManager.pInstance.pCurrentLevel.pAI1PatrouilleB[mCharacter.mPatWaypointID]); } } else { if (mCharacter.pPatrouilleSelection == ePatrouilleSelection.A) { patrolTile = GridManager.pInstance.GetTileAt(GridManager.pInstance.pCurrentLevel.pAI2PatrouilleA[mCharacter.mPatWaypointID]); } else { patrolTile = GridManager.pInstance.GetTileAt(GridManager.pInstance.pCurrentLevel.pAI2PatrouilleB[mCharacter.mPatWaypointID]); } } pSteps = GridManager.pInstance.GetPathTo(mCharacter.pTile, patrolTile); if (pSteps == null) { break; } int currentStepsLeft = mCharacter.pWalkRange; if (pSteps.Count < 3) //close enough to pat-point? { Debug.Log("AI patrol to next waypoint"); mCharacter.mPatWaypointID = (mCharacter.mPatWaypointID + 1) % (mCharacter.pPatrouilleSelection == ePatrouilleSelection.A ? GridManager.pInstance.pCurrentLevel.pAI1PatrouilleA.Length : GridManager.pInstance.pCurrentLevel.pAI1PatrouilleB.Length); if (mCharacter.pFaction == eFactions.AI1) { if (mCharacter.pPatrouilleSelection == ePatrouilleSelection.A) { patrolTile = GridManager.pInstance.GetTileAt(GridManager.pInstance.pCurrentLevel.pAI1PatrouilleA[mCharacter.mPatWaypointID]); } else { patrolTile = GridManager.pInstance.GetTileAt(GridManager.pInstance.pCurrentLevel.pAI1PatrouilleB[mCharacter.mPatWaypointID]); } } else { if (mCharacter.pPatrouilleSelection == ePatrouilleSelection.A) { patrolTile = GridManager.pInstance.GetTileAt(GridManager.pInstance.pCurrentLevel.pAI2PatrouilleA[mCharacter.mPatWaypointID]); } else { patrolTile = GridManager.pInstance.GetTileAt(GridManager.pInstance.pCurrentLevel.pAI2PatrouilleB[mCharacter.mPatWaypointID]); } } pSteps = GridManager.pInstance.GetPathTo(mCharacter.pTile, patrolTile); } if (pSteps.Count > mCharacter.pWalkRange) { yield return(mCharacter.MoveEnumerator(pSteps[pSteps.Count - mCharacter.pWalkRange])); } else { yield return(mCharacter.MoveEnumerator(pSteps[0])); } pActiveTarget = AIfindTarget(mCharacter); if (pActiveTarget != null) { pAIState = eAIState.Fight; } #endregion break; case eAIState.Fight: #region Fight Debug.Log(mCharacter.pName + " is searching for cover against " + pActiveTarget.pName); List <Tile> walkableTiles = GridManager.pInstance.GetReachableTiles(mCharacter.pTile, mCharacter.pWalkRange); //remove tiles with players on it for (int i = walkableTiles.Count - 1; i > 0; --i) { if (walkableTiles[i].pCharacterId != -1) { walkableTiles.Remove(walkableTiles[i]); } } eBlockType currentCoverTarget = eBlockType.Empty; //Creating lists with all options to choose from List <Tile> coverPositionsFull = new List <Tile>(); List <Tile> coverPositionsHalf = new List <Tile>(); foreach (Tile walkableTile in walkableTiles) { if (GridManager.pInstance.GetVisibilityToTarget(mCharacter.pTile, pActiveTarget.pTile, mCharacter.pVisionRange) == eVisibility.Seethrough && walkableTile.pCharacterId == -1) // now with occupied tiles { switch (GridManager.pInstance.GetCoverFromTarget(mCharacter.pTile, pActiveTarget.pTile)) { case eBlockType.Blocked: if (currentCoverTarget != eBlockType.HalfBlocked) { currentCoverTarget = eBlockType.Blocked; } coverPositionsFull.Add(walkableTile); break; case eBlockType.HalfBlocked: currentCoverTarget = eBlockType.HalfBlocked; coverPositionsHalf.Add(walkableTile); break; } } } // sort the choosen options by distance. Switch just for avoiding unnessesary sorting of tiles that are not suitable List <Tile> wayToTarget = new List <Tile>(); switch (currentCoverTarget) { case eBlockType.Empty: wayToTarget = GridManager.pInstance.GetPathTo(pActiveTarget.pTile, mCharacter.pTile); break; case eBlockType.Blocked: coverPositionsFull.Sort((a, b) => Tile.Distance(a, pActiveTarget.pTile).CompareTo(Tile.Distance(b, pActiveTarget.pTile))); wayToTarget = GridManager.pInstance.GetPathTo(mCharacter.pTile, coverPositionsFull[0]); break; case eBlockType.HalfBlocked: coverPositionsHalf.Sort((a, b) => Tile.Distance(a, pActiveTarget.pTile).CompareTo(Tile.Distance(b, pActiveTarget.pTile))); wayToTarget = GridManager.pInstance.GetPathTo(mCharacter.pTile, coverPositionsHalf[0]); break; default: break; } /* * // if we are going to get cover * if (currentCoverTarget != eBlockType.Empty && wayToTarget.Count <= mCharacter.pApCurrent / mCharacter.pWalkCost && wayToTarget.Count > 1) * { * Debug.Log("Move to cover because it seems reachable"); * for (int i = 0; i < (wayToTarget.Count > mCharacter.pWalkRange ? mCharacter.pWalkRange : wayToTarget.Count); ++i) // walk until range is spent or target reached * { * yield return AIevaluator.AImove(mCharacter, pSteps[1]); * } * mCharacter.pApCurrent -= 10; * break; * } */ // if we need to get in range and no cover is present if (currentCoverTarget == eBlockType.Empty && wayToTarget.Count > mCharacter.Range) { // weglist durchgehen und einen punkt wählen der dicht genug für schuss ist und nicht blockiert ist int possibleFinalWaypoint = 0; for (int wayPointCounter = wayToTarget.Count - 1; wayPointCounter > 0; --wayPointCounter) { if (wayToTarget[wayPointCounter].pCharacterId == -1 && wayToTarget.Count - wayPointCounter - 1 <= mCharacter.Range) { possibleFinalWaypoint = wayPointCounter; } else if (wayToTarget[wayPointCounter].pCharacterId == -1 && wayToTarget.Count - wayPointCounter - 1 > mCharacter.Range) { possibleFinalWaypoint = wayPointCounter; break; } } Debug.Log("Move to Enemy because out of range, possible " + wayToTarget.Count.ToString() + " steps"); yield return(mCharacter.MoveEnumerator(wayToTarget[mCharacter.pWalkRange])); break; } if (mCharacter.pApCurrent < 15) // not enough AP to shoot { Debug.Log("No shots left, skipping turn"); mCharacter.pApCurrent = 0; break; } Debug.Log("AI shooting Normal spell at " + pActiveTarget.pName); yield return(mCharacter.StandardAttackCoroutine(pActiveTarget.pTile)); // shoot normal spell at target pActiveTarget = AIfindTarget(mCharacter); //check for survivors if (pActiveTarget == null) { pAIState = eAIState.Patrouille; } #endregion break; default: Debug.LogError("AI in unknown state"); break; } }// loop if char has still points to use #endregion // end AI turn Debug.Log("AI spent all AP, end turn"); yield return(new WaitForSeconds(1)); mCharacter.pAura.SetActive(false); EntityManager.pInstance.EndRound(mCharacter); //ending AI turn and switch to next player GameManager.pInstance.pCurrentFaction = GameManager.pInstance.pCurrentFaction == eFactions.AI1 ? eFactions.Player1 : eFactions.Player2; //EntityManager.pInstance.pGetFactionEntities(pCurrentFraction)[0].Select(); // move camera to an faction entity GameManager.pInstance.ChangeState(eGameState.Select); }
void FixedUpdate() { if (!isAlive) { return; } CustomUpdate(); forward.x = transform.up.x; forward.y = transform.up.y; float deltaTime = Time.deltaTime; switch (stateAI) { case eAIState.Travelling: { // find a target if we dont have one if (target == null || !target.isAlive || target.teamId == teamId) { //todo better distance calculation once sections are completed int shipNum = playerManager.ships.Count; int foundNum = -1; float dist = 9999999; for (int i = 0; i < shipNum; i++) { Ship temp = playerManager.ships[i]; if (temp.shipId != shipId && temp.isAlive && temp.teamId != teamId && Vector2.Distance(temp.transform.position, transform.position) < dist) { dist = Vector2.Distance(temp.transform.position, transform.position); foundNum = i; } } if (foundNum >= 0) { target = playerManager.ships[foundNum]; stateAI = eAIState.Hunting; } } else { stateAI = eAIState.Hunting; } } break; case eAIState.Following: { if (target != null) { float distance = Vector2.Distance(targetLocation, transform.position); float angle = TurnTowards(deltaTime, targetLocation); if (angle < thrustAngle && distance > followDistance) { MoveForward(deltaTime, 3.3f, true); } else { thrustingTime = 0; myBody.angularDrag = 1.5f; if (distance > followDistance / 2) { MoveForward(deltaTime, 1.5f, false, 0.2f); } else if (animThrusting) { thrusterAnim.SetBool("IsStarting", false); thrusterAnim.SetBool("IsEnding", true); animThrusting = false; } } if (target.AIControlled) { AIShip theOtherShip = ((AIShip)target); if (!target.isAlive || theOtherShip.stateAI == eAIState.Travelling || theOtherShip.stateAI == eAIState.Fleeing) { stateAI = eAIState.Travelling; theOtherShip.followingShips.Remove(this); } } else { if (!target.isAlive) { stateAI = eAIState.Travelling; target.followingShips.Remove(this); } } } else { stateAI = eAIState.Travelling; } } break; case eAIState.Hunting: { if (target != null && target.isAlive) { if (firingTimer > 0) { firingTimer -= Time.deltaTime; if (firingTimer < 0) { firingTimer = 0; } } float distance = Vector2.Distance(target.transform.position, transform.position); float angle = TurnTowards(deltaTime, target.transform.position); if (angle < shootAngle && firingTimer == 0) { if (distance < fireDistance) { FireLaser(); } //chance check to see if this turns into a strafing run if (thrustingTime > 0 && Random.Range(0, 50) > 49) //if its moving at a good pace { float coinToss = Random.Range(0, 2); if (coinToss >= 1) { targetLocation = new Vector2(transform.position.x, transform.position.y) + (forward.normalized * 9) + new Vector2(forward.y, -forward.x).normalized *Random.Range(2, 4); } else { targetLocation = new Vector2(transform.position.x, transform.position.y) + (forward.normalized * 9) + new Vector2(-forward.y, forward.x).normalized *Random.Range(2, 4); } stateAI = eAIState.StrafingToAttack; } } if (angle < thrustAngle && distance > followDistance) { MoveForward(deltaTime, 3.3f, true); } else { thrustingTime = 0; myBody.angularDrag = 1.5f; if (distance > followDistance / 2) { MoveForward(deltaTime, 1.5f, false, 0.2f); } else if (animThrusting) { thrusterAnim.SetBool("IsStarting", false); thrusterAnim.SetBool("IsEnding", true); animThrusting = false; } } //check for any other ship that is following the same target if (followingShips.Count < 2) { int shipNum = playerManager.ships.Count; for (int i = 0; i < shipNum; i++) { if (playerManager.ships[i].AIControlled) { AIShip temp = (AIShip)playerManager.ships[i]; if (temp.shipId != this.shipId && temp.isAlive && temp.teamId == teamId && temp.stateAI == eAIState.Hunting && temp.target.shipId == this.target.shipId && temp.followingShips.Count < 2 ) { target = temp; FindFollowingPosition(); stateAI = eAIState.Following; break; } } } } } else { stateAI = eAIState.Travelling; } } break; case eAIState.Fleeing: { if (aggressor != null) { float distance = Vector2.Distance(aggressor.transform.position, transform.position); if (distance < fleeDistance) { Vector2 pos = new Vector2(transform.position.x, transform.position.y); var enemyPos = aggressor.transform.position; Vector2 targetDirection = pos - new Vector2(enemyPos.x, enemyPos.y); fleeOffsetTime += deltaTime; if (fleeOffsetTime > fleeOffsetMaxTime) { RecalulateFleeOffset(); } Vector2 targetPoint = (targetDirection.normalized * fleeDistance) + pos + fleeOffset; float angle = TurnTowards(deltaTime, targetPoint); if (angle < thrustAngle) { MoveForward(deltaTime, 3.3f, true); } else { thrustingTime = 0; myBody.angularDrag = 1.5f; MoveForward(deltaTime, 1.5f, false, 0.2f); } } else { stateAI = eAIState.Travelling; } } else { //todo //search for any nearby enemy units, if there is one, assign a new aggressor //if not break out of fleeing stateAI = eAIState.Travelling; } } break; case eAIState.StrafingToFlee: { TurnTowards(deltaTime, targetLocation); MoveForward(deltaTime, 3.3f, true); //test distance from target, if it is small enough, then go into fleeing fleeOffsetTime += deltaTime; float distance = Vector2.Distance(targetLocation, transform.position); if (distance < 0.2f || fleeOffsetTime > fleeOffsetMaxTime) { stateAI = eAIState.Fleeing; } } break; case eAIState.StrafingToAttack: { TurnTowards(deltaTime, targetLocation); MoveForward(deltaTime, 3.3f, true); //test distance from target, if it is small enough, then go into fleeing fleeOffsetTime += deltaTime; float distance = Vector2.Distance(targetLocation, transform.position); if (distance < 0.2f) { stateAI = eAIState.Hunting; } } break; } ; }