using System.Collections; using System.Collections.Generic; using UnityEngine; public class KnightOnHorse : Ally { [SerializeField] private int _chargeAttackDamage; [SerializeField] private int _chargeCooldown; [SerializeField] private int _maxChargeHitCount; [SerializeField] private int _maxChargeDistance; [SerializeField] private float _fadeDistance; [SerializeField] private GameObject _detection; [SerializeField] private GameObject _chargeDetection; [SerializeField] private GameObject _root; // scripts private Root _rootScript; private Detection _detectionScript; // attack variables private int _originalAttackDamage; // movement variables private Vector3 _originalPos; private Vector2 _movementVector = Vector2.zero; // charge variables private bool _isCharging; private float _timeSinceLastCharge; private List _opponentsHit = new List(); // fading variables private float _fadeProgress; private bool _isFading; private int _fadeState; public override void Start() { base.Start(); _rootScript = _root.GetComponent(); _detectionScript = _detection.GetComponent(); // keep originals to go back to them eventually _originalAttackDamage = _chargeAttackDamage; _originalPos = transform.position; // makes sure the entity charges on creation _timeSinceLastCharge = _chargeCooldown + 1; } public override void Update() { // fade if charge done if (_isFading) { HandleFading(); return; } // check if charge is ready if (_timeSinceLastCharge > _chargeCooldown && !_isCharging) { SweepAttack(); _isCharging = true; Animation.ToggleChargeAnim(true); } if (_isCharging) { // sweep attack if an enemy slips behind the tip's hitbox SweepAttack(); // toggle charge detection _chargeDetection.SetActive(true); // movement HandleMovement(); // attack if (IsEnemyDetected && !_opponentsHit.Contains(Enemy)) { AttackEnemyRiding(); } // reset if (transform.position.x - _originalPos.x >= _maxChargeDistance || _opponentsHit.Count >= _maxChargeHitCount) { // charge state _isCharging = false; _timeSinceLastCharge = 0; _opponentsHit.Clear(); // detection state IsEnemyDetected = false; Enemy = null; _chargeDetection.SetActive(false); // start fading _isFading = true; } } else { // charge cooldown _timeSinceLastCharge += Time.deltaTime; // regular attack if (IsEnemyDetected) { AttackEnemy(); } } } private void HandleMovement() { _movementVector.x = Time.deltaTime * Speed; transform.position += (Vector3)_movementVector; } private void AttackEnemy() { //Attack Cooldown if (AttackSpeedWait > AttackInterval) { AttackDamage = _originalAttackDamage; Animation.PlayAttackAnim(); AttackSpeedWait = 0f; } AttackSpeedWait += Time.deltaTime; } private void AttackEnemyRiding() { AttackDamage = _chargeAttackDamage; // call root attack cause no specific animation _rootScript.Attack(); _opponentsHit.Add(Enemy); } /* * Attacks all enemies already in the default detection box during charge. * Charge uses a different detection (at the tip) due to Enemy being the first opponent to enter the hitbox. * Therefore enemies would only get hit when the previous Enemy exits the hitbox, which is at the handle instead of the tip. * To cover for the enemies behind the charge detection which is at the tip, we hit them all as the charge starts * and during in case something goes wrong and a monster slips through the charge hitbox. */ private void SweepAttack() { foreach (Entity entity in _detectionScript.DetectedEntities) { if (!_opponentsHit.Contains(entity)) { Enemy = entity; AttackEnemyRiding(); } } } private void HandleFading() { if (_fadeState == 0 && _fadeProgress < _fadeDistance) { HandleMovement(); //fade out _fadeProgress += _movementVector.x / _fadeDistance; foreach (SpriteRenderer spriteRenderer in SpriteRenderers) { spriteRenderer.color = new Color(1.0f, 1.0f, 1.0f, 1.0f - _fadeProgress); } } else if (_fadeState == 0 && _fadeProgress > _fadeDistance) { // teleport behind original position to fade in transform.position = new Vector3(_originalPos.x - _fadeDistance, _originalPos.y, _originalPos.z); _fadeState = 1; } else if (_fadeState == 1 && _fadeProgress < _fadeDistance * 2) { HandleMovement(); // fade in _fadeProgress += _movementVector.x / _fadeDistance; foreach (SpriteRenderer spriteRenderer in SpriteRenderers) { spriteRenderer.color = new Color(1.0f, 1.0f, 1.0f, _fadeProgress - _fadeDistance); } } else { // disable fading _isFading = false; _fadeProgress = 0; _fadeState = 0; foreach (SpriteRenderer spriteRenderer in SpriteRenderers) { spriteRenderer.color = new Color(1.0f, 1.0f, 1.0f, 1.0f); } // reset position _movementVector.x = 0; transform.position = _originalPos; // toggle detection _detection.SetActive(true); _chargeDetection.SetActive(false); // toggle animation Animation.ToggleChargeAnim(false); } } }