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; } } } }
// 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; } } }
/// <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 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); }
// 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); }
// 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); } }