Announcement

Collapse
No announcement yet.

How to set Actor Components to other components of a common type?

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

    How to set Actor Components to other components of a common type?

    I have a modular system I'm developing for gameplay where tanks can have different weapons that can be swapped out. To design to system I'm using Actor Components on tank blueprints. I have a base component, "Gun Mod", with all the base functions and properties a gun mod needs to have. This Gun Mod component can morph into other gun mod type that inherit Gun Mod and override its functions. My base tank blueprint has a Gun Mod component of type Gun Mod and I want its children to be able to change the variable Gun Mod to other common types such as Cannon of type Gun Mod. I can't for the life of me figure out how to set my already existing Actor Component, Gun Mod, to be a new Cannon.

    #2
    I'm not sure if that's really possible since the components are created during construction time, but I could be wrong.

    One way to achieve that is to create the guns as actors, and add to the tank class the base gun mod as a class type variable to be spawned. This way you can change the variable class to inherited ones.

    This solution is similar to the one used in ShooterGame project from Epic for the weapon. (I extended this functionality to also be able to use grenades)

    Anyway, I'd also be interested in the actor component solution. Looking forward for further answers.

    Best of luck!

    Comment


      #3
      I'm still thoroughly researching this. There seems to be no real dynamism with Actor Components; which the name "component" makes it deceiving. So far I learned that Actor Components can only be "Added" not "Spawned" using a special internal function that only Actors have. So if outside objects wanted to add a component to an actor, it has to be done through the Actor's public interface.

      Also you can't seem to add them based on class. In my game I have designed on paper three gun mod types that extend from the Gun Mod class. All 4 of these classes have special "Add" functions that do the magic.

      Click image for larger version

Name:	unknown.png
Views:	1
Size:	36.3 KB
ID:	1122645

      So if I wanted my tank to be modular with these weapons, I'd have to write a special public adder function for each components to swap out.

      A
      Pain
      In
      The
      ***

      My other post:
      https://answers.unrealengine.com/que...-a-variab.html

      Other posts similar to my problem:
      https://answers.unrealengine.com/que...m-a-class.html
      https://answers.unrealengine.com/que...blueprint.html
      https://answers.unrealengine.com/que...t-runtime.html
      https://answers.unrealengine.com/que...ject-from.html
      https://answers.unrealengine.com/que...nction-li.html
      Last edited by GhostRavenstorm; 02-06-2017, 06:58 AM.

      Comment


        #4
        This one appears to be a C++ solution to spawning Actor Components from a class.

        http://gamedev.stackexchange.com/que...a-class-in-ue4

        Comment


          #5
          Originally posted by GhostRavenstorm View Post
          This one appears to be a C++ solution to spawning Actor Components from a class.

          http://gamedev.stackexchange.com/que...a-class-in-ue4
          This is intriguing. If you use the C++ code solution, AFAK you'll have to add to it's constructor, making it somehow static. I was able to switch components only in a static manner by overriding the C++ constructor for each component, which is awkward:

          The base class .h:

          Code:
          /** payload component */
          UPROPERTY(VisibleDefaultsOnly, Category = Grenade)
          USF_PayloadBaseComponent* PayloadComp;
          The inherited class .cpp:


          Code:
          ASF_InterceptionGrenade::ASF_InterceptionGrenade(const FObjectInitializer& ObjectInitializer)
          	: Super(ObjectInitializer)
          {
          	PayloadComp = ObjectInitializer.CreateDefaultSubobject<USF_InterceptionPayloadComponent>(this, TEXT("InterceptionGrenadeComponent"));
          	AddOwnedComponent(PayloadComp);
          }
          In this way, If I create an Interception Grenade Blueprint (from the inherited interception grenade class) it would show the component I added:

          Click image for larger version

