- Home /
How to get a component from a prefab.
When creating an Enemy AI and then creating a prefab for it there seems to be a problem when I do damage to it. After I shoot at the prefab and kill it the other enemy seems to be invincible. I know where the problem is but don't know how to fix it. Here is some code from my bullet script which causes the problem.
void OnTriggerExit(Collider enemyTarget)
{
if (enemyTarget.gameObject.tag.Equals("Enemy") == true)
{
GameObject enemy = GameObject.Find("ToonSoldier_WW2_German_Infantry");
EnemyHealthScript enemyHealthScript = enemy.GetComponentInChildren<EnemyHealthScript>(true);
enemyHealthScript.enemyHealth -= damage;
Destroy(gameObject);
}
}
When you say the "other enemy seems to be invincible" which object are you talking about? This script appears to find one object named ToonSoldier_WW2_German_Infantry and decrement it's child objects health and then destroy the gameobject the script is attached to.
GameObject.Find looks in the entire scene for the first instance of an object with that name. If you have multiple enemies with that same name, there's no way to guarantee which one is being returned. It's very likely that the enemy that you're reducing the health of is not the same one that you're shooting at.
If the Collider is attached to the enemy, then you may be able to get the correct enemy health script by doing enemyTarget.gameObject.GetComponentInChildren<EnemyHealthScript>()
Alternatively, you may want to look at the documentation for Transform.Find. You would write enemyTarget.transform.Find("ToonSoldier_WW2_German_Infantry") to get the child gameobject of the enemy that you want.
Do not use "tags" they are slow because they have to be converted to C#, ins$$anonymous$$d use gameobject.name since I can guarantee all your enemies are named "Enemy"
Don't use GameObject.Find either, it looks through every gameobject in the scene and is INCREDIBLY slow. And you're also using it wrong, since once your Enemy collides with your trigger you're looking for it again AND doing it on every single trigger of this function.
Take a look at using a class system for your Enemy and Infantry, you're using some things that can easily be contained in their own objects, you don't want to rely this much on Unity scene functions.
I think tags are a lot more secure than names, names are nearly useless considering how easily they can be changed. I don't think the overhead for checking a tag is significant in any way at all. I pretty much consider names as "Editor-only organization helpers", even when I use a na$$anonymous$$g system I add my own Name field to a class.
When you instance a prefab yes the change but normally you should not be expecting to change your gameObjects names. Also .Equals() returns a boolean, so you don't need to check if its true, you're basically doing this:
if(True == True)
Either way if I was designing this I would do it like this, it's faster than any string or tag comparison:
Enemyhealth enemy = collider.gameObject.GetComponent<Enemyhealth >();
if (enemy != null)
{ }
People are right, and here's how I'd do it.
Should be gameObject, if that's the one from the scene, and don't forget to add (Clone) to the name since instances are called that way if you don't change the name manually.
"Find" is a great function, you just need to use it right: when instantiating, use smth like:
var allEnemies = GameObject.FindGameObjectsWithTag("Enemy");
var totalEnemiesSpawned: int;
function Spawn()
{
var newEnemy = Instantiate(bla bla bla);
totalEnemiesSpawned++;
newEnemy.name = "ToonSoldier_WW2_German_Infantry" + totalEnemiesSpawned;
}
function OnTriggerExit()
{
for(var thisEnemy in allEnemies)
{
//your code including thisEnemy variable...
}
}
That will give unique names for all instances of the enemy. And THAT's when you use find by name among those with tags.
I am new to unity and the general field of game design and code. I could tell that the flaw was that it was searching for all of the enemy with the same name and that the code was over complicated (which I had earlier simplified but did not update). I could tell the flaws but did not have the experience to figure out so thanks for helping and I will probably be asking a lot more questions in the future. By the way @jmgek what do you mean by hardest names.
Hard set hard coded names, values you have assigned in your code that is not generated or obtained through data and logic in your code:
string myString = "This String";
There can be many problems with this, mainly what happens if your Enemy tag or name gets changed, it's hard to track down the values like that. A better way is to have this.
public enum eTypesOfEntities{
Enemy,
Player,
Dogs,
};
Answer by HolgEntertain · May 25, 2017 at 02:54 PM
When you use GameObject enemy = GameObject.Find("ToonSoldier_WW2_German_Infantry"); I think you'll find the first gameobject of that type. I think you want to to GameObject enemy = enemyTarget.gameObject; Saves you a lookup and also should reduce the health of the correct enemy.
Also you should probably read some more about prefabs. You can't "shoot at the prefab" You're shooting at an instance created from a prefab. Just a friendly tip.
Answer by Zooow · May 25, 2017 at 04:21 PM
Not sure what's making your enemies invincible, but here's at least an issue i see with your code : GameObject.Find("ToonSoldier_WW2_German_Infantry"); will return the first object tag with "ToonSoldier_WW2_German_Infantry", not the one your bullet collide with.
I think you actually don't need to search for this object as you already have it with enemyTarget.gameObject
So you could write something like :
if(enemyTarget.gameObject.tag.Equals("Enemy"))
{
EnemyHealthScript = enemyTarget.gameObject.GetComponentInChildren<EnemyHealthScript>();
if(EnemyHealthScript != null)
{
enemyHealthScript.enemyHealth -= damage;
Destroy(gameObject);
}
}
Answer by Headzup · May 25, 2017 at 04:29 PM
Maybe you destroy the script from the other enemies then?
I don't know your comeplete code, but so far I understand it, you search for enemies and then destory them.
I would search the problem at line 7-9 and trying to work with this
Update: Do you have an enemy as a prefab from the beginning in the scene or do you spawn via. script all enemies?
Answer by Bill9009 · May 24, 2017 at 03:06 AM
When you use Component.GetComponentInChildren it only searches for the component in the first enemy.Component.GetComponentInChildren Unity Manual
Answer by oliver82957 · May 25, 2017 at 03:20 PM
I fixed the problem and I could update the script to this answer if wanted.
You should choose an answer and/or explain what went wrong and how you fixed it in case it helps someone else one day.
+1 This goes undone far too often, I'd have a much higher answer ratio if that wasn't the case lol.
Your answer