185 lines
5.0 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Detection : MonoBehaviour
{
[SerializeField]
private Entity _entityLinked;
private Vector2 detectionRange;
private BoxCollider2D _collider;
// List to store all detected objects trough triggerStay2D
private List<Entity> detectedEntities = new List<Entity>();
// If it's a projectile damage > 0
private int _projectileDamage = 0;
private bool _hasStartBeenCalled = false;
protected virtual void Start()
{
_collider = GetComponent<BoxCollider2D>();
detectionRange = _collider.size;
StartCoroutine(C_DetectCoroutine());
_hasStartBeenCalled = true;
}
/*
* Checks if Start ran once already.
* onEnable runs by default before Start so not everything is initialized
* and I don't want to reinitialize the collider everytime I re-enable a unit's detection.
*/
protected void OnEnable()
{
if (_hasStartBeenCalled)
{
StartCoroutine(C_DetectCoroutine());
}
}
// Looped detection every 'delay' amount
private IEnumerator C_DetectCoroutine()
{
// Can happen if unit dies
if (_entityLinked == null) yield break;
ResizeCollider();
// Remove objects that are null
detectedEntities.RemoveAll(obj => !obj);
Entity closest = GetClosest();
if (closest != null)
{
_entityLinked.IsEnemyDetected = true;
_entityLinked.Enemy = closest;
}
else
{
_entityLinked.IsEnemyDetected = false;
_entityLinked.Enemy = null;
}
yield return new WaitForSeconds(0.05f);
StartCoroutine(C_DetectCoroutine());
}
private void OnTriggerEnter2D(Collider2D other)
{
if (_entityLinked == null) return;
// Projectiles detection + deal dmg
Entity otherEntity = other.gameObject.GetComponent<Entity>();
if (otherEntity == _entityLinked)
{
_entityLinked.Hit(_projectileDamage);
// Kill if no hp
if (otherEntity.Hp <= 0)
{
otherEntity.Death();
}
_entityLinked = null;
}
}
private void OnTriggerStay2D(Collider2D other)
{
if (_entityLinked != null && _projectileDamage == 0)
{
GameObject detected = other.gameObject;
string tagToCheck =
(_entityLinked.gameObject.tag == "Ally") ? "Opponent" : "Ally";
if (detected.tag == tagToCheck)
{
Entity entity = other.GetComponent<Entity>();
if (!detectedEntities.Contains(entity))
{
detectedEntities.Add(entity);
}
}
}
}
private void OnTriggerExit2D(Collider2D other)
{
if (_entityLinked != null)
{
GameObject detected = other.gameObject;
string tagToCheck =
(_entityLinked.gameObject.tag == "Ally") ? "Opponent" : "Ally";
if (detected.tag == tagToCheck)
{
Entity entity = other.GetComponent<Entity>();
if (detectedEntities.Contains(entity))
{
detectedEntities.Remove(entity);
}
}
}
}
public Entity GetClosest()
{
Entity closest = null;
float closestDistance = Mathf.Infinity;
Vector3 currentPosition = transform.position;
foreach (Entity entity in detectedEntities)
{
if (entity == null) continue;
float distance = Vector3.Distance(currentPosition, entity.transform.position);
if (distance < closestDistance)
{
closestDistance = distance;
closest = entity;
}
}
return closest;
}
#region Resize
private void ResizeCollider()
{
if (!EntityLinked) return;
var multiplier = EntityLinked.RangeMultiplier;
var size = _collider.size;
size.x = detectionRange.x * multiplier.x;
size.y = detectionRange.y * multiplier.y;
_collider.size = size;
var offset = _collider.offset;
if (offset == Vector2.zero) return;
offset.x = Mathf.Sign(offset.x) * size.x / 2;
_collider.offset = offset;
}
#endregion
// Getter and Setter
public Entity EntityLinked
{
get { return _entityLinked; }
set { _entityLinked = value; }
}
public int ProjectileDamage
{
get { return _projectileDamage; }
set { _projectileDamage = value; }
}
public Rect DetectionRectangle
{
get
{
var coll = GetComponent<BoxCollider2D>();
var rect = new Rect(coll.offset, coll.size);
return rect;
}
}
public List<Entity> DetectedEntities { get { return detectedEntities; } }
}