I have a project where I’ve created an Actor that consists of an inner and outer collision sphere. (It’s a VR project, and I blend different hand animations depending on where my controller is in relation to the spheres). I want to turn this into an ActorComponent so that I can attach these objects to other actors. What is the best way to do that?
I tried creating a blueprint based on the ActorComponent, but there’s no viewport, so I don’t see how to easily set up the hierarchy of components. I could use the ChildActor component, but everything I’ve read advises that I generally stay away from that?
So what’s the right way to attach an object like this to other objects…?
In general, the Unreal Way is not for components to manage sub-components, but instead for Actors to manage components. If you have components that need to talk to each other, make those in an Actor, and then subclass that Actor for whatever other re-use you need to make.
This runs into trouble when you need two separate bases – e g, “YourActor” and “Character” in the same class. You’ll then end up porting all the actor code from YourActor to a custom subclass of Character, that you can then in turn subclass for whatever the desired behavior is.
Well… that’s frustrating. That doesn’t seem to resonate with the object-oriented design paradigm of favoring composition over inheritance.
Surely I’m doing something wrong. I have a little object that has some collision spheres and some functions. I want it to be a component so that other actors can contain one or more of them. Is that really not possible?
You can use the same method as the constraint component:
Make an actor component. Get a reference to the owning actor. Get the names of the shape components and then the references. Work off the references.
If you want your component to include the shapes as well, you can use shape traces per tick in the component, but this may be less performant.
Though, like jwatte said, you would do this in the actor, not the component. Scene components (have transforms) usually only do work on themselves, while actor components (don’t have transforms) modify some property of the actor they are attached to. A simpler method than what I made above is to do what jwatte said: make a base actor class that has the two spheres & the logic already in them. Then in the child classes, allow setting the size of those. My method is only useful if you want to attach them to any actor type without needing a base class, but since you’re only going to be doing this on pickable items, using a base class is easier.
Wow, I appreciate the thorough reply! Although… you’ve just created an ActorComponent within the one actor that i’m trying to turn into an ActorComponent. I’m trying to make multiple instances of these components so that they can be attached to other actors.
Which is why inheritance is a no go for something like this. What if I want two of the components attached to one actor? What if I want it to be a base class, so that some instances have two shapes and some have three? etc.
It genuinely sounds like the engine isn’t designed to support this kind of thing, apart from using the ChildActor component (which is advised to be used sparingly).
But I’d still have to create all the individual shape objects, per actor. Instead of just having a component that encapsulates those things. Like an object. Like an “object oriented” approach.
This is one of the primary reasons for the design principle “Composition over Inheritance”, and I’m surprised to find Unreal is limited in this regard. I guess the Child Actor component is the answer here, but it’s apparently clunky and unreliable.
Is there not a C++ way to do it? Can I not create my own component through code that contains the objects and functions I want?
Yes, you can do that. Just duplicate the sphere component and modify it to support more than one sphere. Though, I don’t know if it’s as simple as that since I haven’t seen it. But I’ve made components in C++ before and it’s pretty simple. Edit: Though, I just realized, you’re not going to be able to move them in the viewport since scene components have only one transform. You would have to set their location through the details panel only.
I would just stick with either my or jwatte’s idea; I whipped them both up quickly and they’re easy & straightforward.
I get you want it all contained in one component, but the only types of objects that are going to be using this are pickable ones. Think about it this way: for every new object you create, you’re going to have to add this component to it manually. It would be faster if it came automatically with the object. That’s what a base class is for. Any pickable object inherits from “PickableObject” and comes with the logic for handling the overlap and anything else. For every child actor, all you need to do is add the shapes. Since the shapes will vary per-object, this is a necessary step anyway.
A better example: What if you wanted to animate the shapes? Or attach them to separate components that will be moving? What if you wanted to change the size of the shapes over time. What if a property of the shape is determined by some gameplay element? Put simply: what if the shapes are dynamic. Having them in a single component wouldn’t allow this, but having each shape as a separate component will.
" but the only types of objects that are going to be using this are pickable ones"
…that’s not true. That’s not how I’m planning to use these things. Inheritance is not the right tool for the job here. Seriously, this is a classic problem related to a design paradigm that emerged as object-oriented programming languages evolved.
I’ve already started creating a C++ class based on ActorComponent, it’s definitely how I want to tackle this. Especially since I can just nativize the actor blueprint I’ve already created and bring that logic over to the component.
Then you only need the data (floats, animation sequences, etc.) in the spheres, then put the logic (animation handling) in the hand. Whenever the hand overlaps a sphere, it gets the data from that sphere.
Since you can’t make a child blueprint class from a sphere component, you’ll have to do it in C++, which is simple.