public override void Execute() { ExecuteMethod.OnceInUpdate("SquadChildFSM.UpdateLandmineList", null, null); m_scFSM.Strafing(); // if: There is more landmine than the production child count if (SquadChildFSM.ListLandmine.Count >= SquadChildFSM.StateCount(SCState.Produce)) { for (int i = 0; i < SquadChildFSM.ListLandmine.Count; i++) { if (Vector3.Distance(SquadChildFSM.ListLandmine[i].transform.position, m_scFSM.transform.position) < 2f) { m_scFSM.Advance(SCState.Avoid); return; } } } // else if: There is lesser landmine state BUT not 0 else if (SquadChildFSM.ListLandmine.Count != 0) { for (int i = 0; i < SquadChildFSM.ListLandmine.Count; i++) { if (Vector3.Distance(SquadChildFSM.ListLandmine[i].transform.position, m_scFSM.transform.position) < 2f) { m_scFSM.Advance(SCState.Attack); return; } } } }
// Public Functions /// <summary> /// Spawns the squad captain /// </summary> /// <param name="_position"> The position in which the squad captain to spawn in </param> public bool Initialise(Vector3 _position) { transform.position = _position; this.Advance(PSState.Idle); SquadChildFSM.Spawn(_position); return(false); }
/// <summary> /// Advance _chance amount of alive cells to _nextsState /// </summary> /// <returns><c>true</c> There was transition happening <c>false</c> There wasn't any transition happening </returns> /// <param name="_nextState"> The state in which the squad child advances to </param> /// <param name="_chance"> The chance in which the squad child cell will advance </param> public static bool AdvanceSquadPercentage(SCState _nextState, float _chance) { // if: All the alive child is the _nextstate state if (SquadChildFSM.AliveCount() == SquadChildFSM.StateCount(_nextState)) { return(false); } // for: Checksthrough all the child in the array for (int i = 0; i < s_array_SquadChildFSM.Length; i++) { if (s_array_SquadChildFSM[i].EnumState != SCState.Dead) { // if: the current cell type is NOT the targeted cell type, as transition would be useless if (s_array_SquadChildFSM[i].EnumState != _nextState) { // if: The it is within the chance range if (UnityEngine.Random.value <= _chance) { s_array_SquadChildFSM[i].Advance(_nextState); } } } } return(true); }
/// <summary> /// Advance all squad in the state _currentState to _nextState by a certain amount of _chance /// </summary> /// <param name="_currentState"> the state of squad child which would be advancing </param> /// <param name="_nextState"> The state that the squad child cell will advance towards </param> /// <param name="_chance"> The chance of which the squad child cell will advance </param> public static bool AdvanceSquadPercentage(SCState _currentState, SCState _nextState, float _chance) { if (_currentState == _nextState) { return(false); } else if (SquadChildFSM.StateCount(_currentState) == 0) { return(false); } // for: Checks through all the child in the array for (int i = 0; i < s_array_SquadChildFSM.Length; i++) { // if: The current cell type is the trageted cell type if (s_array_SquadChildFSM[i].EnumState == _currentState) { // if: The it is within the chance range if (UnityEngine.Random.value <= _chance) { s_array_SquadChildFSM[i].Advance(_nextState); } } } return(true); }
public static void LoadScene(int _sceneId) { Application.LoadLevel(2); // Call All Reset Statics PlayerChildFSM.ResetStatics(); PlayerMain.ResetStatics(); player_control.ResetStatics(); GameManager.ResetStatics(); EndGamePanel.ResetStatics(); PlayerSquadFSM.ResetStatics(); SquadChildFSM.ResetStatics(); Wall.ResetStatics(); WallRenderer.ResetStatics(); Nutrients.ResetStatics(); ECPoolManager.ResetStatics(); ECIdleState.ResetStatics(); DirectionDatabase.ResetStatics(); FormationDatabase.ResetStatics(); PathQuery.ResetStatics(); PointDatabase.ResetStatics(); PositionQuery.ResetStatics(); ECTracker.ResetStatics(); EnemyMainFSM.ResetStatics(); Application.LoadLevel(_sceneId); }
// Co-Routines IEnumerator SpawnRoutine() { bIsProduce = true; this.CalculateCooldown(); while (bIsProduce) { yield return(new WaitForSeconds(fNextCooldown)); if (SquadChildFSM.StateCount(SCState.Produce) != 0) { if (!this.CalculateCooldown()) { bIsProduce = false; } else { SquadChildFSM.Spawn(transform.position); mAnimate.ExpandContract(0.5f, 1, 1.3f); } } else { bIsProduce = false; } } }
// Public Functions // Think(): The think process of the Squad Captain. Call this method to return the desire state that the SquadCaptain should be in public void Think() { // if: Restricts the brain from think too much if (fCurrentThinkCooldown >= fThinkCooldown) { fCurrentThinkCooldown = 0f; } else { fCurrentThinkCooldown += Time.deltaTime; return; } // Squad Child Cells Count Check // if: The number of alive squad child is less than fMininumChildCount <--------------------------------------------- DEPERATE TIMES if (PlayerSquadFSM.Instance.AliveChildCount() < nMinimumChildProducing) { SquadChildFSM.AdvanceSquadPercentage(SCState.Produce, 1f); m_PlayerSquadFSM.Advance(PSState.Produce); } // else if: There is more than enough child cells producing, moves to idle <----------------------------------------- RECOVERY else if (SquadChildFSM.StateCount(SCState.Produce) > nMaximumChildProducing) { SquadChildFSM.AdvanceSquadPercentage(SCState.Produce, SCState.Idle, 0.75f); } // if: There is child idling, assign them to defence <-------------------------------------------------------------- ASSIGN JOB if (SquadChildFSM.StateCount(SCState.Idle) > 0) { // if: Aggressive is triggered if (UnityEngine.Random.value > fAggressiveToDefensive) { SquadChildFSM.AdvanceSquadPercentage(SCState.Idle, SCState.Attack, 1f); } else if (SquadChildFSM.StateCount(SCState.Defend) < nMaximumChildDefence) { // nPredictedCount: The predicted number of defence cells it would have int nPredictedCount = (int)((float)SquadChildFSM.StateCount(SCState.Idle) * (1f - fAggressiveToDefensive)) + SquadChildFSM.StateCount(SCState.Defend); // if: The current predicted count is more that its requirement AND there is room to spawn more defence if (nPredictedCount > nMinimumIdleToDefence && SquadChildFSM.StateCount(SCState.Defend) < nMaximumChildDefence) { SquadChildFSM.AdvanceSquadPercentage(SCState.Idle, SCState.Defend, 1f - fAggressiveToDefensive); } } } // if: There is no child cells producing but it is still important to do it <-------------------------------------- ASSIGN JOB if (SquadChildFSM.StateCount(SCState.Produce) == 0 && SquadChildFSM.AliveCount() < nOptionalToProduceAt) { SquadChildFSM.AdvanceSquadPercentage(SCState.Produce, 0.2f); } // if: There is extra child in Idle and the player have relatively low amount of resource if (SquadChildFSM.StateCount(SCState.Idle) >= nAmountIdleBeforeConsider && player_control.Instance.s_nResources <= nNeedNutrients) { SquadChildFSM.AdvanceSquadPercentage(SCState.Idle, SCState.FindResource, 0.75f); } }
// GetNearestTargetPosition(): Assign a target to aggressive squad child cells. public static bool GetNearestTargetPosition() { // if: There are no attacking squad children if (SquadChildFSM.StateCount(SCState.Attack) == 0) { return(false); } s_list_enemyChild = EnemyMainFSM.Instance().ECList; // if: There is no enemy child cells to attack if (s_list_enemyChild.Count == 0) { for (int i = 0; i < s_array_SquadChildFSM.Length; i++) { if (s_array_SquadChildFSM[i].EnumState == SCState.Attack) { s_array_SquadChildFSM[i].Advance(SCState.Idle); } } return(false); } // for: Resets all the attackTarget of all squad children for (int i = 0; i < s_array_SquadChildFSM.Length; i++) { s_array_SquadChildFSM[i].attackTarget = null; } // for: Every enemy child in the list... for (int i = 0; i < s_list_enemyChild.Count; i++) { // for: Finds a squad children in the list... for (int j = 0; j < s_array_SquadChildFSM.Length; j++) { // if: The current squad children is attacking and it has no target if (s_array_SquadChildFSM[j].EnumState == SCState.Attack && s_array_SquadChildFSM[j].attackTarget == null) { s_array_SquadChildFSM[j].attackTarget = s_list_enemyChild[i]; } } } // for: This for loops returns all attacking squad children to idle when they have no target for (int i = 0; i < s_array_SquadChildFSM.Length; i++) { if (s_array_SquadChildFSM[i].EnumState == SCState.Attack && s_array_SquadChildFSM[i].attackTarget == null) { s_array_SquadChildFSM[i].Advance(SCState.Idle); } } return(true); }
// CheckDieable(): Since the health of the squad captain is determine by the number of squad child, it checks if the health reaches 0 public bool CheckDieable() { if (SquadChildFSM.AliveCount() == 0) { Advance(PSState.Dead); MainCamera.CameraShake(5, 0.7f); return(true); } else { return(false); } }
// CalculateDefenceSheildOffset(): Calling this method will recalculates all defence offsets for all defence cells public static bool CalculateDefenceSheildOffset() { // Resets all the strafing offset to 0 for (int i = 0; i < s_array_SquadChildFSM.Length; i++) { s_array_SquadChildFSM[i].fDefenceOffsetAngle = 0f; } // if: There is no squad cells in defence state if (StateCount(SCState.Defend) == 0) { return(false); } int defenceCount = SquadChildFSM.StateCount(SCState.Defend); // if: there is only 1 defence cell if (defenceCount == 1) { for (int i = 0; i < defenceCount; i++) { if (s_array_SquadChildFSM[i].EnumState == SCState.Defend) { s_array_SquadChildFSM[i].fDefenceOffsetAngle = 0.5f * fDefenceAngle; return(true); } } return(false); } else { // for: Calculates the distribution of the angle offset from the main vector int j = 0; for (int i = 0; i < s_array_SquadChildFSM.Length; i++) { if (s_array_SquadChildFSM[i].EnumState == SCState.Defend) { s_array_SquadChildFSM[i].fDefenceOffsetAngle = j / (defenceCount - 1f) * fDefenceAngle; j++; } // if: The loop have checked through all defence state cells, then it would break the loop if (j == defenceCount) { break; } } return(true); } }
// Update(): is called once every frame void Update() { // Pre-Execution if (SquadChildFSM.StateCount(SCState.Produce) > 0) { if (!bIsProduce) { StartCoroutine("SpawnRoutine"); } } // Execution m_CurrentState.Execute(); // Post-Execution }
// CalculateStrafingOffset(): Calling this method will recalculate all strafing offsets for all production cells public static bool CalculateStrafingOffset() { // Resets all the strafing offset to 0 for (int i = 0; i < s_array_SquadChildFSM.Length; i++) { s_array_SquadChildFSM[i].fStrafingOffsetAngle = 0f; } // if: There is no squad child cells in produce state if (StateCount(SCState.Produce) == 0) { return(false); } int produceCount = SquadChildFSM.StateCount(SCState.Produce); // for: Calculates strafing angle for squad child cells that are in production state // Calculation: Angles are split equally among each cells, which is also based on the number of production cells // 1 cell = 360 deg apart, 2 cells = 180 deg apart, 3 cells = 120 deg apart, 4 cells = 90 deg apart... int j = 0; for (int i = 0; i < s_array_SquadChildFSM.Length; i++) { if (s_array_SquadChildFSM[i].EnumState == SCState.Produce) { s_array_SquadChildFSM[i].fStrafingOffsetAngle = 360f / produceCount * j; j++; } // if: The loop have checked through all production state cells, then it would break the loop if (j == produceCount) { break; } } return(true); }
// DefenceSheild(): Handles the movement when the cells in defence state public bool DefenceSheild() { if (m_currentEnumState != SCState.Defend) { Debug.LogWarning(gameObject.name + ".SquadChildFSM.DefenceSheild(): Current state is not SCState.Defend! Ignore Defence!"); return(false); } // if: There is lesser defence child than it have if (SquadChildFSM.StateCount(SCState.Defend) < nDefenceMinimumCount) { SquadChildFSM.AdvanceSquadPercentage(SCState.Defend, SCState.Idle, 1f); } Vector3 toTargetPosition = Quaternion.Euler(0f, 0f, -fDefenceOffsetAngle) * mainDefenceVector + playerPosition - transform.position; if (toTargetPosition.magnitude > fDefenceRigidity) { m_RigidBody.AddForce(toTargetPosition * Time.deltaTime * fDefenceSpeed); } m_RigidBody.velocity = Vector3.ClampMagnitude(m_RigidBody.velocity, Mathf.Max(fDefenceRigidity, toTargetPosition.magnitude)); return(true); }
// Constructor public SC_IdleState(SquadChildFSM m_SquadChildFSM) { list_IdleChild = new List <SC_IdleState>(); m_scFSM = m_SquadChildFSM; }
public SC_AvoidState(SquadChildFSM para_SquadChildFSM) { m_scFSM = para_SquadChildFSM; }
// Constructor public SC_AttackState(SquadChildFSM m_SquadChildFSM) { m_scFSM = m_SquadChildFSM; }
public override void Enter() { Debug.Log(SquadChildFSM.CalculateDefenceSheildOffset()); }
// Constructor public SC_DefendState(SquadChildFSM m_SquadChildFSM) { m_scFSM = m_SquadChildFSM; }
public override void Execute() { targetNutrients = m_scFSM.GetNearestResource(); // if: The target nutrient is too close to the wall, disable the target if (targetNutrients != null) { if (Mathf.Abs(targetNutrients.transform.position.x) >= 4f) { targetNutrients = null; } } // Seperation Factor // vSeperationVector: The final vector used to space away from all the other nearby cells Vector3 vSeperationVector = Vector3.zero; Collider2D[] array_nearbyCollider = Physics2D.OverlapCircleAll(m_scFSM.transform.position, 0.5f, Constants.s_onlySquadChildLayer); if (array_nearbyCollider.Length > 0) { for (int i = 0; i < array_nearbyCollider.Length; i++) { // if: The current gameObject is itself if (array_nearbyCollider[i] == m_scFSM.gameObject) { continue; } // vDirectionVector: The vector that the current squad child should be travelling in to space away from the current neighbour Vector3 vDirectionVector = (m_scFSM.transform.position - array_nearbyCollider[i].transform.position); // if: Somehow this is triggered, which is very often... if (vDirectionVector.magnitude > 0) { vSeperationVector += vDirectionVector.normalized / vDirectionVector.sqrMagnitude; } } // Average the the final vector to use for spacing away vSeperationVector = vSeperationVector / array_nearbyCollider.Length; vSeperationVector = Vector3.ClampMagnitude(vSeperationVector, 7f); } // Attraction Factor ExecuteMethod.OnceInUpdate("SC_FindResourceState.RecalculateCenter", null, null); Vector3 vAttractionVector = vCenterPosition - m_scFSM.transform.position; vAttractionVector *= 10f; // Final Velocity Vector // toTargetVector: The vector between the target nutrients and the current squad child cells Vector3 toTargetVector; // if: There is no target nutrient, the find nutrients group will idle infront of squad group if (targetNutrients == null) { toTargetVector = PlayerSquadFSM.Instance.transform.position + new Vector3(0f, 2f, 0f) - m_scFSM.transform.position; } else { toTargetVector = targetNutrients.transform.position - m_scFSM.transform.position; } toTargetVector *= 10f; if (targetNutrients != null) { SquadChildFSM.Circle(targetNutrients.transform.position); } //Debug.Log("toTargetVector: " + toTargetVector.magnitude + ", vSeperationVector: " + vSeperationVector.magnitude + ", vAttractionVector: " + vAttractionVector.magnitude); // Apply vector to velocity /* Quick Vector Summary: * toTargetVector -> The vector between the nutrients and the 'FindResource' group * vSeperationVector -> The personal space vector * vAttractionVector -> The 'stay as a group' vector */ m_scFSM.RigidBody.AddForce(toTargetVector + vSeperationVector + vAttractionVector * Time.deltaTime * 100f, ForceMode2D.Force); m_scFSM.RigidBody.velocity = Vector3.ClampMagnitude(m_scFSM.RigidBody.velocity, 3f); // if: The distance between the two bodies is less than a certain distance if (targetNutrients != null) { if (Vector3.Distance(targetNutrients.transform.position, m_scFSM.transform.position) < 0.5f) { // if: The current squad child is added to the nutrients if (targetNutrients.AddSquadChildCount()) { m_scFSM.Advance(SCState.Dead); targetNutrients = null; } } } }
/// <summary> /// Returns the number of squad child cells that is alive /// </summary> /// <returns></returns> public int AliveChildCount() { return(SquadChildFSM.AliveCount()); }
// Constructor public SC_ProduceState(SquadChildFSM m_SquadChildFSM) { m_scFSM = m_SquadChildFSM; }
// Constructor public SC_IdleState(SquadChildFSM m_SquadChildFSM) { list_IdleChild = new List<SC_IdleState>(); m_scFSM = m_SquadChildFSM; }
// Constructor public SC_FindResourceState(SquadChildFSM m_SquadChildFSM) { m_scFSM = m_SquadChildFSM; }
// CalculateCooldown(): Call this function to re-calculate the cooldown of production public bool CalculateCooldown() { fNextCooldown = (fMaximumCooldown - fMinimumCooldown) * ((float)(nMaximumChildCount - SquadChildFSM.StateCount(SCState.Idle)) / (float)nMaximumChildCount) + fMinimumCooldown; if (fNextCooldown <= 0f) { Debug.LogWarning(this.name + ".CalculateCooldown: fNextCooldown is less than or equal to 0! fNextCooldown = " + fNextCooldown); fNextCooldown = 0.0f; return(false); } else { return(true); } }
private GameObject FindTargetChild() { //Find the node to obtain a target child by evaluating which node is the most threatening if (m_TargetSource == null) { GameObject Source = m_ecFSM.m_AttackTarget; if (Source == null) { return(null); } m_TargetSource = Source; } m_TargetEndPos = m_TargetSource.transform.position; //If the target to obtain a child cell to attack is any of the two nodes, loop through the cells within that specific node to get the closest child cell to the enemy child cell if (m_TargetSource.name.Contains("Node")) { List <PlayerChildFSM> m_PotentialTargets = new List <PlayerChildFSM>(); if (m_TargetSource.name.Contains("Left")) { for (int i = 0; i < PlayerChildFSM.childrenInLeftNode.Length - 1; i++) { if (PlayerChildFSM.childrenInLeftNode[i] == -1) { break; } m_PotentialTargets.Add(PlayerChildFSM.playerChildPool[PlayerChildFSM.childrenInLeftNode[i]]); } } else if (m_TargetSource.name.Contains("Right")) { for (int i = 0; i < PlayerChildFSM.childrenInRightNode.Length - 1; i++) { if (PlayerChildFSM.childrenInRightNode[i] == -1) { break; } m_PotentialTargets.Add(PlayerChildFSM.playerChildPool[PlayerChildFSM.childrenInRightNode[i]]); } } float fDistanceBetween = Mathf.Infinity; GameObject m_TargetCell = null; float ChildToPotentialTarget = 0f; PCState TargetCurrentState = PCState.Idle; for (int i = 0; i < m_PotentialTargets.Count; i++) { ChildToPotentialTarget = Utility.Distance(m_Child.transform.position, m_PotentialTargets[i].transform.position); TargetCurrentState = m_PotentialTargets[i].GetCurrentState(); if (CheckIfTargetIsAvailable(m_PotentialTargets[i].gameObject) && ChildToPotentialTarget < fDistanceBetween && TargetCurrentState != PCState.Dead && TargetCurrentState != PCState.Avoid) { fDistanceBetween = ChildToPotentialTarget; m_TargetCell = m_PotentialTargets[i].gameObject; break; } } if (m_TargetCell != null) { return(m_TargetCell); } } //Else If the target to obtain a child cell to attack is the squad captain cell, loop through the cells within that squad to get the closest child cell to the enemy child cell else if (m_TargetSource.name.Contains("Squad")) { List <SquadChildFSM> m_PotentialTargets = SquadChildFSM.GetAliveChildList(); if (m_PotentialTargets.Count <= 0) { return(null); } SquadChildFSM ClosestSquadChild = m_PotentialTargets[0]; float ChildToSquadChild = 0f; float ClosestDistance = Mathf.Infinity; for (int i = 0; i < m_PotentialTargets.Count; i++) { ChildToSquadChild = Utility.Distance(m_Child.transform.position, m_PotentialTargets[i].transform.position); if (ChildToSquadChild < ClosestDistance) { ClosestSquadChild = m_PotentialTargets[i]; ClosestDistance = ChildToSquadChild; } } m_ecFSM.Target = ClosestSquadChild.gameObject; return(m_ecFSM.Target); } //If there is no target for the child cell, transition it back to idle state return(null); }