
Added graphics options and rendering quality level settings Added new movement patterns to the dumb enemy AI Added chance for Coward Enemies to drop a random Added method to correctly reset the game variables on death and win screens Updated the UI to work on different resolutions without breaking Moved Sprites into a sprites folder Fixed issue where score would overflow the int because the multiplier was too high Fixed issue where new lives gained from the score breakpoints were not being calculated correctly Fixed issue where clicking off a menu element then trying to control the menu with the controller did not correctly reselect a menu item Fixed issue where enemies colliding with the outer boundary too much would break the sfx and music (i assume from a buffering issue)
418 lines
14 KiB
C#
418 lines
14 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
public class DumbEnemyHoverMovement : HoverMovement
|
|
{
|
|
// 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 maxRNGThrust;
|
|
public float movementDecayRate;
|
|
private List<TimerHelper> _movementMoveTimers = new List<TimerHelper>();
|
|
public float patternChangeInterval;
|
|
private TimerHelper _movementPatternTimer;
|
|
|
|
private float _currentHoldHeight;
|
|
private float _heightChangeTick;
|
|
public float heightChangeInterval;
|
|
|
|
private int _currentPattern;
|
|
private int _nextThrustDir;
|
|
private int _nextTurnDir;
|
|
|
|
protected override void DoAwakeTasks()
|
|
{
|
|
base.DoAwakeTasks();
|
|
}
|
|
|
|
// Start is called before the first frame update
|
|
private 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<EnemyColliderManager>();
|
|
|
|
_residualThrust = 0.0f;
|
|
_residualThrustCurrentTime = 0.0f;
|
|
_currentJumpTime = 0.0f;
|
|
_isJumping = false;
|
|
|
|
_aiJump = false;
|
|
_aiHorz = 0.0f;
|
|
_aiVert = 0.0f;
|
|
|
|
_currentHoldHeight = GetCurrentHeight();
|
|
_heightChangeTick = 0.0f;
|
|
|
|
_movementPatternTimer = new TimerHelper(patternChangeInterval, false);
|
|
_movementPatternTimer.HasTicked(patternChangeInterval + 100.0f);
|
|
_currentPattern = Random.Range(0, 4);
|
|
|
|
BaseOnStart();
|
|
// Custom start stuff can go here
|
|
}
|
|
|
|
private void DoAIPhysics(float currentTimeStep)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculates some RNG movement for the attached Enemy.
|
|
/// </summary>
|
|
/// <param name="currentTimeStep">The time unit currently used, typically deltatime or deltafixed time depending on if its the fixed update or not.</param>
|
|
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);
|
|
|
|
// 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<PlayerHoverMovement>().GetCurrentHeight();
|
|
|
|
_aiVert = 1;
|
|
if (_movementPatternTimer.HasTicked(currentTimeStep))
|
|
{
|
|
_currentPattern = Random.Range(0, 4);
|
|
_movementMoveTimers.Clear();
|
|
|
|
switch (_currentPattern)
|
|
{
|
|
default:
|
|
case 0:
|
|
int dirRandom = Random.Range(0, 2);
|
|
if (dirRandom == 0)
|
|
{
|
|
_nextTurnDir = -1;
|
|
}
|
|
else
|
|
{
|
|
_nextTurnDir = 1;
|
|
}
|
|
_movementMoveTimers.Add(new TimerHelper(30.0f, false));
|
|
_movementMoveTimers.Add(new TimerHelper(3.0f, false));
|
|
break;
|
|
case 1:
|
|
_movementMoveTimers.Add(new TimerHelper(10.0f));
|
|
break;
|
|
case 2:
|
|
int zigRandom = Random.Range(0, 2);
|
|
if (zigRandom == 0)
|
|
{
|
|
_nextTurnDir = -1;
|
|
}
|
|
else
|
|
{
|
|
_nextTurnDir = 1;
|
|
}
|
|
_movementMoveTimers.Add(new TimerHelper(3.0f, false));
|
|
break;
|
|
case 3:
|
|
_movementMoveTimers.Add(new TimerHelper(15.0f, false));
|
|
break;
|
|
}
|
|
|
|
_movementPatternTimer.RestartTimer();
|
|
}
|
|
else
|
|
{
|
|
switch (_currentPattern)
|
|
{
|
|
default:
|
|
case 0:
|
|
_aiVert = 1.0f;
|
|
if (_movementMoveTimers[0].HasTicked(currentTimeStep))
|
|
{
|
|
if (_movementMoveTimers[1].HasTicked(currentTimeStep))
|
|
{
|
|
int dirRandom = Random.Range(0, 2);
|
|
if (dirRandom == 0)
|
|
{
|
|
_nextTurnDir = -1;
|
|
}
|
|
else
|
|
{
|
|
_nextTurnDir = 1;
|
|
}
|
|
|
|
_movementMoveTimers[0].RestartTimer();
|
|
_movementMoveTimers[1].RestartTimer();
|
|
}
|
|
else
|
|
{
|
|
_aiHorz = _nextTurnDir;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_aiHorz = 0.0f;
|
|
}
|
|
break;
|
|
case 1:
|
|
_aiVert = 1.0f;
|
|
if (_movementMoveTimers[0].HasTicked(currentTimeStep))
|
|
{
|
|
int dirTimesRan = _movementMoveTimers[0].TimesRun % 2;
|
|
if (dirTimesRan == 0)
|
|
{
|
|
_aiHorz = 1;
|
|
}
|
|
else
|
|
{
|
|
_aiHorz = -1;
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
_aiVert = 1.0f;
|
|
if (_movementMoveTimers[0].HasTicked(currentTimeStep))
|
|
{
|
|
_nextTurnDir *= -1;
|
|
|
|
_movementMoveTimers[0].RestartTimer();
|
|
}
|
|
else
|
|
{
|
|
_aiHorz = _nextTurnDir;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (_movementMoveTimers[0].HasTicked(currentTimeStep))
|
|
{
|
|
_nextThrustDir = Random.Range(0, 2);
|
|
_nextTurnDir = Random.Range(-1, 2);
|
|
|
|
_movementMoveTimers[0].RestartTimer();
|
|
}
|
|
else
|
|
{
|
|
_aiVert = _nextThrustDir;
|
|
_aiHorz = _nextTurnDir;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="currentTimeStep">The time unit currently used, typically deltatime or deltafixed time depending on if its the fixed update or not.</param>
|
|
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.0f * _aiVert;
|
|
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.0f * _aiVert;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_residualThrust > 0.0f)
|
|
{
|
|
if (_residualThrustCurrentTime >= residualThrustTimeTickMax)
|
|
{
|
|
_residualThrust -= residualThrustIdleDecayRate;
|
|
}
|
|
_thrustDirection = _residualThrust / residualThrustMax;
|
|
}
|
|
else
|
|
{
|
|
_thrusting = false;
|
|
_thrustDirection = 0.0f;
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Method for dealing with the jump physics, this should be in the fixed update since it uses rigidbody physics
|
|
/// </summary>
|
|
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 (_heightChangeTick >= heightChangeInterval)
|
|
{
|
|
_currentHoldHeight = Random.Range(startHeight, startHeight + 5.0f);
|
|
_heightChangeTick = 0.0f;
|
|
}
|
|
else
|
|
{
|
|
_heightChangeTick += currentTimeStep;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|