226 lines
6.3 KiB
C#
226 lines
6.3 KiB
C#
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<Entity> _opponentsHit = new List<Entity>();
|
|
|
|
// fading variables
|
|
private float _fadeProgress;
|
|
private bool _isFading;
|
|
private int _fadeState;
|
|
|
|
public override void Start()
|
|
{
|
|
base.Start();
|
|
|
|
_rootScript = _root.GetComponent<Root>();
|
|
_detectionScript = _detection.GetComponent<Detection>();
|
|
|
|
// 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);
|
|
}
|
|
}
|
|
} |