Are dependent components bad

Let’s say I have a component called ‘Pushable’ which allows me to push any Actor with this component on it. This component includes all the logic when I can push the object, in which direction, minimum distance, etc… However, I want to be able to do all the actual movement logic in a seperate movement component. So the ‘Pushable’ component would require a ‘Movement’ component to work. Is this bad style? Should a component always be self-contained and not dependent on other components?

If yes, how would you solve my example? Of course I could implement the movement logic into my ‘Pushable’ component as well, but this would of course require duplicate code and also makes the ‘Pushable’ component have to deal with things it shouldn’t need to deal with…

If not, how would you enforce an user who uses the ‘Pushable’ component, to provide a ‘Movement’ component on the Actor as well?

In addition to “SuddenlyMuffin’s” answer some amendments:

I already thought about using interfaces, however I think they don’t fit in my case, because:

  1. I want to be able to easily add/remove features on the fly, without having to create a blueprint in the beginning and without having to implement this interface in order to see if I should keep the new behaviour or not
  2. Adding a pushable functionality at runtime becomes much cleaner and easier, since I would only have to attach the existing component

Furthermore, here is Zach’s new video, which inspired me to start this discussion. He also uses components to actually give Actors new behaviour and features: Using BP Components for Game Behaviour | Live Training | Unreal Engine - YouTube

Not being staff, I cannot comment on the intended style for components.

That said, It seems to me that a more appropriate approach to the problem you describe is to use a Blueprint Interface. You could create a “PushableInterface”, which defines some pushing related functions. You then implement this interface on all the objects that you consider able to be pushed, implementing the functions and using the movement components as appropriate for the implementing object.

Objects wishing to perform a push on something simply then need to either call the interface message, or cast to the interface and call the functions directly. If you find that most pushable objects are using the same kind of code, you could then create a component or some helper functions in a function library to simplify it.

One of the advantages of this approach is that how the pushing works is not tied to the implementation. If you have a object that is considered to be “Pushable” but it does not use a movement component, but instead uses physics simulation, it would simply implement the interface differently, and would already work with the rest of your code that does the pushing.

The documentation for Blueprint Interfaces can be found here:

If you are set on using components to provide pushable behaviour, then I would recommend a weak dependence on MovementComponent. Check if the parent actor has one, and if it doesn’t exist, the PushableComponent shouldn’t do anything. That way as little as possible will break if the MovementComponent is missing, the actor will simply not be pushable.

Thank you very much for your answer.
Coming from a C++/C+/Java Background, I also thought firstly, that using an BP Interface would be the right solution.
Then however I saw this quite new video, where Zach describes how to use components to add behaviour. I think this is very useful, mainly because of two reasons:

  1. You actually don’t need to create a Blueprint in order to use the behaviour. In my opinion, this is great for testing and constant adding/removing of functionality
  2. If I suddendly wanted to make a object pushable, I could simply attach my component to this object. Sure, I could implement the interface on every object and just call a ‘disablePushing’/‘enablePushing’ function to allow or deny pushing of this object. However, this is a lot of work and adds a functionality to an object that probably will never need this feature.

Sorry if I’m quite touchy right now (and probably over-engineering) but I love discussions about such theoretical design questions.

While this is to some extent stating the obvious, I think it’s a case of tradeoffs. No system will be perfect. The pluggable components system is great for allowing modular functionality to be added to objects of various types. But naturally, by circumventing a strict inheritance hierarchy, you are faced with not knowing so much about the object your component is plugged into. You then essentially have two choices.

  1. Leave it to the owning actor to coordinate interactions between components. This way you have more control, but lose a large part of the pluggability, in that a component no longer entirely takes care of itself. You also end up duplicating more code.

  2. Make assumptions within the component about its owner, and what other components it’s owner has, thereby introducing dependencies. Of course you should always try to minimize dependencies, but sometimes you won’t be able to avoid them.

Thanks kamrann!
Yes there doesn’t seem to be an ultimative answer. But I’ll keep overthinking this issue, since I really really like the flexibility components give you. If I come to a good solution, I’ll probaply post my work either here or on the forum.
However I’m still leaving the question in the room for a while, since I’m not quite convinced by any answer right now…

Components are made to be flexible and working with them should reflect that. I think benjamin.rickels is right in pursuing a better way to leverage the power of components even though it might not be supported in the Engine for now.

This is a part of UE that I think needs much priority. Not because it does not work in it’s current state, but just because components is what people (should?) use for everything.

Perhaps some more editor validation would go a long way here? I know it’s a feature request for UE but there are already some systems in place guiding users to do the right thing. A trivial example would be the attached popup when trying to attach a plain ActorComponent to an Actor or SceneComponent: