LightSourceManager.cs


using System;
using UnityEngine;
using System.Collections;
using System.Linq;
using Random = UnityEngine.Random;

public class LightSourceManager : MonoBehaviour
{
    //Public variables 
    public GameObject[] LightSourcePrefabs;
    public float MinSpawnBoundMargin = 2f;
    public float MaxSpawnBoundMargin = 5f;
    public float LightSourceSpawnChance = 30f;
    public float LightSourceSpawnTime = 3f;
    public float LightSourceCapacityAdd { get; set; }

    public bool ShowSpawnQuadrants = false;

    //Private variables
    private enum QuadrantNames
    {
        TopLeft = 1,
        TopRight = 2,
        BottomLeft = 3,
        BottomRight = 4
    }
    private struct SpawnQuadrant
    {
        public QuadrantNames Name;
        public Rect BoundsA;
        public Rect BoundsB;
    }

    private GameObject _LightSourceClone;

    private Bounds _CameraBounds;
    private SpawnQuadrant _QuadrantTopLeft;
    private SpawnQuadrant _QuadrantTopRight;
    private SpawnQuadrant _QuadrantBottomLeft;
    private SpawnQuadrant _QuadrantBottomRight;

    private bool _SourceSpawnedIn;
    private float _SpawnTimer;

    private GameController _GameController;

    // Use this for initialization
    private void Start()
    {
        _SourceSpawnedIn = false;

        LightSourceCapacityAdd = 0f;
        _SpawnTimer = 0f;

        _CameraBounds = GlobalFunctions.GetOrtographicBounds(Camera.main);

        InitializeSpawnQuadrants();

        if (ShowSpawnQuadrants)
            DebugSpawnQuadrants();

        _GameController = GameController.Instance;
    }

    /// 
    /// Initialize all possible spawn quadrants
    /// 
    private void InitializeSpawnQuadrants()
    {
        //Separate each quadrant into smaller quadrants called A and B
        //Top left A is the top section above the screen.
        //Top left B is the right section next to the screen.
        //This goes on for all quadrants. Only the position chance for each section.
        _QuadrantTopLeft = new SpawnQuadrant()
        {
            Name = QuadrantNames.TopLeft,
            BoundsA = new Rect(_CameraBounds.center.x, _CameraBounds.center.y + _CameraBounds.max.y + MinSpawnBoundMargin,
                              _CameraBounds.min.x - MinSpawnBoundMargin, MaxSpawnBoundMargin - MinSpawnBoundMargin),
            BoundsB = new Rect(_CameraBounds.center.x - _CameraBounds.max.x - MaxSpawnBoundMargin, _CameraBounds.center.y,
                                MaxSpawnBoundMargin - MinSpawnBoundMargin, _CameraBounds.max.y + MaxSpawnBoundMargin)
        };
        _QuadrantTopRight = new SpawnQuadrant()
        {
            Name = QuadrantNames.TopRight,
            BoundsA = new Rect(_CameraBounds.center.x, _CameraBounds.center.y + _CameraBounds.max.y + MinSpawnBoundMargin,
                              _CameraBounds.max.x + MinSpawnBoundMargin, MaxSpawnBoundMargin - MinSpawnBoundMargin),
            BoundsB = new Rect(_CameraBounds.center.x + _CameraBounds.max.x + MinSpawnBoundMargin, _CameraBounds.center.y,
                                MaxSpawnBoundMargin - MinSpawnBoundMargin, _CameraBounds.max.y + MaxSpawnBoundMargin)
        };
        _QuadrantBottomLeft = new SpawnQuadrant()
        {
            Name = QuadrantNames.BottomLeft,
            BoundsA = new Rect(_CameraBounds.center.x, _CameraBounds.center.y - _CameraBounds.max.y - MinSpawnBoundMargin,
                              _CameraBounds.min.x - MinSpawnBoundMargin, MinSpawnBoundMargin - MaxSpawnBoundMargin),
            BoundsB = new Rect(_CameraBounds.center.x - _CameraBounds.max.x - MaxSpawnBoundMargin, _CameraBounds.center.y,
                              MaxSpawnBoundMargin - MinSpawnBoundMargin, _CameraBounds.min.y - MaxSpawnBoundMargin)
        };
        _QuadrantBottomRight = new SpawnQuadrant()
        {
            Name = QuadrantNames.BottomRight,
            BoundsA = new Rect(_CameraBounds.center.x, _CameraBounds.center.y - _CameraBounds.max.y - MinSpawnBoundMargin,
                              _CameraBounds.max.x + MinSpawnBoundMargin, MinSpawnBoundMargin - MaxSpawnBoundMargin),
            BoundsB = new Rect(_CameraBounds.center.x + _CameraBounds.max.x + MinSpawnBoundMargin, _CameraBounds.center.y,
            MaxSpawnBoundMargin - MinSpawnBoundMargin, _CameraBounds.min.y - MaxSpawnBoundMargin)
        };
    }

    /// 
    /// Call if you want to show the spawn quadrants
    /// 
    private void DebugSpawnQuadrants()
    {
        GameController.Instance.DebugRect(_QuadrantTopLeft.BoundsA);
        GameController.Instance.DebugRect(_QuadrantTopLeft.BoundsB);
        GameController.Instance.DebugRect(_QuadrantTopRight.BoundsA);
        GameController.Instance.DebugRect(_QuadrantTopRight.BoundsB);
        GameController.Instance.DebugRect(_QuadrantBottomLeft.BoundsA);
        GameController.Instance.DebugRect(_QuadrantBottomLeft.BoundsB);
        GameController.Instance.DebugRect(_QuadrantBottomRight.BoundsA);
        GameController.Instance.DebugRect(_QuadrantBottomRight.BoundsB);
    }

    // Update is called once per frame
    private void Update()
    {
        //DEBUG!!
        if (Input.GetKeyDown(KeyCode.K))
        {
            _LightSourceClone.GetComponent().DisableLight();
        }
    }

    /// 
    /// Move the light opposite of the direction the player goes.
    /// This is because the player stands still on 0,0 and only updates a vector and a facing direction.
    /// 
    /// The direction the player faces
    /// The speed the player moves
    /// Rotation in degrees of the player
    /// The position of the light in world space
    public Vector2 MoveLight(Vector3 moveDir, float moveSpeed, float angle)
    {
        if (_GameController.GamePaused)
            return Vector2.zero;

        if (_SourceSpawnedIn)
        {
            _LightSourceClone.GetComponent().Move(moveDir, moveSpeed);
            if (IsLightOutOfBounds(_LightSourceClone.transform.position))
                _LightSourceClone.GetComponent().DisableLight();
            return _LightSourceClone.transform.position;
        }
        else if (!_SourceSpawnedIn)
        {
            _SpawnTimer += Time.deltaTime;
            if (_SpawnTimer >= LightSourceSpawnTime)
            {
                if (Random.Range(0f, 100f) <= LightSourceSpawnChance)
                    Spawn(GetSpawnQuandrant(angle));
                _SpawnTimer = 0f;
            }
        }
        return Vector3.zero;
    }

    /// 
    /// Create a new light source.
    /// Only one can exist
    /// 
    /// 
    public void CreateLightSource(Vector3 createPos)
    {
        _LightSourceClone = Instantiate(GetRandomLightSource(), createPos, Quaternion.identity) as GameObject;
    }

    /// 
    /// Get a random lightsource from the prefab list.
    /// 
    /// Random lightsource
    public GameObject GetRandomLightSource()
    {
        //TODO Legacy code might work better with random spawning, still testing...
        //int size = LightSourcePrefabs.Length - 1;
        //if (index > size)
        //    index = 0;

        //float chance = LightSourcePrefabs[index].GetComponent().SpawnChance;
        //if (chance > 0 && Random.Range(0f, 100f) <= chance)
        //    return LightSourcePrefabs[index];

        //return GetRandomLightSource(++index);

        int size = LightSourcePrefabs.Length;
        int[] rolledDice = new int[size + 1];
        for (int i = 0; i < LightSourcePrefabs.Length; i++)
        {
            float chance = LightSourcePrefabs[i].GetComponent().SpawnChance;
            float rollDice = Random.Range(0f, 100f);

            //check if a legit dice has been rolled
            if (chance > 0 && rollDice <= chance)
                rolledDice[i + 1] = (int)rollDice;
        }
        int index = Array.IndexOf(rolledDice, rolledDice.Max());

        //Keep rolling the dice until a legit dice has been rolled
        if (index <= 0)
            return GetRandomLightSource();


        //Return the lightsource who has rolled the highest
        return LightSourcePrefabs[index - 1];
    }

    /// 
    /// Destroy the current lightsource
    /// 
    public void DestroyLightSource()
    {
        DestroyObject(_LightSourceClone);
        _SourceSpawnedIn = false;
    }

    /// 
    /// Get the current lightsource
    /// 
    /// Current lightsource
    public GameObject GetLightSource()
    {
        return _LightSourceClone;
    }

    /// 
    /// Spawn the lightsource in a quadrant
    /// 
    /// The quadrant that the player faces
    private void Spawn(SpawnQuadrant spawnQuadrant)
    {
        CreateLightSource(GetRandomSpawnPosition(spawnQuadrant));
        _SourceSpawnedIn = true;
    }

    /// 
    /// Get a random position for the lightsource between the two sections of a quadrant
    /// 
    /// The quadrant that the player faces
    /// 
    private Vector3 GetRandomSpawnPosition(SpawnQuadrant spawnQuadrant)
    {
        //Choose a random spawnpoint between bound A or B.
        Rect spawnPoint = (Random.Range(0, 100) <= 50 ? spawnQuadrant.BoundsA : spawnQuadrant.BoundsB);

        //Randomize spawnpoint in the bounds
        float randPosX = Random.Range(spawnPoint.x, spawnPoint.xMax);
        float randPosY = Random.Range(spawnPoint.y, spawnPoint.yMax);

        return new Vector3(randPosX, randPosY, -5f);
    }

    /// 
    /// Get a spawnquadrant facing towards the player
    /// 
    /// The angle from the player
    /// A spawnQuadrant
    private SpawnQuadrant GetSpawnQuandrant(float angle)
    {
        SpawnQuadrant spawnQuadrant = new SpawnQuadrant();

        if (angle >= 0f && angle <= 90f)
            spawnQuadrant = _QuadrantTopRight;
        else if (angle >= 90 && angle <= 180)
            spawnQuadrant = _QuadrantTopLeft;
        else if (angle >= 180 && angle <= 270)
            spawnQuadrant = _QuadrantBottomLeft;
        else if (angle >= 270 && angle <= 360)
            spawnQuadrant = _QuadrantBottomRight;

        return spawnQuadrant;
    }

    /// 
    /// Check if the light is out of the max bounds
    /// 
    /// Light source position
    /// 
    private bool IsLightOutOfBounds(Vector3 pos)
    {
        return (pos.x > (_CameraBounds.min.x + _CameraBounds.size.x) + MaxSpawnBoundMargin ||
            pos.x < _CameraBounds.min.x - MaxSpawnBoundMargin ||
            pos.y > (_CameraBounds.min.y + _CameraBounds.size.y) + MaxSpawnBoundMargin ||
            pos.y < _CameraBounds.min.y - MaxSpawnBoundMargin);
    }
}