First, an advice every person beginning in programming should know: avoid as much as you can string comparisons. This is a slow process that can turn into big performances issues and raise code complexity. Most of the time, they can be avoided easily.
Since I don’t know how you get your ‘hit’ object, it can be a Collision or a RaycastHit. If it is a Collision, it means you got it from OnCollisionEnter() and it’s mostly fine (for now) since the comparision is only tested when a collision happens on a single item. But be aware that collisions can happen pretty often in some situations. However, if it’s a RaycastHit you got from Physics.Raycast() it could have been inside an Update() loop (or any method called from within). Avoid that !
Since Update is called on every frame, this is a critical place where code should be optimized (according to the programer’s skill), and is the worst place to put a string comparison check.
This said, GetComponent() is a generic method. It means that ‘T’ (a type) can be of any type inside a constrained field, which for GetComponent is a MonoBehaviour (erroneously called “scripts”). It will return you a ‘T’ reference you can use and access all its public datas (fields, properties, methods). So, when you call for GetComponent(), you get back an ‘Enemy’ reference and can access all the variables you preceed with the “public” keyword within the class. In order to catch the reference, you need to assign it to a variable of the same type. Here is an example:
Enemy hitEnemy = hit.transform.GetComponent<Enemy>();
// 'hitEnemy' is our freshly acquired reference, now you can access any public data the regular way
// we suppose there is a public field 'life' in the Enemy class...
hitEnemy.life -= 1;
// ... and a public method 'Hit(int damages)'
hitEnemy.Hit(1);
When your ‘Hero’ and ‘Enemy’ classes are doing pretty much the same thing, you can use a more generic component, such as “Character” or “BattleCharacter” (these are example names) that will contain all the needed informations they can do.
In order to achieve that, you can use inheritance with components, which will let you store common informations for different derived classes.
Here is a simple example.
Character.cs
public class Character : MonoBehaviour
{
// every character have life and can move
public int life;
public int speed;
// every character can be Hit
public void Hit(int amount)
{
life -= amount;
if (life <= 0)
Die();
}
// every character can Die, yet it can't be called from outside the class
// note the use of 'virtual' wich let derived class override this method
private virtual void Die()
{
Destroy (gameObject);
}
}
Hero.cs
// note that we tell 'Hero' to derive from 'Character' (which derive from 'MonoBehaviour')
public class Hero : Character
{
// only the Hero can have experience and level
public int level;
public int experience;
// 'Hero', as any character can Die, but it will instead lead to a GameOver screen
// note the use of the 'override' keyword which will bypass the
// method 'Die' from base class 'Character' whenever it is called
private override void Die()
{
GameOver();
}
// 'Hero' only can level up
public void LevelUp()
{
level++;
experience = 0;
}
}
Enemy.cs
// as we've done for 'Hero', we derive 'Enemy' from 'Character'
public class Enemy : Character
{
// only 'Enemy' characters drop money & experience
public int givenGold;
public int givenExperience;
// as we did for 'Hero', we use the 'override' keyword, however,
// this time we will call the base method with 'base.Die();'
private override void Die()
{
// create a new GameObject at the current Enemy Transform's position
GameObject loot = new GameObject("loot", transform.position)
// just as GetComponent<T>(), AddComponent<T>() returns a 'T' reference
// note 'Loot' is not defined in this example, you'll have to do it yourself
Loot lootComponent = loot.AddComponent<Loot>();
// we suppose lootComponent have public field: gold and experience
lootComponent.gold = givenGold;
lootComponent.experience = givenExperience;
// will destroy the GameObject
base.Die();
}
}
You can attach ‘Hero’ or ‘Enemy’ to any GameObject in your scene (note that ‘Character’ can be attached to a GameObject too, but you mustn’t, not for this example please read footnote).
Now that you have distinct classes derived from the same base class, you can either detect collisions from within ‘Character’ or inside ‘Hero’ and ‘Enemy’. Thanks to polymorphism, you will be able to access any derived class from its base class. Of course, GetComponent() can be used to get back a base class.
Back to Character.cs
public class Character : MonoBehaviour
{
// [...] (previous code...)
void OnCollisionEnter (Collision collision)
{
// use of a more generic tag, so we don't care if it is a 'Hero' or 'Enemy'
if (hit.collider.tag == "Character")
{
Character characterComponent = collision.collider.transform.GetComponent<Character>();
// Hit() is accessible because it is defined within
// 'Character' and is marked with the 'public' keyword
characterComponent.Hit();
// however, Die() is not accessible since it is
// 'private' and 'Hero.LevelUp()' is not accessible
// because it is not defined in 'Character'
}
}
}
Last, you can get the derived class from a reference to the base class. But, you first need to check if the reference is of the derived type you want.
still inside Character.cs
public class Character : MonoBehaviour
{
// [...] (previous code...)
void OnCollisionEnter (Collision collision)
{
if (hit.collider.tag == "Character")
{
// [...] (previous code...)
IfHeroLevelUp(characterComponent);
}
}
public void IfHeroLevelUp(Character characterComponent)
{
// check if the instance is of derived class is as simple as
if (characterComponnent is Hero)
{
// but we still can't do 'characterComponent.LevelUp()'
// we need to 'cast' our reference this way
Hero heroComponent = (Hero) characterComponent;
// now, we can access 'LevelUp' method !
heroComponent.LevelUp();
}
}
}
Footnote: If there are multiple Component of the same base class on the same GameObject, GetComponent() (assuming we search for a Character component) will only return the first instance it finds (base or derived). In this case, you will need to use GetComponents() (note the ‘s’) which will then return an array of Character that you must loop through in order to get the desired component.
Hope this help !
Happy coding’