using MoreMountains.Feedbacks; using MoreMountains.Tools; using System.Collections; using System.Collections.Generic; 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 /// 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 List _targets; protected float _lastAttackStartedAt = -100f; protected Vector3 _initialPosition; protected Vector3 _initialLookAtTarget; protected Vector3 _lookAtTarget; protected BarbarianEnemy _enemy; /// /// On Awake we store our initial position /// protected virtual void Awake() { _initialPosition = this.transform.position; _initialLookAtTarget = this.transform.position + this.transform.forward * 10f; _lookAtTarget = _initialLookAtTarget; } /// /// On Update we look for input /// protected virtual void Update() { HandleInput(); LookAtTarget(); } /// /// Makes the character look at the target it's attacking /// protected virtual void LookAtTarget() { Vector3 direction = _lookAtTarget - _initialPosition; this.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(); Collider[] hitColliders = Physics.OverlapSphere(this.transform.position, 5f); foreach (var hitCollider in hitColliders) { Vector3 enemyPosition = hitCollider.transform.position; Vector3 direction = this.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() { float intervalDuration = AttackDuration / _targets.Count; // we play our initial attack feedback AttackFeedback?.PlayFeedbacks(); int enemyCounter = 0; foreach (Vector3 destination in _targets) { // for each new enemy, we play an attack feedback IndividualAttackFeedback?.PlayFeedbacks(); MMTween.MoveTransform(this, this.transform, this.transform.position, destination, null, 0f, intervalDuration, AttackCurve); _lookAtTarget = destination; yield return MMCoroutine.WaitFor(intervalDuration - enemyCounter * IntervalDecrement); enemyCounter++; } MMTween.MoveTransform(this, this.transform, this.transform.position, _initialPosition, null, 0f, intervalDuration, AttackCurve); _lookAtTarget = _initialLookAtTarget; } /// /// 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 int damage = Random.Range(50, 250); _enemy.TakeDamage(damage); } } } }