Reputation: 25
I'm creating a tower-defense game in Unity and I've encountered a problem.
I have class Unit, where my mobs have params like HP, damage, type, speed etc. and method Hit(int damage) (that damages unit). And I have a class for every type of unit: warrior, ranger, mage etc. that inherits Unit class
Tower begins to shoot, when mob enters its trigger area. Towers don't have bullets, missiles or anything else to shoot. The question is, how to call that Hit method from tower's script?
For every unit I have prefab with 2 scripts on it: Unit and, for example, Tank. I guess it's not right because thus I have 2 Unit classes: one just Unit and one inherited by, for example, Tank.
So this doesn't seems right:
if (obj.GetComponent<Unit>()) obj.GetComponent<Unit>().Hit(dmg);
Also I think it is not right to check this way:
if (obj.GetComponent<Tank>()) obj.GetComponent<Tank>().Hit(dmg);
else if (obj.GetComponent<Warrior>()) obj.GetComponent<Warrior>().Hit(dmg);
else ... etc.
So what's the right way of calling Hit?
Upvotes: 2
Views: 2508
Reputation: 11558
The following code will retrieve the Unit object, even if it is a inherited type.
if (obj.GetComponent<Unit>()) obj.GetComponent<Unit>().Hit(dmg);
However,
For every unit I have prefab with 2 scripts on it: Unit and, for example, Tank. I guess it's not right because thus I have 2 Unit classes: one just Unit and one inherited by, for example, Tank.
That doesn't sound right - You shouldn't have Unit and an inherited class of Unit on the same gameobject. I think you may need to revisit how you're doing things. There are quite a few ways to achieving what I think you're trying to achieve. Here is one I used recently:
Interfaces
This is my personal preferred method. You apply interfaces to each of your classes - Warrior, Mage, etc. One such interface could be IDamagable, which will define some properties such as Health, TakeDamage(int), etc.
If you haven't used interfaces before, I found this Unity3D specific video tutorial here.
I also use this fantastic extension method, which you can drop into Utilities class somewhere:
using System.Linq;
using UnityEngine;
public static class Utilities {
public static T GetInterface<T>(this GameObject inObj) where T : class {
if (!typeof (T).IsInterface) {
Debug.LogError(typeof (T).ToString() + ": is not an actual interface!");
return null;
}
return inObj.GetComponents<Component>().OfType<T>().FirstOrDefault();
}
public static IEnumerable<T> GetInterfaces<T>(this GameObject inObj) where T : class {
if (!typeof (T).IsInterface) {
Debug.LogError(typeof (T).ToString() + ": is not an actual interface!");
return Enumerable.Empty<T>();
}
return inObj.GetComponents<Component>().OfType<T>();
}
}
You can use this code like so:
var item = someGameObject.GetInterface<IItem>();
if (item != null) {
// Access a Property from IItem in here:
item.Drop();
}
Upvotes: 2