Announcement

Collapse
No announcement yet.

Can you prevent specific components being added to a Blueprint class?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Can you prevent specific components being added to a Blueprint class?

    Hi all,

    I was creating some components the other day to add specific behaviour to some objects. It crossed my mind that whilst the components could be added to any actor, I would never really want that to be the case... for example, if I created a health component, I might want that on my player, or an NPC, but perhaps not on a rock (arguably you could say the rock has some health until it splits when you keep hitting it, but lets assume its the smallest rock already that wont break any further).

    The point being, if I was working in a small group and creating these components I would like to be able to say something like "can only be added to..." or "requires this component...".

    Unity had the "Requires Component" ability, so I'm assuming Unreal has something similar - but how about "preventing" them from being added? e.g. within the editor, I try to add a component and its either greyed out, or just errors when I try to add it - in editor?

    Anything like that built into Unreal?

    Would appreciate any info - thanks

    #2
    I generally use interfaces in conjunction with components. So if an actor can use a component, it usually implements the required interface and the component uses the interface functions to communicate with its owning actor.

    For example, in your health example, your player character and NPCs would have a BPI_Health interface & the Health component can also use the interface functions to contact the owning actor irrespective of whether it belongs to a player or an NPC.

    The same system can be used to check for the interface as a prerequisite (Does Implement Interface node) when you're adding a component & if it doesn't, as would be the case with rock, you don't add it.

    As for not having the contextual options in the BP graph, I believe there's no built in option to do that in blueprints.
    Last edited by Stormrage256; 12-03-2019, 04:04 AM.
    Unreal Possibilities
    Wave Spawning System | Tower Defense Starter Kit | Floating Damage Texts

    Comment


      #3
      Hey Stormrage256, thanks for the reply and info, my apologies for the delay responding.

      When you mentioned about checking the Does Implement Interface node, presumably this would be where the components are being added in a construction script? e.g. check to see if the interface is implemented, and then, if so, add the components.

      I suppose that would give the greater control, although I could then effective "move up" this same question to another level in the hierarchy, e.g. what would stop someone inadvertently implementing a wrong interface.

      Perhaps I'm thinking about this from the wrong direction, but I was considering say multiple people, same project, someone is designing the components, someone is adding those components to actors in the game. I was looking for the belt and braces approach to ensure the wrong things couldn't happen, of course, in reality I am working on my own, but I would still like to implement that level of scrutiny and control where possible.

      One thing I found with the interfaces/components (I think, I've been through a few iterations now and may have confused myself a little), was that the components couldn't have the reciprocating responses to the interface calls, because they are not the "thing" which is implementing them, only the owning actor could. Whilst that makes sense, it does mean that I can't wrap up all the health functionality, in this example, into the health component. The owning actor still has to have some awareness of things which are going on.

      Is that kinda normal, or am I perhaps doing something wrong?

      As I type that I have just realised that the components themselves could "implement" the interface... so, that now raises another question..>

      Do you typically implement the interface on the owning actor, and then have the corresponding event in the owning actors event graph which then in turn communicates with the component, or, have the component implement the interface and then have the event wrapped up inside that.

      At the moment I've done the former, but didn't like the owning actor knowing so much about what the component needed to do, it also meant those additional nodes were kinda cluttering up the owning actor. The latter approach would tidy that up, but I'm not sure if it may create other issues.

      Your thoughts are most welcome

      Comment


        #4
        I think you just need to use Child Blueprints.

        When you right click a BP you can duplicate. Or you can chose make child BP.

        So you can add a base 'being' class, and add a model and health system.

        If you duplicate it and make a 'troll class'. You can then switch the model but keep the health system. You can update it to a Troll's health and it won't effect the human. And if you now make changes to the human the troll isn't effected.

        If you make a child class of troll now, you can add a combat system. It won't change the base troll or the human. But changes to base troll will affect it.

        ------
        So now you have

        base being
        -base human
        ---other humans
        -base troll
        ---archer trolls

        If other people are working on the project just let them know you want the archer class to only affect 'archer trolls'. Then you don't have to redo the entire health system, you just modify it per class. But the archer system only affects children class under which it was assigned.

        Comment


          #5
          Within=OuterClassName Objects of this class cannot exist outside of an instance of an OuterClassName Object. This means that creating an Object of this class requires that an instance of OuterClassName is provided as its Outer Object.
          DependsOn=(ClassName1, ClassName2, ...) All classes listed will be compiled before this class. The class names provided must indicate classes in the same (or a previous) package. Multiple dependency classes can be identified using a single DependsOn line delimited by commas, or can be specified using a separate DependsOn line for each class. This is important when a class uses a struct or enum declared in another class, as the compiler only knows what is in the classes it has already compiled.
          UCLASS() created in C++ can be given those specifiers by the programmer.
          | Savior | USQLite | FSM | Object Pool | Sound Occlusion | Property Transfer | Magic Nodes | MORE |

          Comment


            #6
            RobMeade Yes, irrespective of whether the component is being added in the Construction Script or Event Graph, you can add the interface check right before the add component operation. But, as you pointed out, this won't stop anyone from just going ahead and adding a component anyway.

            You can think about it as a coding standard that everyone is made aware of. That if you want to add a particular component to a certain actor, the actor needs to have this interface. And it's not just a prerequisite check, but also as a way of saying that the interface will provide a means of communication from the interface to the actor.

            You can also extend it further by having an interface function that can be used to retrieve the component later. It saves you from using "GetComponent(s)byClass" function calls everywhere.

            I use the same approach that you're using as well. Having the actor implement the interface. This prevents the need for a component to make a cast operation to each potential owner class before communicating with them.

            So, for example, you have an enemy soldier class derived from Character. And another turret class derived from Pawn. And suppose both can have the health component regardless of having different parent classes. Here, if the health component wanted to relay some message back to its owner, without an interface, it would have to first cast to the soldier and see if its true. If not, then cast to turret and do the same. Now imagine a lot of different classes being able to have the health component. You would have to try casting to all of them to find out what the owner is.

            Now on the other hand, when you use an interface, you don't worry about that. If the parent has the interface, then it can respond to the transmission. That's it. Plus each owner can respond in a different manner. One example of this would be an interface function that gets called when health falls below a certain %. Enemy A might flee in terror, while Enemy B might become super aggressive. The Player Character might have HUD changes to reflect the damage taken. The health component wouldn't know how the owner will respond, so all it has to do is alert the owner and forget about it.

            None of this will prevent someone from going ahead and adding the wrong code in the wrong place. And I'm working on my own as well, so there are quite possibly issues with this approach that I've not encountered yet. But I like to think of it as choices that's kind of cumbersome at the beginning, but end up making it easier to work as your project gets larger and complicated in the long run. But, for setting a hard and fast rule, Bruno's answer above might be the only solution.
            Last edited by Stormrage256; 12-07-2019, 03:14 AM.
            Unreal Possibilities
            Wave Spawning System | Tower Defense Starter Kit | Floating Damage Texts

            Comment


              #7
              Stormrage256, thanks for the sanity check and it's nice to hear that someone else is working in a similar way to myself, that's kinda reassuring

              Thanks also BrUnO XaVIeR and jay_adams_11, I appreciate you taking the time to reply. It looks like the behaviour of the "depends on" would be perhaps what I want, but this project is all in Blueprint as opposed to me touching C++ at this time, so not an option at the moment.

              Comment

              Working...
              X