Hello, I’m a secondary school student, and I’m doing this game in Unity for a school project
I have some doubts, I can’t really get to understand how Unity works
I’m trying to make a class called Enemy, which would have all the stats of an Enemy, of course, and then, make enemies spawn from another script
I keep getting thiserror that says that MonoBehaviours can’t be instantiated with the keyword “new”
I would really like to have access to the constructors, it seems that I can’t if I my class is a MonoBehaviour ?
The code of my Enemy class is:
using UnityEngine;
using System.Collections;
public class Enemy : MonoBehaviour{
public int baseHp;
public int damage;
protected string type;
protected int totHp;
public int currHp;
protected int enemyId;
public GameObject zombie; //here goes the prefab
public Enemy(string type) {
this.type=type;
switch(this.type){
case "zombie":
GameObject enemyInstance = (GameObject) Instantiate(zombie, gameObject.transform.position, Quaternion.identity);
this.baseHp=150;
enemyInstance.SendMessage("setName", "hola");
this.damage=35;
this.totHp=calcHp(this.baseHp, round);
this.currHp=this.totHp;
break;
}
public int damageHp (int hit){
if (this.currHp>hit this.currHp-hit > 0){
this.currHp-=hit;
return this.currHp;
}
else{
Destroy(gameObject);
return 0;
}
}
And a bunch of code more
I would like to be able to just do
Enemy enemy1 = new Enemy("zombie");
enemy1.damageHp(20);
for example
I’m coding on C#, but I’ll understand if you answer in JS too
Somebody please explain to me what I’m doing wrong? I would like some theory please, not just “no no, you do it like this” and give me answers
You would do it in 2 scripts. The first script would have the instantiate logic in it. The second would have the data for each zombie.
First create an object that will instantiate the zombies and put a script like this on it:
using UnityEngine;
using System.Collections;
public class EnemyCreator : MonoBehaviour
{
public GameObject zombie;
void Start()
{
CreateEnemy("Hola", 150);
}
void CreateEnemy(string name, int hp)
{
GameObject enemy = Instantiate(zombie, gameObject.transform.position, Quaternion.identity) as GameObject;
enemy.SendMessage("SetName", name);
enemy.SendMessage("SetHP", hp);
}
}
You would then create an enemy prefab that is to be instantiated and it would be assigned to the above ‘zombie’ variable. This prefab would have an enemy component script that controls logic for the enemy.
using UnityEngine;
using System.Collections;
public class Enemy : MonoBehaviour
{
public string name;
public int hp;
public void SetName(string name)
{
this.name = name;
}
public void SetHP(int hp)
{
this.hp = hp;
}
public void ApplyDamage(int hit)
{
// your logic
}
}
GameObjects are containers that store Components. Components are what provide functionality to objects within your game. MonoBehaviours are a type of Component, and as such are created, destroyed, and otherwise managed entirely by Unity’s engine-level Component management.
Instead of creating them with “new” you create them by calling AddComponent(…) on the GameObject you wish to add them to. Instead of the constructor (which is reserved for use by the engine) you have access to the Awake() and Start() methods. Awake() is more or less what you should use instead of the constructor, with the main difference being that you can’t pass arguments into it.
Also, rather than the following…
Enemy enemy1 = new Enemy("zombie");
… you might want to create a static function CreateEnemy(…) which is a part of the Enemy class which takes in your arguments and creates an Enemy with appropriate specs. (One approach to this is instantiating a prefab and then setting some script variables, then returning a reference to either the GameObject or the Enemy script, for instance.)
Without static you would need a reference to an enemy to create an enemy. By putting everything in a static method, you can do do all the required pieces like positioning the enemy, initializing, etc. in that one method instead having the same 5 lines everywhere that you want to create an enemy.
Exactly. Static is usually something to be avoided like plague, but for things like this I personally think it’s quite suitable.
If you were doing something more complicated, or if it becomes more complicated, a “factory” class might be the way to go. But don’t add complexity until you need it.
Actually, using static in these situations is a great decision. It is actually supported by “design theory” :). Seriously speaking, you can actually use either of 2 most common “design patterns” here - factory class or factory method (createEnemy() is a factory method). Both work great.
Indeed. The reason I say that it’s usually to be avoided like plague is that many, many newbie programmers run afoul with it by using it without understanding what it actually does. If anyone’s able to articulate why it doesn’t necessarily need to be avoided then they probably understand it enough to use it effectively.