using System.Collections; using System.Collections.Generic; using MoreMountains.Feedbacks; using MoreMountains.Tools; using UnityEngine; namespace MoreMountains.Feel { /// /// A simple class controlling the hero character in the Barbarians demo scene /// It simulates a very simple character controller in an ARPG game /// [AddComponentMenu("")] public class Barbarian : MonoBehaviour { [Header("Cooldown")] /// a duration, in seconds, between two attacks, during which attacks are prevented [Tooltip("a duration, in seconds, between two attacks, during which attacks are prevented")] public float CooldownDuration = 0.1f; [Header("Feedbacks")] /// a feedback to call when the attack starts [Tooltip("a feedback to call when the attack starts")] public MMFeedbacks AttackFeedback; /// a feedback to call when each individual attack phase starts [Tooltip("a feedback to call when each individual attack phase starts")] public MMFeedbacks IndividualAttackFeedback; /// a feedback to call when trying to attack while in cooldown [Tooltip("a feedback to call when trying to attack while in cooldown")] public MMFeedbacks DeniedFeedback; [Header("Attack settings")] /// a curve on which to move the character when it attacks public MMTween.MMTweenCurve AttackCurve = MMTween.MMTweenCurve.EaseInOutOverhead; /// the duration of the attack in seconds public float AttackDuration = 2.5f; /// an offset at which to attack enemies public float AttackPositionOffset = 0.3f; /// a duration by which to reduce movement duration after every attack (making each attack faster than the previous one) public float IntervalDecrement = 0.1f; protected BarbarianEnemy _enemy; protected Vector3 _initialLookAtTarget; protected Vector3 _initialPosition; protected float _lastAttackStartedAt = -100f; protected Vector3 _lookAtTarget; protected List _targets; /// /// On Awake we store our initial position /// protected virtual void Awake() { _initialPosition = transform.position; _initialLookAtTarget = transform.position + transform.forward * 10f; _lookAtTarget = _initialLookAtTarget; } /// /// On Update we look for input /// protected virtual void Update() { HandleInput(); LookAtTarget(); } /// /// When we collide with an enemy, we apply damage to it /// /// protected virtual void OnTriggerEnter(Collider other) { _enemy = other.GetComponent(); if (_enemy != null) { // we randomize the damage done and apply it to the enemy var damage = Random.Range(50, 250); _enemy.TakeDamage(damage); } } /// /// Makes the character look at the target it's attacking /// protected virtual void LookAtTarget() { var direction = _lookAtTarget - _initialPosition; transform.LookAt(_lookAtTarget + direction * 5f); } /// /// Detects input /// protected virtual void HandleInput() { if (FeelDemosInputHelper.CheckMainActionInputPressedThisFrame()) Attack(); } /// /// Performs an attack if possible, otherwise plays a denied feedback /// protected virtual void Attack() { if (Time.time - _lastAttackStartedAt < CooldownDuration + AttackDuration) { DeniedFeedback?.PlayFeedbacks(); } else { AcquireTargets(); StartCoroutine(AttackCoroutine()); _lastAttackStartedAt = Time.time; } } /// /// Finds targets around the Barbarian and stores them /// protected virtual void AcquireTargets() { _targets = new List(); var hitColliders = Physics.OverlapSphere(transform.position, 5f); foreach (var hitCollider in hitColliders) { var enemyPosition = hitCollider.transform.position; var direction = transform.position - enemyPosition; if (hitCollider.GetComponent() != null) _targets.Add(enemyPosition + direction * AttackPositionOffset); } _targets.MMShuffle(); } /// /// A coroutine used to move to each stored target to attack them /// /// protected virtual IEnumerator AttackCoroutine() { var intervalDuration = AttackDuration / _targets.Count; // we play our initial attack feedback AttackFeedback?.PlayFeedbacks(); var enemyCounter = 0; foreach (var destination in _targets) { // for each new enemy, we play an attack feedback IndividualAttackFeedback?.PlayFeedbacks(); MMTween.MoveTransform(this, transform, transform.position, destination, null, 0f, intervalDuration, AttackCurve); _lookAtTarget = destination; yield return MMCoroutine.WaitFor(intervalDuration - enemyCounter * IntervalDecrement); enemyCounter++; } MMTween.MoveTransform(this, transform, transform.position, _initialPosition, null, 0f, intervalDuration, AttackCurve); _lookAtTarget = _initialLookAtTarget; } } }