Understanding True Component Based Design

Hi

I was tempted to post this in Answers, but really what i’m asking for here is kind of based on peoples programming practice opinions, so I think this is better suited.

I’ve been using Unity for a while, but never really embraced the Component system, so now i’m trying to drop my reliance on OOP and really get into it, but I cant seem to get past this very small hurdle. I was hoping someone could help talk me through this simple example:

A Jumping Character.

If I was doing this the way I would usually do it: When the jump key is pressed, I check if the character is touching the ground, possibly via a short raycast, then I’d set the vertical velocity of the rigidbody to some jump strength value, and let gravity do the rest. All in one class.

I’d like to figure out how to break this down into separate components, so I started with creating a Jump component, which just handles increasing the velocity based on a Vector3 direction parameter and a strength parameter. Easy peasy.

class Jumper : Monobehaviour {
  // ... parameters...
  public void jump(){
    // ... Make character jump...
  }
}

and something similar for the ground check

class Grounded : Monobehaviour {
  // ... parameters...
  public bool check(){
    // ... ray cast etc...
  }
}

But now i’m stuck trying to work out how to work in the ground check without tightly coupling it to the Jump component.
So far I have tried creating a third component which, when triggered, will check the ground using the ground check and jump if its grounded.

// ... Require jumper  grounded...
class JumpIfGrounded : Monobehaviour {
  Jumper j;
  Grounded g;
  public void jump(){
    if(g.check())
    j.jump();
  }
}

But the problem with this solution is that i’ll need to create a class like this for every combination of check and action. For example, what If i want to enable the character to perform a special dash, only when its touching the ground. I want to be able to use this same ground check for that too. At the same time, I don’t want the Jump or the Dash to always require a ground check, since I might want some creatures to be able to dash in the air, or double jump. Also, what if I create a Sticky platform? In that case it shouldn’t matter if the character is grounded. But ideally don’t want Sticky to have to know about Grounded, or Jump (although I really can’t imagine how that’s possible).

I have been tempted to use inheritance to solve this problem, but this is a red flag, because i’m trying to ditch OOP in favor of this Component based design.

How would you tackle this problem in a component based fashion?

p.s. I realize the level of component interchangeability I am searching for might not be possible, but perhaps in that case I can get close?

I don’t have an answer to your question other than this. I have never seen a “True Component Based Design” in unity EVER, in any project that I’ve looked at. I wouldn’t kill yourself over striving for some theoretical “Perfect Design”, I highly doubt it’s even possible to achieve that in unity. You see, you have to consider certain limitations that unity has. For instance, every single unity class is sealed except MonoBehaviour. Honestly this alone probably destroys any hope of achieving a “Perfect Design”.

Here’s a challenge, show me an existing unity project that demonstrates this “True Component Based Design”.

/facedesk

Why the hell would you want that?

