Reputation: 123
I currently have a player "sense ability" that would detect nearby enemies through Physics2D.OverlapCircleAll()
Enemies have a component that carries general properties about them:
using UnityEngine;
public class EnemyProperties : MonoBehaviour
{
public WorldColors color;
public bool hookable;
public bool isLast;
}
Now I want to filter those enemies in an array based on the attribute hookable == true
What I managed to do so far is to filter them based on the component:
public static void GetObjectsWithComponent(Transform srcTransform, float checkRadius, LayerMask checkLayers, Type myType)
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(srcTransform.position, checkRadius, checkLayers);
Collider2D[] collidersWithComponent = Array.FindAll(colliders, collider => collider.gameObject.TryGetComponent(myType, out Component component));
// Collider2D[] collidersWithComponentAttribute = ??
}
private void Update()
{
Sense.GetObjectsWithComponent(this.transform, checkRadius, checkMask, typeof(EnemyProperties));
}
how can I filter them further based on the bool hookable == true
?
Upvotes: 1
Views: 674
Reputation: 2173
You can use C# generics and Linq to make your life easier...
public static IEnumerable<TType> GetComponentsWithAttributeInCircle<TType>(Transform srcTransform, float checkRadius, LayerMask checkLayers, Func<TType, bool> filter)
{
Collider2D[] colliders = Physics2D.OverlapCircleAll(srcTransform.position, checkRadius, checkLayers);
IEnumerable<TType> colliderWithComponentAttribute = colliders.Select(collider => collider.gameObject.GetComponent<TType>()).Where(component => component != null).Where(filter);
return colliderWithComponentAttribute;
}
and in Update:
private void Update()
{
var hookableEnemies = Sense.GetComponentsWithAttributeInCircle<EnemyProperties>(this.transform, checkRadius, checkMask, (EnemyProperties => EnemyProperties.hookable));
foreach (var enemy in hookableEnemies)
{
...
}
}
As a remark to your additional comment, Linq is already pretty generic and general purpose. If you learn to use it, you can set up simple filters like this in no time. And it works well with compile time types. If you want to do the same thing without compile time knowledge of the types you will have to use reflection.
Reflection is usually slow, and not easy to follow, so if you can stick to Linq and generics, you will probably do a lot better.
Upvotes: 4
Reputation: 1059
The method FindAll
from the Array class is prototyped as follows :
public static T[] FindAll<T> (T[] array, Predicate<T> match);
So the second argument is actually a function, or lambda. The match
parameter needs to return a boolean. If it returns true
, it adds the element in the resulting array. If it returns false
, it doesn't.
So you can use the &&
operator in order to filter the component EnemyProperties
and the hookable == true
.
It would look something like this :
Collider2D[] collidersWithComponent = Array.FindAll(colliders, collider => (collider.gameObject.TryGetComponent(myType, out Component component) && collider.gameObject.GetComponent<EnemyProperties>().hookable == true));
Upvotes: 0