- Home /
Implementation question: Classes instantiating prefabs, or multiple prefabs with classes?
Hello everyone.
This is more like a discussion on which would do better in terms of implementation rather than an actual question, but here it goes:
In my game (something like an RTS, to make things a little bit clearer), I want each unit in game to be an instance of the class named Unit, which contains things such as an inventory, and all the stats for that single unit, I'm working on that so I can store everything I need to make units work independently and be able to take simple orders by themselves (like move there, or, get that thing into your inventory).
Anyway, so I've come into two different ways of doing this and I don't know which would do better:
First I had thought of creating a prefab named Unit, with my Unit script attached on it, so that script would give my unit each property it needs (a 3d model, an HP value and so on...) But then I thought that if I wanted to do that through code, i could approach this in a different way which I think should work as well.
Let's say I create the unit class, and instead of attaching it to a gameObject in the scene, I create instances of that class through code. And then, those instances are able to Instantiate an animated 3d model in scene and are able to control it, so I have many instances of that class in memory controlling a 3d model in the actual game but not being "inside" that gameObject.
What's the best way to implement what I want? I don't fully understand how unity works at that level, so I'm not able to decide which one would do better, I see both ways to be viable and I also can find some pros and cons, for example:
If I use the first method, I can easily access each unit's Unit class, let's say, with a rayCast where the mouse is clicking.
However, if I used the second method, I find it easier to save all my Unit instances into an array, not having to save the whole prefab multiple times, but a bunch of numeric values which I store in the class. Also, having an array with all the units in game seems easier with this second method.
Taking into account the way in which unity works, I find the first way to be more logical, however I don't want to start coding in one way and then find out that the other one had some serious advantages.
Thank you very much
Answer by Berenger · Jun 18, 2012 at 10:24 PM
You must understand that the script you create that can be attached to game objects inherit from MonoBehaviour. That allow them to receive messages like Update, Start etc. However, you cannot instantiate them like any object with a new keyword. You need to either drag them in the editor on the gameObject, or to use AddComponent.
This being said, I suggest you create a class called UnitPool (or whatever) that contains all the instances of units, all inactive at first. This class must be able to provide an instance of a unit (activating it) or recycle one that is dead (inactive). That way, you don't need to use Instantiate, which is quite expensive, and you can keep track of all the active instance.
First, the hierarchy so everything is well sorted in the hierarchy view. You don't HAVE to do it, but it's cleaner. So, create a GameObject named UnitPool, reset transform, add the script UnitPool.cs/js to it (I'll get to that later). Then create other empty go with relevant names for those Units (Troopers, Tanks, etc), make them children of UnitPool, reset transform. Finally, drag you're unit(s) prefab on the scene, make it child of the corresponding go and duplicate them 20 (or more). Select them all and uncheck the active checkbox.
The script now. Declare as many arrays as you have types of units. Assign them the duplicates in the inspector. Create an enum with the name of your units, like enum UnitType{ Trooper, Tank }. Then, create a function that returns a gameObject depending on the type :
// PS : It would be smart to create a class that does the array access, counter and wrapping.
public GameObject GetUnit( UnitType type )
{
GameObject unit = null;
switch( type )
{
case UnitType.Trooper : unit = trooperArray[ trooperCounter ];
trooperCounter++;
// Wrap the counter when we reach the end
trooperCounter = trooperCounter >= trooperArray ? 0 : trooperCounter;
break;
case UnitType.Tank : unit = tankArray[ tankCounter ];
tankCounter++;
// Wrap the counter when we reach the end
tankCounter = tankCounter >= tankArray ? 0 : tankCounter;
break;
}
// Re-active it
unit.SetActiveRecursively(true);
// An init function is probably needed here, to restore health for instance
return unit;
}
Finally, a recycle function. The point is to make the unit disappear when it's dead without destroying it. Basically, you just use SetActiveRecursively(true);. You might have to reset the parent if you changed it.
public void Recycle( GameObject unit )
{
unit.SetActiveRecursively(false);
unit.transform.localPosition = Vector3.zero;
unit.transform.localRotation = Quaternion.identity;
}
As you may understand, you need at to have enough pre-instantiated units for any possibilities in your game. The best is probably to limit the number the player can create.
Well, I understand the concept, but I'm not sure on how to implement this. So what you're telling me is:
I should create a class (UnitPool) which contains instances of all of my units in game. But what do you mean by inactive, made them disabled?
Also, how can I avoid using the instantiate method with this? If I have all my instances in a singleton class, and want to get one into game, rather than activating it, shouldn't I copy it into the game? Or were you talking about this class holding ALL of the units let's say there are 20 soldiers in screen, all of them the same (just like in most RTS games), then the UnitPool must have 20 instances of the soldier?
I know this is asking a lot... I'd be very gratefull if you were able to answer me
Well, taking into account the kind of game I want to create, this seems to be what I'm looking for. Unlike normal RTS games, i'm planning to decide all the units in a battle before the battle starts, so this avoids me a lot of unnecesary memory cost. Each unit involved in battle must have been deter$$anonymous$$ed before, and doing that through the scene view rather than coding seems like the best way to do it.
So, thank you very much, that was really helpful ^^ I'll keep on working
Your answer
Follow this Question
Related Questions
How to check hit on tank 1 Answer
Multiplayer RTS Script 2 Answers
Attaching an RTS scrolling script to a camera (Noob Question) 3 Answers
How do I implement Kongregate's API? 0 Answers
Free Camera 2 Answers