Component and OOP are not mutually exclusive, as they don’t mean the same thing. (http://lightstrikersoftware.com/index.php/blog)

Because…

I know they are not mutually exclusive, but right now i’m trying to find out exactly where one is more appropriate than another. As I said, it’s unlikely that i’ll be able to find a perfect solution. But I would much rather come to the forums and ask for another take on the problem before reverting to using the solution that I already know. In other words: If there is a component-based solution I would like to know it.

Are you saying that what I want to achieve is outside the scope of what a component based design can provide?

Not at all. Only that dividing your behaviour into such smaller chunk will gives you horrible communication and maintenance issue.

Usually, people won’t subdivide that much. You got to ask yourself, how will you combine components. If every player is able to jump, shouldn’t all the jump mechanic be inside the Player class?

Or if every character can jump, should it be in “Character” and “Player” derive from that?

One helpful way I think about breaking things down in Unity3D is in the very name of the base class for any script: a Monobehaviour

In the human context, when you say “behavior,” generally you mean a related set of activities and information related to that behavior. Often breaking it down further than that isn’t helpful, and is actually destructive to smooth functioning.

“Jumping” generally involves decisions relating to where, when and how high, as well as considerations for where you might land, or intend to land. When we jump, our bodies coordinate all these different activities generally as a single behavior, and while technically there are different components of our bodies doing each of these things, it isn’t helpful (when jumping) to break them down. It might be helpful for a sports trainer, but that’s a different story.

Another thing is to not be afraid to refactor and reorganize how you have chosen to do things and come up with a better way. Try not to get too brittle in the direction you chose for something, especially if it begins to show higher technical “costs” than you’re comfortable with.

Kurt

Thats OO thinking, completely fine but a component based approach is also fine. The OO approach tends to require more up front design and a larger cost for change.

Consider for example an Explode behaviour, you put it in on object and in response to a collision with a certain force it destructs the mesh, plays a particle effect and then destroys the object. Armed with this behaviour you can drop it on to anything in your game world that you wnt to explode and it will work… you can even do this at run time: a level designer can think “hey this barrel should explode when the other car rams in to it” and literally pause the game and add the behaviour to test it out.

Its not that you can’t design such a system in OO (maybe every object has an IExplodable implementation), but you do need to go out of your way to make something with the workflow described above.

Back to the OP… there’s no problem trying your jump to grounded… jumping is generally the kind of thing that is tied to being grounded.

If some special character can jump while in the air then you can always have a character specific implementation of grounded. Inheritance and components can work together :slight_smile:

I know it is, and that’s my point. However, I disagree with the up front design and cost. Yeah, I guess you have to think a little bit more about your design. However, by experience, that always save time down the road.

For a small game that you don’t care about quality, making a “jump” component may be sound. However, when they “jump” has to talk to every other “behaviour” component or state machine, animation, and has to synchronize with getting hurt or performing other task… When your character is rather complex, it may very well get over 20-30 small behaviour “chunks”. You get behaviour that breaks each other and a major headache trying to have them all talk properly in a component fashion. On top you’ll have to sort out the execution order of all the possible component. IsGround should obviously be called before Jump.

Consider your example of “Explode”. If I put it on a interactive chest, should the player be able to interact with it while its exploding? Obviously not… Should Explode disable every other component that it is not using? But then, turning off a script at the wrong time could have some unwanted effect. Imagine the player is currently interacting with the chest when a rocket explode it. You might just break both the chest and the player’s behaviour. It’s cool for fast prototyping and trying new thing, but just not as cool when you got to build a full real game.

Components are very useful when taken alone, when they have a very specific job and when their communication channel are well defined. For example, the Renderer/Mesh Filter/Collider all perform a simple function and work well together. The numerous components built-in Unity are usually good example of components implementation.

There’s the part where something should maybe not be a GameObject’s component, but be a MonoBehaviour’s component. Components of a bigger script is also a real possibility. Imagine you have a “Character” MonoBehaviour, with a “CharacterBehaviour” list of internal component that you attach to it. The master class decide how the small chunk behave and communicate between each other. It gives limits to what they can do and when.

Let me start by saying that I’ve read a few of your posts and I think most of what you say is accurate, insightful, and well written, however I think your recommendations against components shows a little bit of a bias which I believe is unfounded.

Firstly, and I know this argument smacks of a call to authority, but maybe also a proof by example too: there’s a reason that Unity and UDK (and Unreal) and from what I understand Crysis are all heavily component based. Component based systems are well suited to games. I think you are quite wrong when you suggest the approach is only good for prototyping and small games. I don’t have enough insight to say most large games are component based, but I do know enough to say that large portions of many large games are.

As to my specific example its easy to argue my Explode component is bad if you assume I write a bad Explode component. The reality is that its frequently quite easy to write that sort of component in a way that works well in almost all cases. But I think its pointless to argue based on an example, you can always come up with a case that doesn’t work, to which I provide a counter, etc. I thnk my example illustrated a point and I’ll leave it at that.

Similarly I’m not neccessarily saying the OP’s Jump is the right level of granularity. I agree its probably too specific. What I really like is that TickTakashi is making a commitment to trying to learn another methodology. Hard not to sound condescending when I say this but maybe you should try it yourself: dive in to a reasonably large project with the goal of using component based approach wherever its vaguelly appropriate, I think you will find it rewarding.

Let me finish with a bit of my own history:

I come from a background of strong OO, many years in developing enterprise systems using Java. When I first started Unity I wrote component based javascript becasue thats what the examples look like. I picked up c# because it was close to the language I knew best (Java), and pretty much everything I built after that was heavily OO. I was even writing unit tests for most of my code, to the extent that I wrote an IL post-processor to enable me to hook in tests for stuff that Unity made hard to test (if you have ever seen the Benchy profiler for Unity free, thats using my IL post-processing code … although I’m sure Sean has matured the code I originally sold him pretty significantly).

But more and more I’m seeing good projects (between supporting my asset store products and my consulting work I get to see a lot of projects) and good assets written using a strongly component based approach. So much so that in the stuff I’m working on now I’m favouring component based design and finding it to work exceedingly well. The proof will be in the pudding: the new version of my platform controller is a complete, strongly component-based, rewrite … there are many users who will be eating the pudding.

:slight_smile:


EDIT: I just have to add I definitely am not recommending component based design to the exclsuion of OO! Some things suit one, some thing suit the other, and some problems are best solved with a combination of both.

I… am a little new to argue, but I would love to hear about examples of components in use, on the explosion case and others. And I thank you guys for the chat. It’s very helpful.

I’ve got to actually do some work, but I’ll aim to producce a post mortem of my platform asset update with a focus on the design and why I went with the component based approach.

1 Like

I think you got me wrong. I’m not at all against components implementation. I’m against extreme implementation, like when someone come and say “I want to go pure Components or pure OOP”. For the same reason I dislike pure code-driven and pure data-driven approach. To me, each of those are a tools that exist for a purpose. I think doing a twisted design because someone despite a specific paradigm and want to avoid it at all cost is just about the worst someone can do in code architecture. Every times someone comes and tell me “static” is wrong and should never be used… sigh

Components are great when the behaviour of a component is well define and its interaction with other components is controlled. If your “Explode” component is well written, it’s all great. However, I’m all too used to a designer taking something you think is well written and mixing it with other components you didn’t think about, and making the whole thing explode in a not-so-good kind of way. Components offer a data-driven approach to building the objects of a video game, and for that task, they work perfectly. What most people forget is, a GameObject is not the only object that can live with components attach to it. The first thing I did when I started working with Unity is to create a “create instance from derived field type” interface to be able to create sub-component from an Inspector field, and inspect those sub-objects. Doing that opens up a huge panel of possibility that otherwise would be harder to handle or manage, such has a script having fully polymorphic sub-components.

As for diving into a large project… Is Assassin’s Creed 3 large enough? :wink: 14 millions line of codes in C++/C#. Sure, it’s not Unity, but Anvil/Scimitar is also heavily component based. However, unlike Unity, Anvil favor the idea that every components may have inner components on its own and is fully supporting polymorphism at every level. Something I highly regret that Unity doesn’t properly support. :frowning:

I’m a technical director with 8 years of experience. I’ve made huge game with huge (750+ people) teams and small games with small (~20 people) teams.

If I pass as being condescendent, I deeply apologize, I didn’t mean it. I don’t speak English on a daily basis, and no doubt that doesn’t help.

I’m just going to spew my thoughts out as I don’t want to waste too much more time arguing on the forums :slight_smile: So quickly…


The reasoning for the extreme implementation here wasn’t “this is the best way”, its “I want to force myself to do this something to the extreme so I get a better understanding”. This seems very reasonable to me.

Because one good product was delivered a certain way that doesn’t mean its the only way, or imply that other methods are bad or even inferior.

I can’t deny you have more games industry game experience, but I have signifcantly more than eight years development experience (I published my first computer game in Amstrad Action when I was twelve, I did my first paid programming work when I was fifteen, and even if you only want to count full-time post degree work I have fifteen years of experience).The projects I work on on a daily basis are often an order of magnitude larger than the most expensive games ever made, so I do know a little bit about large projects.

But really neither this nor AAA game industry experience particualry applies to this situation. You yourself say small projects of ~20 people… I’d guess that 99% of people posting here are working in teams signifcantly smaller than that, most of them would be 1-5 people*.

If anything the experience of my hobby (where I do some consulting for indie developers, work on and support Unity assets used by many hundreds of people, and develop small mobile and web games), is much more applicable to what the average user here is trying to achieve.

But who cares about a call to authority…

  • That’s not to say there aren’t larger teams working on Unity, but most of them wouldn’t be asking for basic design advice in the forums.

In the end maybe I’ve got you wrong, maybe it is a small part due to language, or maybe just an error in my own interpretation, but it just seems every time someone mentions Component based design you caution them away from it. You don’t do so bluntly and you do so quite reasonably because you are obviously a smart and reasonable person, but I think that working with Unity’s component system will often lead to better results, particually in the context of small indie teams.

Thank you for highlighting this, I didn’t mean to say that one was better than the other. I just want to understand this pattern by working through examples.

Reading through all of you guys posts, you’re all much more experienced than I am, so i’m glad you’ve chimed in on this. I have worked through my problem a little and you guys are right and I wasn’t really thinking it through. A jump is only a jump if you eventually hit the ground (otherwise its flying).

That implies a dependency, jumping component will always need a ground checking component. But not the other way around. I was tempted to force objects to have a “Ground” component, but instead the ground check component can be set to target specific layers. The ground checking component is free to be used in other situations, I’ve used it to check when a driving car can accelerate for example.

The question that is now on my mind is to do with the use of “SendMessage” in component communication. When is it appropriate to use? I have thought about implementing a StickyGround component which would send a “Stuck” message to all things that collide with it, but obviously that means that all movement-related components would need a Stuck method. This is very clearly something that is usually solved by programming to an Interface, so Is this one of those moments when the two approaches should meet? Or is there a Component based solution to this issue?

You guys have been really helpful so far, even if its not directly answering my questions, this discussion is really valuable.

I’m of two minds on SendMessage, it can used to good effect to get very loosley coupled code, but this can also lead to hard to debug code (amongst other issues). NGUI makes extensive use of SendMessage, and although I woulnd’t hold NGUI up as a paragron of good design, it does make good use of it.

Obviously don’t use it in a way that could have a performance impact (i.e. many calls per frame).

I’d be interested to hear LightStrikers views on it.

Also I would like to add these days my primary usage of Unity is to develop assets for the store, this would certianly colour my view: its very important in this context for the asset to be easy to use and widely accessible, potentially even at the expense of other design principles.

I would argue that going to the extreme could be useful only for finding the limitation of an implementation. As for learning it, it could simply give you bad habits right from the start, or twist the view you get from that paradigm. I know some people claim the best way to learn that fire is hot, is by being burn. However, some burnt people may fear the fire later… or burn houses themselves.

Personally, I like to learn something by understanding how and why it’s done. However, I admit not everybody learn the same way.

I would stay away from SendMessage because of its performance cost. On top, hard-coding string message isn’t a very clean design and is hard to maintain (and debug) if you need to change anything. Frankly, it’s a shortcut method when you need something quick and dirty. There’s always alternative to it, but they often requires more thinking about your design.

Yes, in this case, an interface could be useful. I like to have all the classes that can receive damage to implement something like IDamageable, or everything that can be targeted to be ITargetable, and so on. Note that the generic method GetComponents cannot take an interface as type because it constraint it to a derive from Component. You need to use the non-generic one (GetComponents(Type type)). However, it will gives you every component that implement your interface.

Lightstriker, what are your thoughts on using composition, vs inheritance?

1476568--81484--$jEDjaVI.png

In all seriousness, to me, both are - again - just tools that serve a purpose. It’s a case-by-case issue where one tool may be best for one problem, but may be not for another.

Frankly, I actually have an implementation that uses both! Geezz… I would need a graph for that… but let’s do without it. Be patient, the explanation may take a while.

It’s the camera system I use in all the projects I work on. It was first code by Patrick Desbiens-Wright for Prince of Persia: The Forgotten Sands.
This system took about a year to design and put in place, but once done, we never had to rework its foundation. We simply didn’t manage to find a camera we couldn’t do with it. I ported the system to Unity.

public class CameraBehaviour : MonoBehaviour
{
    public CameraContext previousContext;
    public CameraContext currentConext;
    public CameraContext defaultContext;
}

The system is built in many parts, but the 2 main one are CameraBehaviour and CameraContext. The CameraBehaviour is simply the GameObject which resides a Camera component. The behaviour is simply the anchor to the GameObject.

The CameraContext, on the other hand, is the container defining a specific camera behaviour. For example, a first person camera behaviour would be fully defined in a CameraContext. The CameraBehaviour can transition between different contexts by interpolation. Want to switch from a first person to a third person? Give the CameraBehaviour a new context and tells it to switch to it over a period of time.

Yeah… So far, what’s the big deal? The CameraContext is only a sub-component of CameraBehaviour.

public sealed class CameraContext

Wait? What? If CameraContext is sealed, how can someone derive from it and implement a behaviour like a first person view? Well… you don’t.

public sealed class CameraContext
{
    public CameraFieldOfView fieldOfView;

    public CameraPositionner positionner;
    public CameraDamper positionnerDamper;

    public CameraOrienter orienter;
    public CameraDamper orienterDamper;

    public CameraCollider collider;
    public CameraBanker banker;
    public CameraShaker shaker;
}

The CameraContext is a data-driven composition made of smaller part that perform a single job on a how a camera behave. In the Inspector, it looks like this;

1476568--81489--$GkI1GLT.png

So I build the behaviour of a camera block by block. For example, from CameraPositionner, I have the following derived class;

  • CameraFixedPositionner
  • CameraInputPositionner
  • CameraLinearPositionner
  • CameraPlanarPositionner

Which each control the position of the camera in a different way. However, Unity is a bit tricky when it comes to polymorphism. CameraPositionner cannot derive directly from System.Object, otherwise it would always deserialize this into CameraPositionner and not CameraFixedPositionner. On top, I like to have common method and behaviour into a base class. The hiearchy of CameraFixedPositionner is;

CameraFixedPositionner => CameraPositionner => CameraModifier => ComponentMonoBehaviour => MonoBehaviour => etc.

Youch! Talk about inheritance! ComponentMonoBehaviour is a bit special and it allows me to have this object handled as a component of another MonoBehaviour instead of a component of a GameObject.

So once I decided on a positionner, the Inspector looks like this;

1463031--79978--$BSXMUvN.png

Yeah, I got a sub-sub-component called CameraTarget, which implement different method of retrieving a position/orientation… Like projection on a spline, average of a list of GameObject, animated camera, or even a security camera. And you can have a CameraTarget in a CameraTarget in a CameraTarget in a… But let’s keep it simple.

So, CameraContext is built, by the designer and not the coder, by composition of a collection of classes built from a deep inheritance.

Do I prefer composition over inheritance? Not really. I guess I tend to use inheritance slightly more often because what I have to build is better suited for it. I also use composition because it gives the flexibility of a component system, but with control over how the pieces play with each other. I can do any camera you can think of, and if you can come up with a new behaviour, I’ll only need write the few lines required for a new positionner… or orienter… or whatever block can define the missing parts of that new behaviour. This new piece is then able to work with every other existing blocks of the system, because each of them has a well define role.

I’m deeply sorry if you read all that. I wrote that at midnight, so it may very well be a huge mess of typos and grammar errors.

I too am intersted in going for a more component based design for my next project. It can be very hard (at least for me) to figure out exactly how to structure everything with components to make things as modular as possible.

Does anyone know of anywhere where techniques and best practices for this are described? If these descriptions were Unity specific that would be even better.

I’m looking forward to JohnnyA’s rework of his platform controller. Hopefully it will be a valuable resource for me to learn more about component based design :slight_smile:

Thanks for the insights LightStriker and JonnyA