Name:	interceptiongrenade.png
Views:	1
Size:	62.4 KB
ID:	1122652

          I'll try bringing this solution to Blueprints so that it would be easily maintained.

          I'm wondering: would this result in the solution you were talking about here?

          So if I wanted my tank to be modular with these weapons, I'd have to write a special public adder function for each components to swap out.

          A
          Pain
          In
          The
          ***
          Last edited by MatheusRC; 02-06-2017, 09:09 AM.

          Comment


            #6
            Apparently I found a way of achieving some kind of actor component polymorphism.

            Let's say you wanted to make a tank with selected components. You would inherit a new BP from the base tank and would add the components in the Construction Script. Sounds like a good solution for you?

            I'll show you how I tested this using my grenade actor with payload components. (The grenade would be your tank, and the payload components your weapon components)

            In order to achieve this, I created a C++ base payload component, adding the base component functionality. Here, I added a generic Print function:

            PayloadBaseComponent .h:

            Code:
            UFUNCTION(BlueprintCallable, Category = "Test")
            virtual void Print();
            PayloadBaseComponent .cpp:

            Code:
            void USF_PayloadBaseComponent::Print()
            {
            	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Silver, "This is the base payload component", false);
            }
            Then, I created a C++ inherited payload component, called InterceptionPayloadComponent:

            InterceptionPayloadComponent .h:

            Code:
            virtual void Print() override;
            In order to be able to Add this component in Blueprints, you need to also add this to the UCLASS():

            Code:
            UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
            InterceptionPayloadComponent .cpp:

            Code:
            void USF_InterceptionPayloadComponent::Print()
            {
            	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Silver, "This is the interception payload component", false);
            }
            With the components created, I head to the Grenade class, the one I'll add components. To be able to reference the components, I'll add this variable:

            Grenade class .h:

            Code:
            /** payload component */
            UPROPERTY(BlueprintReadWrite, Category = "Grenade|Configs")
            USF_PayloadBaseComponent* PayloadComp;
            Ok, enough of C++. Now, I create an inherited blueprint class from Grenade, called InheritedGrenadeBP.

            Inside the Construction Script, I added this:

            Click image for larger version

Name:	constructionscript.png
Views:	1
Size:	36.8 KB
ID:	1122653

            Now, the inherited Grenade contains an Interception Payload Component, and I can use it's overrided methods. In the Inherited Grenade Event Graph, I added this:

            Click image for larger version

Name:	beginplay.png
Views:	1
Size:	29.9 KB
ID:	1122654

            So, when the Begin Play fires at the Inherited Grenade, it will use the Payload Component reference to call Print, which happens to be an Interception payload component!

            When running the game, this is printed:

            Click image for larger version

Name:	thisisthe.png
Views:	1
Size:	4.4 KB
ID:	1122655

            I hope this helps you somehow, I think from now on I'll use this to create my grenades

            [UPDATE]

            Do you want to change the component in runtime? I'm afraid this solution wouldn't fit this need.
            Last edited by MatheusRC; 02-06-2017, 10:30 AM.

            Comment


              #7
              Well the example from GameDev StackExchange doesn't work as described. I keep seeing this confusion between what the correct procedures are for creating a Scene Component or an Actor Component all over the forums. The Attach To method only exists in Scene Components. Actor Components need to use Add <Component> that's only within Actors. This has been the biggest hurdle in my design is the stupid limitations on actor components.

              I wrote a static function that takes an Actor reference and an Actor Component UClass reference, and it calls New Object using these two arguments as parameters because I want to take the variable of an already existing Actor Component type on any Actor and I want to set it to a new instance of whatever the UClass reference is.

              Code:
              UActorComponent* UApolloLibrary::SpawnActorComponentFromClass(UClass *actorComponent, class AActor *Owner)
              {
                 UClass* spawnedComponent = NewObject<UClass>(Owner, actorComponent);
                 Owner->AddOwnedComponent((UActorComponent*)spawnedComponent);
              
                 return (UActorComponent*)spawnedComponent;
              }
              This totally crashes the editor by the way. I don't yet if its an incorrect use of New Object, or maybe casting from UClass to Actor Component is causing it, or it could be the weird casting I' forced to do in blueprints because passing a self reference by reference doesn't make it writable and below blueprint static function (calling the above one) is suppose to write data to the self reference because that's where the Actor Component variable is I want to set.

              Click image for larger version

Name:	unknown.png
Views:	1
Size:	58.3 KB
ID:	1122703

              The Actor calling Equip Gun Mod to Tank is doing this on key press.
              Click image for larger version

Name:	unknown.png
Views:	1
Size:	50.2 KB
ID:	1122704

              I'm probably making this more complicated than it should be, and I don't want to. I'm just trying to figure out what retarded workarounds I need to make Actor Components dynamically interchangeable at runtime.

              Comment


                #8
                Im not sure if this is what you are after but a while ago I created a blueprint and c++ function to dynamically spawn components at runtime . Check the last few posts of this thread

                https://forums.unrealengine.com/show...es-it-go-wrong

                There is a link to the project on my GitHub which you can download to look at the code etc . Sorry it is only tested to work in engine 4.12 I haven't updated it since as I have been doing other things

                Comment


                  #9
                  This totally crashes the editor by the way.
                  Would you mind showing us the crash log?

                  Comment

                  Working...
                  X