ScytheMovement.cs


using UnityEngine;
using System.Collections;

/// 
/// Author: Tim van den Bosch
/// 
public class ScytheMovement : MonoBehaviour
{
    #region Public variables

    public float MaxRotateDegrees = 90f;                //The maximum rotating degrees from left to right 
    public float StartSwingSpeed = 0.5f;                //The initial starting swing speed.
    public float PhaseSwingSpeedAdd = 0.1f;             //The swing speed add after each phase has ended.
    public bool StopSwinging = false;                   //Completly stop swinging if enabled.

    #endregion

    #region Public properties

    //Get the current swingingspeed not the starting
    public float SwingingSpeed
    {
        get { return _SwingingSpeed; }
        set { _SwingingSpeed = value; }
    }

    #endregion

    #region Private variables

    private float _SwingTimer;
    private float _SwingingSpeed;

    private bool _IsEnraging;
    private bool _StartingEnrage;
    private Quaternion _StartEnrageRotation;
    private Quaternion _EndEnrageRotation;

    private Quaternion _StartSwingRotation;
    private Quaternion _EndSwingRotation;

    private EnrageHandler _EnrageHandler;
    private float _EnrageWaitTimer;

    #endregion

    // Use this for initialization
    void Start()
    {
        ResetScytheToStartPosition();

        _SwingTimer = 0f;
        _EnrageWaitTimer = 0f;
        _SwingingSpeed = StartSwingSpeed;

        //Set the starting and ending position based on the maximum rotating degrees.
        _StartSwingRotation = Quaternion.AngleAxis(-MaxRotateDegrees, Vector3.forward);
        _EndSwingRotation = Quaternion.Inverse(_StartSwingRotation);

        _EnrageHandler = BossManager.Instance.GetEnrageHandler;
    }

    /// 
    /// Reset the scythe rotation to its starting position based on the max rotate.
    /// 
    public void ResetScytheToStartPosition()
    {
        transform.rotation = Quaternion.AngleAxis(MaxRotateDegrees, Vector3.forward);
    }

    // Update is called once per frame
    void Update()
    {
        if (GameController.Instance.GamePaused || StopSwinging)
            return;

        //Check if the boss is enraging, if so start the enrage sequence.
        if (!_IsEnraging)
            RotateScythe();
        else
            Enrange();
    }

    /// 
    /// Completely flip the rotation/speed. 
    /// So if swinging left it now swings to the right.
    /// 
    public void FlipRotation()
    {
        _SwingingSpeed *= -1;
    }

    /// 
    /// Get the current scythe rotation direction from left to right in vectors.
    /// 
    /// 
    public Vector3 GetScytheRotDirection()
    {
        return Quaternion.AngleAxis(transform.rotation.eulerAngles.z, Vector3.forward) * Vector3.right;
    }

    /// 
    /// Rotate the scythe from its starting position to its ending position.
    /// 
    private void RotateScythe()
    {
        _SwingTimer += Time.deltaTime * _SwingingSpeed;
        transform.rotation = Quaternion.Lerp(_StartSwingRotation, _EndSwingRotation, (Mathf.Sin(_SwingTimer + Mathf.PI / 2f) + 1f) / 2f);

        //Check if the scythe has reached it's end or start point if so flip the scythe.
        CheckForFlip();
    }

    /// 
    /// Check if the scythe needs to flip if he reached a certain rotation.
    /// 
    private void CheckForFlip()
    {
        Vector3 dir = GetScytheRotDirection();

        //Flip from left to right
        if (Mathf.Approximately(dir.y, -1))
            FlipScythe(dir.y);
        //Flip from right to left.
        else if (Mathf.Approximately(dir.y, 1))
            FlipScythe(dir.y);
    }

    /// 
    /// Flip the scythe object.
    /// 
    /// 
    private void FlipScythe(float dir)
    {
        Vector3 scale = transform.localScale;
        scale.x = dir;
        transform.localScale = scale;
    }

    /// 
    /// Begin the enrage sequence
    /// 
    /// The new swingspeed for the enrage sequence
    public void BeginEnrage(float newSwingSpeed)
    {
        _IsEnraging = true;
        _StartingEnrage = true;
        _SwingingSpeed = newSwingSpeed;

        //Check which side the scythe needs to be start swinging.
        float currentRot = transform.localRotation.eulerAngles.z;
        float rot = (currentRot < 360f && currentRot > 180f ? 360f - MaxRotateDegrees : 0f + MaxRotateDegrees);

        _StartEnrageRotation = Quaternion.Euler(0f, 0f, rot);
        _EndEnrageRotation = Quaternion.Inverse(_StartEnrageRotation);

        RotateToEnragePosition();
    }

    /// 
    /// Enrage the scythe rotation
    /// 
    private void Enrange()
    {
        //Rotate to the swing scythe position
        if (_StartingEnrage)
        {
            RotateToEnragePosition();

            if (transform.rotation == _StartEnrageRotation)
            {
                _EnrageWaitTimer += Time.deltaTime;
                if (_EnrageWaitTimer >= _EnrageHandler.EnrageWaitTime)
                {
                    _EnrageWaitTimer = 0;
                    _StartingEnrage = false;
                }
            }
        }
        else
        {
            //Swing the scythe
            float t = _SwingingSpeed * Time.deltaTime;
            transform.rotation = Quaternion.RotateTowards(transform.rotation, _EndEnrageRotation, t);

            CheckForFlip();

            //Check if the rotation has reached it's ending rotation if so set the boss to its normal state.
            if (transform.rotation == _EndEnrageRotation)
                BossManager.Instance.SetState(BossManager.BossStates.Normal);
        }
    }

    /// 
    /// Stop the enrage.
    /// 
    public void StopEnrage()
    {
        _SwingTimer = 0f;
        _SwingingSpeed = StartSwingSpeed;

        _StartSwingRotation = _StartEnrageRotation;
        _EndSwingRotation = Quaternion.Inverse(_StartSwingRotation);

        _IsEnraging = false;
    }

    /// 
    /// Rotate the scythe to its starting position for the enrage.
    /// 
    private void RotateToEnragePosition()
    {
        float t = 20f * Time.deltaTime;
        transform.rotation = Quaternion.RotateTowards(transform.rotation, _StartEnrageRotation, t);

        CheckForFlip();
    }
}