60FPS 101, Rule #1:
Never, ever, never use FindObjectsOfType
and FindGameObjectsWithTag
(tags is general) outside Awake or Start. Period.
How to replace them? Use arrays and System.Collection.Generic.List
lists instead.
Code below shows how you can do that and without physics being involved.
Player.cs
using System.Collections.Generic;
using UnityEngine;
[DisallowMultipleComponent]
public class Player : MonoBehaviour
{
public static List<Player> Instances = new List<Player>();
public float _reach = 3f;
public int wood = 0;
void OnEnable () => Player.Instances.Add( this );
void OnDisable () => Player.Instances.Remove( this );
void Update ()
{
if( Input.GetMouseButtonDown(0) )
{
if( this.FindNearest( Enemy.Visible , _reach , out Enemy enemy , out float enemyDist ) )
{
enemy.Hit();
}
else if( this.FindNearest( Destructible.Visible , _reach , out Destructible destructible , out float destructibleDist ) )
{
if( destructible.type==DestructibleType.Wood )
{
wood++;
Debug.Log($"You have {wood} wood");
}
destructible.Die();
}
}
}
#if UNITY_EDITOR
void OnDrawGizmosSelected ()
{
Gizmos.color = Color.cyan;
Gizmos.DrawWireSphere( transform.position , _reach );
}
#endif
}
Enemy.cs
using System.Collections.Generic;
using UnityEngine;
[DisallowMultipleComponent]
[RequireComponent( typeof(SkinnedMeshRenderer) )]
public class Enemy : MonoBehaviour
{
public static List<Enemy> Instances = new List<Enemy>();
public static List<Enemy> Visible = new List<Enemy>();
[SerializeField] float _life = 3f;
void OnEnable () => Enemy.Instances.Add( this );
void OnDisable () => Enemy.Instances.Remove( this );
void OnBecameVisible () => Enemy.Visible.Add( this );
void OnBecameInvisible () => Enemy.Visible.Remove( this );
public void Hit ()
{
Debug.Log($"{this.name} hit");
/* hit code */
if( _life>0f )
{
_life -= 1.6f;
if( _life<=0f ) Die();
}
}
public void Die ()
{
_life = 0f;
/* death code */
Debug.Log($"{this.name} died");
this.gameObject.SetActive( false );
}
}
Destructible.cs
using System.Collections.Generic;
using UnityEngine;
[DisallowMultipleComponent]
[RequireComponent( typeof(MeshFilter) )]
[RequireComponent( typeof(MeshRenderer) )]
public class Destructible : MonoBehaviour
{
public static List<Destructible> Visible = new List<Destructible>();
public DestructibleType type = DestructibleType.Undefined;
void OnBecameVisible () => Destructible.Visible.Add( this );
void OnBecameInvisible () => Destructible.Visible.Remove( this );
public void Die ()
{
/* death code */
Debug.Log($"{this.name} destroyed");
this.gameObject.SetActive( false );
}
}
public enum DestructibleType
{
Undefined = 0 ,
Wood = 1 ,
Stone = 2
}
ComponentExtentionMethods.cs
using System.Collections.Generic;
using UnityEngine;
public static class ComponentExtentionMethods
{
public static bool FindNearest <T,K>
(
this T me ,
List<K> others ,
float maxSearchDistance ,
out K nearest ,
out float nearestDist
)
where T : Component
where K : Component
{
Vector3 myPosition = me.transform.position;
float maxSearchDistanceSq = maxSearchDistance * maxSearchDistance;
float nearestDistSq = float.MaxValue;
bool hit = false;
nearest = null;
int len = others.Count;
for( int i=0 ; i<len ; i++ )
{
K next = others*;*
float nextDistSq = Vector3.SqrMagnitude( next.transform.position - myPosition );
// if( closer && below search threshold && not me )
if( nextDistSq<nearestDistSq && nextDistSq<maxSearchDistanceSq && nextDistSq>0f )
{
nearest = next;
nearestDistSq = nextDistSq;
hit = true;
}
}
nearestDist = hit ? Mathf.Sqrt(nearestDistSq) : float.MaxValue;
return hit;
}
public static bool FindNearest <T,K>
(
this T me ,
List others ,
float maxSearchDistance ,
out K nearest
)
where T : Component
where K : Component
{
return FindNearest( me:me , others:others , maxSearchDistance:maxSearchDistance , out nearest , out float nearestDist );
}
public static bool FindNearest <T,K>
(
this T me ,
K[] others ,
float maxSearchDistance ,
out K nearest ,
out float nearestDist
)
where T : Component
where K : Component
{
Vector3 myPosition = me.transform.position;
float maxSearchDistanceSq = maxSearchDistance * maxSearchDistance;
float nearestDistSq = float.MaxValue;
bool hit = false;
nearest = null;
int len = others.Length;
for( int i=0 ; i<len ; i++ )
{
K next = others*;*
float nextDistSq = Vector3.SqrMagnitude( next.transform.position - myPosition );
// if( closer && below search threshold && not me )
if( nextDistSq<nearestDistSq && nextDistSq<maxSearchDistanceSq && nextDistSq>0f )
{
nearest = next;
nearestDistSq = nextDistSq;
hit = true;
}
}
nearestDist = hit ? Mathf.Sqrt(nearestDistSq) : float.MaxValue;
return hit;
}
public static bool FindNearest <T,K>
(
this T me ,
K[] others ,
float maxSearchDistance ,
out K nearest
)
where T : Component
where K : Component
{
return FindNearest( me:me , others:others , maxSearchDistance:maxSearchDistance , out nearest , out float nearestDist );
}
}