I am using an interface on my objects to determine if they can be shot or not.
public class ChickenBehaviour : MonoBehaviour, IShooter
{ ...
void Update() { ...
IShooter shooter = hit.transform.gameObject.GetComponent(typeof(IShooter)) as IShooter;
...
This code compiles and works fine but gives a warning:
GetComponent requires that the requested component inherits from Component or MonoBehaviour.
You used GetComponent(IShooter) which does not inherit from Component.
IShooter is an interface, so yes it does not inherit from Component or MonoBehaviour.
Should I log this as sort of bug, or is there another intended way to implement interfaces on game objects.
No, Unity functions just expect to be dealing with Unity objects. Functions like GameObject.GetComponent and Object.FindObjectsOfType won’t work with interface types or classes that don’t inherit from Unity.Object or Unity.MonoBehaviour.
This doesn’t mean interfaces are useless. You can just check every Component yourself (instead of using the single GetComponent):
foreach (MonoBehaviour mono in GetComponents(typeof(MonoBehaviour)))
if (mono is IShooter)
{
IShooter shooter = (IShooter) mono;
// handle shooter
}
}
The actual implementation of GetComponent is probably more efficient than doing the type checking yourself, but as long as you’re not working in some performance critical loop, this code should do the job fine. Besides, in performance critical parts of your application, you would avoid using GetComponent anyway.
PS: if implementing IShooter means you can be shot, the name is rather confusing. Perhaps ICanBeShot would be better ;).
IShooter shooter = hit.transform.gameObject.GetComponent(typeof(IShooter)) as IShooter;
I get a warning and it works fine.
Looping to find an interface with getComponents() to avoid the warning seems like it would be slower. Thoughts about this? How would looping compare with GetComponent for performance.
If using getComponents should be avoided, what is the recommended way identify objects as belonging to different groupings. A chicken can be shot and can be dinner, each concept supporting an interface. In the C# world using interfaces is a nice design pattern way of doing it. What is Unity way of handling this if interfaces are discouraged?
Understood that it is not bug, but supporting interfaces for C# (and C++) can be an enhancement request.
I’m dealing with this now myself. So would a try-catch statement silence warnings? (ANSWER = no, since a Debug.LogWarning() is not an exception so it is caught.)
By the way, I heard casting is much faster than the as keyword. e.g.
The problem I have is that I need to get the interface-derived component based on the ‘other’ collider returned by an OnTriggerEnter event. I can’t see any way around this. Does anyone know an alternate pattern?
I’ve been unable to think of a way to get the object to report itself, or register to some sort of delegate but it always seems like a chicken-or-the-egg situation. All I get is a collider to work with.
I just ran the version that uses GetComponents in a loop that runs 1000 times each time an object enters the collider I mentioned, and it didn’t even show up on the profiler. Perhaps I am tired so I’ll run it again in the morning and verify the loop is actually running since that is hard to believe.
The single version caused the game to pause for a split second while the warnings were logged. Bummer. Why post warnings we can test for with a simple if == null??
EDIT: LOL… I just logged “i” (my counter in that loop, and it froze the game for about 3 seconds. It is definitely running the loop!
Rafes, do you specifically need an Interface?
If all iShooters are MonoBehaviours, can you not add one more layer of Inheritance?
i.e. instead of your Shooter classes inheritting from MonoBehaviour and the IShooter interface just make an abstract class inheritting from MonoBehaviour called Shooter, and have your different Shooter types inherit from that. That way you can call GetComponent<> on your Shooter class and get all derived types.
It’s a workaround, but since there is no way to define Constraints on Interfaces, it’s going to be clunky to try to build a system that can both guarantee it’s a MonoBehaviour and an IShooter otherwise.
I could, but it adds some complexity because it would have to go at the very top of a class tree where, in my particular case, I have a UnitBaseClass which all units in our game derive from, however, not all units need to have this interface, only a select group, perhaps even the most specific derived class (is there a term for this? the last child class…)
There is a larger issue for me to solve here though, which is different from the OP. I want to distribute this tool. It is a very advanced, highly optimized, target tracking system, and we really want people to be able to snap it on to their games without much splicing, if that makes sense? It will be hard enough walking new/uninterested developers through the process without this complexity. I can’t explain the whole situation, but I’ve got it quite modular, which is going to be nice. Anyway, I needed to have the user implement a couple properties which I need to reference in the plugin. A reference to the interface works great. I could re-roll the whole solution and provide a more complex SDK but make setup more simple, or I could go this route and do all the hard stuff internally as long as this interface is available on any GameObjects which want to be targeted, which is why I called it ITargetable. So far the whole thing is quite elegant, so unless this becomes an issue, I’m keeping it.
So far the way of doing it above is waaaay faster than I thought it would be. Perhaps it is because everything is cached before I run it and GetComponents is more performance friendly than we thought. The ‘is’ keyword should be a fast comparison as well I would think, so really, getting the components is the only part in question for performance. I’m not sure how much I should worry about this if I ran it 1000 times more often than a real game situation and it didn’t show up on the profiler.
I’m super excited about releasing this but I’m taking my time to be sure it will not only deliver what it promises but also provides a simple work-flow.
Just to follow-up. It occured to me that the way we can use components is a lot like interfaces and object inheritance. It is a pattern I haven’t really thought that deeply about until now, even though we all use them constantly. They ARE a pattern though.
I now use a component instead of an interface for my current needs. The user can slap on my component and we both have access to it.
Sorry for this necro, I found the thread via google. Rafe, don’t you compromise type safety though if you elect to use a component instead of an interface? I’m wrestling with a similar use case as yours and it seems like we would either compromise the contract implied via a hand rolled interface, or else the type safety if we opt in to using a component.
I read back through the thread and I honestly don’t recall all the details. I did end up using a component that exposes event delegates. It is simple and extremely flexible.
Double necro, sorry, haven’t been on in a while. I’ve since answered my own question via experimentation. My issue was I didn’t like how open using a type of “gameobject” was. In that you could link components that didn’t belong but it was a classic case of ovethinking it. I can still query for the interface and throw out if it doesn’t match, but thank you for the offer.