- Home /
Inheritance vs RequireComponent
Hello Answers,
I'm currently wondering about the code & files structure for my project, and I couldn't yet figure out the following: when should I use C# inheritance ? when should I use multiple components that call each other ?
I'll use the example where I'm stuck (using multiple components so far): each moving actor of the game is based on MoveController, which determines its speed & moving direction.
Then, this script is used by 2 other type of scripts: - Inputs: for instance AIInput and PlayerInput, which both call MoveController to set the actor's direction. - Special behaviors: for instance GravityController and FollowingController, which both make edits on the actor's direction, then Translate the actor in the end.
All these scripts use a RequireComponent(MoveController), so that I'm sure it's there when needed (either by an input or by a special behavior).
However, I feel Special behaviors classes could be children classes of MoveController, so the special behavior is easier to override (no need to call GetComponent, no public access on MoveController members needed...).
But, if I do so, I don't need to put MoveController in the actor anymore (the child classes are enough). Then "inputs" scripts won't work anymore because the required component is absent (only the child component is there).
What would be the best way to achieve this kind of thing ?
And do you agree with the following ?
Inheritance pro: + better control on override + better control on members access + More optimized (GetComponent being pretty slow) ?
Multiple components: + better interaction capabilities through Unity scripts
Thanks !
(note: asking again due to some bug in the portal)
Personally I recommend multiple components (because I tend to work by the rule that composition is better than inheritance).
why on unity answers is there a such thing as - answers?
Answer by Jacek_Wesolowski · Mar 06, 2012 at 04:16 PM
I think the MVC paradigm could be useful here. It says the Model - or internal simulation of an object's movement - should be separated from its Controller - or the input that influences the Model. For instance, in case of a car, the way the engine works would be part of the Model, and position of the steering wheel would be part of the Controller. The Controller would keep updating the Model with the steering wheel position data, without trying to affect direction as such. The Model would figure out how the input translates into actual direction and velocity, possibly taking into account such things as skidding.
In a case like yours, I would create a MoveModel class and have it handle all movement simulation, including things like inertia and gravity. If there were more than one movement model, I would implement those as children classes. In case of gravity, I think I wouldn't create a new class or component at all. Instead, there would be an "isAffectedByGravity" flag that controls a conditional statement within the model. I would never expose position, speed or acceleration as write-able variables. Instead, I would provide public functions such as Accelerate(), Brake(), Turn() etc. In other words, I would explicitly define what can be done with this particular model.
I would also create a separate MoveController class and have it provide the input for the model. Various kinds of input would be the children classes. Player input (eg. mouse or keyboard) would be one of those. Enemy AI could be another. Or, you might want to have different kinds of Player input, eg. one where pushing "forward" affects speed, and one where pushing the same "forward" affects acceleration. The trick is, these classes could differ a lot internally (eg. taking input from the keyboard as opposed to calculating it from an AI routine, not to mention remote input via network), but they would create exactly the same kind of feed for the model class.
Note that neither MoveModel nor MoveController need to inherit from MonoBehaviour. You could have a MonoBehaviour wrapper with MoveModel and MoveController fields that get initialised at runtime. Then you could connect them with references, i.e. there could be a MyModel field in the controller class, and MyController field in the model class. This would let you skip on using RequireComponent or GetComponent() altogether.
Thanks for the reply, the $$anonymous$$VC paradigm indeed makes sense here (always good to hear the basics after a couple of years without developing ^_^).
I see a couple of points here where I'm still confused:
if I initialize needed instances at runtime, I won't be able to expose their public variables in the editor right ? that thing is pretty handy for designers (rather than some settings X$$anonymous$$L loaded at runtime)
also, let's imagine I have another function assimilable to the $$anonymous$$odel: Shoot$$anonymous$$issile for instance. Should I have a different component from the kinetic model (child class of $$anonymous$$ove$$anonymous$$odel) ?
If so, let's say Shoot$$anonymous$$issile needs to know the velocity of the character to give the right impulse to the missile. Shoot$$anonymous$$issile will call $$anonymous$$ove$$anonymous$$odel.GetSpeed() , but for that I'd like to use RequireComponent($$anonymous$$ove$$anonymous$$odel) so I'm sure $$anonymous$$ove$$anonymous$$odel is available. But children classes are not recognized as $$anonymous$$ove$$anonymous$$odel so I can't operate this way. Is there something wrong in my approach ?
Thanks again for your help :)
Ha sorry, i didn't get the connection with references at 1st read (though passing ref on initialization in the code). I get the reference thing then, but again 2 thing: if the ref needs to be a $$anonymous$$ove$$anonymous$$odel, can I put a $$anonymous$$ove$$anonymous$$odel's children class instance there ?
and also, aren't the cross-references a bit of a pain to define for the GD that will manipulate these objects ?
Hu... seems I don't even have to bother with the cross-reference thing.
if I the following public class PlayerInputController : $$anonymous$$oveController { }
and [RequireComponent (typeof ($$anonymous$$ove$$anonymous$$odel))] public class $$anonymous$$oveController : $$anonymous$$onoBehaviour { }
then it seems I can use any child class from $$anonymous$$ove$$anonymous$$odel and it will still work (don't know why I thought the opposite on my last test). Then, however, when added to an object, PlayerInputController creates a $$anonymous$$ode$$anonymous$$odel component and the game designer will have to overwrite it with the move model he wants by drag & dropping the child $$anonymous$$odel at the place of its parent (ins$$anonymous$$d of adding the component anywhere), which is a bit more tricky.
Anyways, seems using inheritage works WITH RequireComponent, which shall help me to create my classes (I can regroup them nicely as you did with the $$anonymous$$VC paradigm) and not be an headache for the designer (no reference to define, just need to choose the type of behavior he'll want).
Bottom line: I'll keep in $$anonymous$$d having references to other component, and will activate them on Awake or Start to avoid using GetComponent during Updates (I heard GetComponent is really slow).
Thanks !
Jacek_Wesolowski, may I ask your thought about all the stuff above ? I'd like to have your feedback to close the thread :)
thx !