using System; using System.Collections; using System.Collections.Generic; using OMGeeky; using Unity.Mathematics; using UnityEngine; [RequireComponent( typeof(SpriteRenderer) )] public class Character : MonoBehaviour { #region Components private new CompositeCollider2D collider; private SpriteRenderer spriteRenderer; #endregion #region Inspector [SerializeField] public bool isActivePlayer; [SerializeField] private Sprite aliveSprite; [SerializeField] private Sprite deadSprite; [SerializeField] private float dissolveSpeed = 0.05f; [SerializeField] private Transform parentForNew; [SerializeField] private LayerMask findLayerMask; [SerializeField] private float eatRange = 2.5f; [SerializeField] private float attachRange = .5f; [SerializeField] public PauseMenuCaller PauseMenuCaller; #endregion #region Other public data public Checkpoint spawnPosition; public Character root; #endregion #region Events public event Action Killed; public event Action Spawned; #endregion public List spawnedObjects = new(); private static readonly int DissolveAmount = Shader.PropertyToID( "_DissolveAmount" ); private readonly Collider2D[] findColliders = new Collider2D[50]; private void Start() { // yield return new WaitForSeconds( 0.5f ); if ( root == null ) { root = this; SpawnNew(); } // if ( spawnPosition == null ) // spawnPosition = transform; } private void OnEnable() { collider = GetComponent(); spriteRenderer = GetComponent(); spriteRenderer.sprite = aliveSprite; if ( root != null ) { Spawned -= OnSpawned; Spawned += OnSpawned; } } private void OnSpawned( Character c ) { root.CallSpawned( c ); } private void CallSpawned( Character character ) { Spawned?.Invoke( character ); } private void Init( Character prefab ) { // inputToMovement.enabled = true; // characterController2D.enabled = true; root = prefab; isActivePlayer = true; Killed += character => root.spawnedObjects.Remove( character ); } public void KillSelf() { if ( math.distance( transform.position , spawnPosition.transform.position ) < 2 ) { Debug.Log( "Cant restart here, too near to spawn" ); return; } // characterController2D.enabled = false; // inputToMovement.enabled = false; isActivePlayer = false; SpawnNew(); spriteRenderer.sprite = deadSprite; // newPlayer.GetComponent().enabled = true; // newPlayer.GetComponent().enabled = true; } private void SpawnNew() { var newPlayer = Instantiate( root , root.spawnPosition.transform.position , Quaternion.identity , parentForNew ); newPlayer.Init( root ); root.spawnedObjects.Add( newPlayer ); Spawned?.Invoke( newPlayer ); } public void Eat() { var target = FindNearestSpawned( eatRange ); if ( target == null ) return; //TODO: buff player after eating // var size = target.transform.transform.localScale; // size.z = 0; // var localScale = transform.localScale; // var finalSize = MathHelpers.AddBoxAreaToBox( (Vector2) size , (Vector2) localScale ); // transform.localScale += size; // localScale = new Vector3( finalSize.x , finalSize.y , localScale.z ); // transform.localScale = localScale; target.DissolveSelf(); } public void DissolveSelf() { StartCoroutine( DissolveRoutine() ); } private Character FindNearestSpawned( float range ) { Character closest = null; float closestDistance = float.MaxValue; var t = transform; var localScale = t.localScale; Array.Clear( findColliders , 0 , findColliders.Length ); var bounds = collider.bounds; var size = new Vector2( bounds.size.x + range , bounds.size.y + range ); Physics2D.OverlapBoxNonAlloc( point: t.position , size: size , angle: 0 , results: findColliders , layerMask: findLayerMask ); foreach ( Collider2D coll in findColliders ) { if ( coll == null ) continue; if ( !coll.TryGetComponent( out Character character ) ) continue; if ( character == this ) continue; var distance = Physics2D.Distance( collider , coll ).distance; if ( distance >= closestDistance ) continue; closest = character; closestDistance = distance; } /* foreach ( Character spawnedObject in root.spawnedObjects ) { if ( spawnedObject == this ) continue; var distance = math.distance( spawnedObject.transform.position , transform.position ); if ( distance > range ) continue; if ( closest != null && distance < closestDistance ) continue; closest = spawnedObject; closestDistance = distance; } */ return closest; } private IEnumerator DissolveRoutine() { var mat = GetComponent().material; float value = 0; while ( value < 1 ) { value += dissolveSpeed; mat.SetFloat( DissolveAmount , value ); yield return null; } Killed?.Invoke( this ); Destroy( gameObject ); } public void Attach() { var target = FindNearestSpawned( attachRange ); if ( target == null ) return; target.transform.parent = transform; // var targetInput = target.GetComponent(); target.isActivePlayer = false; RemovePlayerComponentsFromTarget( target ); } private static void RemovePlayerComponentsFromTarget( Character target ) { var targetRb = target.GetComponent(); var targetCol = target.GetComponent(); // var targetController = target.GetComponent(); // var targetInput = target.GetComponent(); // Destroy( targetInput ); // Destroy( targetController ); Destroy( targetCol ); Destroy( targetRb ); } }