using System.Collections.Generic; using UnityEngine; public class CowardEnemyHoverMovement : CommanderHoverMovement { public GameObject minePrefab; public int mineSpawnChance; public float mineSpawnCooldown; private TimerHelper _mineSpawnTick; private bool _canSpawnMine; public float mineDropTime; public float mineDropCooldown; private TimerHelper _mineDropTimer; private TimerHelper _mineDropCooldownTimer; private TimerHelper _canMineDropRoll; private bool _mineDropReady; private bool _mineDropping; // Game object to track the player GO private GameObject _player; private GameObject _blackHole; private EnemyColliderManager _enemyColliderManager; // Residual Thrust variables to handle the "glide" after the gameObject has moved public float residualThrustStep; public float residualThrustMax; public float residualThrustTimeTickMax; public float residualThrustDecayRate; public float residualThrustIdleDecayRate; public float jumpForce; public float jumpMaxTime; private float _residualThrust; private float _residualThrustCurrentTime; private float _currentJumpTime; private bool _isJumping; // Variables for RNG movement private float _aiVert; private float _aiHorz; private bool _aiJump; public float cowerDistance; public float emergencyBoostSpeed; public float emergencyBoostCooldownSpeed; public float emergencyBoostTime; public float emergencyBoostCooldown; private bool _emergencyBoosting; private bool _emergencyBoosted; private TimerHelper _currentEmergencyBoostingTick; private TimerHelper _currentEmergencyBoosterCooldownTick; private float _currentHoldHeight; private TimerHelper _heightChangeTick; public float heightChangeInterval; protected override void DoAwakeTasks() { base.DoAwakeTasks(); } // Start is called before the first frame update void Start() { // We have to find the player since setting it in the editor doesnt work correctly _player = GameObject.Find("Player"); _blackHole = GameObject.Find("BlackHole"); _enemyColliderManager = gameObject.GetComponent(); _residualThrust = 0.0f; _residualThrustCurrentTime = 0.0f; _currentJumpTime = 0.0f; _isJumping = false; _aiJump = false; _aiHorz = 0.0f; _aiVert = 0.0f; _emergencyBoosting = false; _emergencyBoosted = false; _currentHoldHeight = GetCurrentHeight(); _currentEmergencyBoostingTick = new TimerHelper(emergencyBoostTime, false); _currentEmergencyBoosterCooldownTick = new TimerHelper(emergencyBoostCooldown, false); _heightChangeTick = new TimerHelper(heightChangeInterval, false); _mineSpawnTick = new TimerHelper(mineSpawnCooldown, false); _mineDropReady = false; _mineDropping = false; _mineDropTimer = new TimerHelper(mineDropTime, false); _mineDropCooldownTimer = new TimerHelper(mineDropCooldown, false); _canPartyTypes = new List(); _canPartyTypes.Add(EnemyTypeName.ENEMYDUMB); _enemyParty = new List(); BaseOnStart(); // Custom start stuff can go here } private void DoAIPhysics(float currentTimeStep) { } /// /// Calculates some RNG movement for the attached Enemy. /// /// The time unit currently used, typically deltatime or deltafixed time depending on if its the fixed update or not. private void DoAI(float currentTimeStep) { if (_enemyColliderManager.Magnetized) { _noMovement = true; } else { _noMovement = false; } // Get the Up vector of each gameObject so we can compare its X values rather than the Y Vector3 playerDirection = _player.transform.position - transform.position; Vector3 playerLocation = Vector3.ProjectOnPlane(_player.transform.position, Vector3.up); Vector3 myLocation = Vector3.ProjectOnPlane(transform.position, Vector3.forward); Vector3 direction = playerLocation - myLocation; float facingPlayer = Vector3.Dot(playerDirection.normalized, transform.forward); // Added a check to see if the difference is big enough to warrant a turn otherwise they just get stuck turning forever float playerHeight = _player.GetComponent().GetCurrentHeight(); _aiVert = 1; _aiHorz = 0.0f; if (playerDirection.magnitude <= cowerDistance) { if (!_emergencyBoosting && !_emergencyBoosted) { // Try to boost away _emergencyBoosting = true; _canSpawnMine = false; _mineSpawnTick.RestartTimer(); // Force a height change for fun _heightChangeTick.HasTicked(heightChangeInterval); } } if (!(facingPlayer < 0.5f && facingPlayer > -0.5f)) { _aiHorz = -direction.normalized.x; } if (_currentHoldHeight >= GetCurrentHeight()) { RaycastHit aboveCheck; Physics.SphereCast(transform.position, 3.0f, transform.up, out aboveCheck, 5.0f, LayerMask.GetMask("Player")); if (aboveCheck.rigidbody != null) { if ((GetCurrentHeight() < playerHeight)) { _objectRigidbody.velocity = Vector3.zero; _aiJump = false; } else { _aiJump = true; } } else { _aiJump = true; } } else { _aiJump = false; } if (minePrefab != null) { if (_canSpawnMine && _emergencyBoosting) { DoAMineSpawn(); } else { if (!_emergencyBoosted) { if (_mineDropReady) { int dropChance = Random.Range(0, 100); if (dropChance <= mineSpawnChance) { _mineDropping = true; } _mineDropReady = false; } else { if (_canSpawnMine && _mineDropping) { DoAMineSpawn(); } } } } } } private void DoAMineSpawn() { if (!freezeMovement) { GameObject newMine = Instantiate(minePrefab); MineHoverMovement mineMovement = newMine.GetComponent(); if (mineMovement) { mineMovement.startPositionVector = transform.position + (-transform.forward * 2.0f); mineMovement.startHeight = GetCurrentHeight() - 0.5f; } newMine.SetActive(true); _canSpawnMine = false; } } /// /// Processes the inputs needed to move the gameObject, the turn direction, thrust direction and any residual thrust calculations so that we dont just stop in place. /// Anything in this method can be removed, as long as the _turnDirection and _thrustDirection are set then the parent script with handle the orbit and positioning. /// /// The time unit currently used, typically deltatime or deltafixed time depending on if its the fixed update or not. protected override void ProcessPreMovement(float currentTimeStep) { // Check if movement has been frozen if (!freezeMovement) { // Get the Horz and Vert axis from the RNG (or whatever vars you want) float horzInput = _aiHorz; float vertInput = _aiVert; // Check horz direction value, pos = Right, neg = Left if (horzInput > 0) { _turnDirection = 1; } else if (horzInput < 0) { _turnDirection = -1; } else { _turnDirection = 0; } // Check if the vert is pushed forwards or back, pos = forward, neg = back if (vertInput > 0) { _thrusting = true; _thrustDirection = 1; if (_emergencyBoosting) { _thrustDirection *= emergencyBoostSpeed; } else if (_emergencyBoosted) { _thrustDirection *= emergencyBoostCooldownSpeed; } if (_residualThrust < residualThrustMax) { _residualThrust += residualThrustStep * currentTimeStep; } } // If the Enemy is holding backwards else if (vertInput < 0) { if (_residualThrust > 0.0f) { if (_residualThrustCurrentTime >= residualThrustTimeTickMax) { _residualThrust -= residualThrustDecayRate; } _thrustDirection = _residualThrust / residualThrustMax; } else { _thrusting = true; _thrustDirection = -1; } } else { if (_residualThrust > 0.0f) { if (_residualThrustCurrentTime >= residualThrustTimeTickMax) { _residualThrust -= residualThrustIdleDecayRate; } _thrustDirection = _residualThrust / residualThrustMax; } else { _thrusting = false; _thrustDirection = 0; } } // Clamp the residual thrust so we cant fall below 0 or greater than the max value set _residualThrust = Mathf.Clamp(_residualThrust, 0, residualThrustMax); if (_residualThrustCurrentTime >= residualThrustTimeTickMax) { _residualThrustCurrentTime = 0.0f; } else { _residualThrustCurrentTime += currentTimeStep; } // Check if the jump button if (_aiJump && !_isJumping) { _isJumping = true; } // Run any base class stuff base.ProcessPreMovement(currentTimeStep); } } /// /// Method for dealing with the jump physics, this should be in the fixed update since it uses rigidbody physics /// private void ProcessJump() { // If the enemy is jumping add the jump force if (_isJumping) { _objectRigidbody.AddRelativeForce(Vector3.up * jumpForce * Time.fixedDeltaTime, ForceMode.Impulse); if (_currentJumpTime >= jumpMaxTime) { _currentJumpTime = 0.0f; _isJumping = false; _aiJump = false; } else { _currentJumpTime += Time.fixedDeltaTime; } } } private void ProcessCooldowns(float currentTimeStep) { if (_emergencyBoosting) { if (_currentEmergencyBoostingTick.HasTicked(currentTimeStep)) { _emergencyBoosted = true; _emergencyBoosting = false; _currentEmergencyBoostingTick.RestartTimer(); } } if (_emergencyBoosted) { if (_currentEmergencyBoosterCooldownTick.HasTicked(currentTimeStep)) { _emergencyBoosted = false; _currentEmergencyBoosterCooldownTick.RestartTimer(); } } if (_heightChangeTick.HasTicked(currentTimeStep)) { _currentHoldHeight = Random.Range(startHeight - 2.0f, startHeight + 3.0f); _heightChangeTick.RestartTimer(); } if (!_canSpawnMine) { if (_mineSpawnTick.HasTicked(currentTimeStep)) { _mineSpawnTick.RestartTimer(); _canSpawnMine = true; } } if (_mineDropping) { if (_mineDropTimer.HasTicked(currentTimeStep)) { _mineDropTimer.RestartTimer(); _mineDropping = false; } } if (!_mineDropReady && !_mineDropping) { if (_mineDropCooldownTimer.HasTicked(currentTimeStep)) { _mineDropCooldownTimer.RestartTimer(); _mineDropReady = true; } } } private void FixedUpdate() { if (!GameEngine.isPaused) { if (objectIsActive) { DoAIPhysics(Time.fixedDeltaTime); ProcessJump(); } } } // Update is called once per frame void Update() { if (!GameEngine.isPaused) { if (objectIsActive) { ProcessWorkingStartValues(Time.deltaTime); DoAI(Time.deltaTime); ProcessPreMovement(Time.deltaTime); ProcessCurrentMovement(Time.deltaTime); ProcessPostMovement(); ProcessCooldowns(Time.deltaTime); } } } }