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)

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.