Implementing the Actor functionality by composition

Custom Actors without components don't have a location, and can't be attached to other Actors. Without a root Component, an Actor doesn't have a base transform, and so it has no location. Most Actors, therefore, require at least one Component to be useful.

We can create custom Actors through composition—adding a number of components to our Actor, where each component provides some of the functionality required.

Getting ready

This recipe will use the Actor class created in the Creating a custom Actor in C++ recipe.

How to do it...

  1. Add a new member to your custom class in C++ by making the following changes in the public section:
    UPROPERTY()
    UStaticMeshComponent* Mesh;
  2. Add the following line to the constructor inside the cpp file:
    Mesh = CreateDefaultSubobject<UStaticMeshComponent>("BaseMeshComponent");
  3. Verify your code looks like the following snippet, and compile it by using the Compile button in the editor, or building the project in Visual Studio:
    UCLASS()
    class UE4COOKBOOK_API AMyFirstActor : public AActor
    {
      GENERATED_BODY()
      public:
      AMyFirstActor();
      
      UPROPERTY() 
      UStaticMeshComponent* Mesh;
    };
    
    #include "UE4Cookbook.h"
    #include "MyFirstActor.h"
    AMyFirstActor::AMyFirstActor()
    {
      PrimaryActorTick.bCanEverTick = true;
    
      Mesh = CreateDefaultSubobject<UStaticMeshComponent>("BaseMeshComponent");
    }
  4. Once you've compiled this code, drag an instance of your class from the Content Browser out into the game environment, and you will be able to verify that it now has a transform and other properties, such as a Static Mesh, which comes from the StaticMeshComponent that we added.

How it works...

  1. The UPROPERTY macro we added to the class declaration is a pointer to hold the component we are using as a subobject of our Actor.
    UPROPERTY()
    UStaticMeshComponent* Mesh;
  2. Using the UPROPERTY() macro ensures that the object declared in the pointer is considered to be referenced, and won't be garbage-collected (that is, deleted) out from under us, leaving the pointer dangling.
  3. We're using a Static Mesh component, but any of the Actor Component subclasses would work. Note the asterisk is connected to the variable type in accordance with Epic's style guide.
  4. In the constructor, we initialize the pointer to a known valid value by using a template function, template<class TReturnType> TReturnType* CreateDefaultSubobject(FName SubobjectName, bool bTransient = false).
  5. This function is responsible for calling the engine code to appropriately initialize the component, and return a pointer to the newly constructed object so that we can give our component pointer a default value. This is important, obviously, to ensure that the pointer has a valid value at all times, minimizing the risk of dereferencing uninitialized memory.
  6. The function is templated based on the type of object to create, but also takes two parameters—the first one is the name of the subobject, which ideally should be human-readable, and the second is whether the object should be transient (that is—not saved along with the parent object).

See also

  • The following recipe shows you how to reference a mesh asset in your Static Mesh Component so that it can be displayed without requiring a user to specify a mesh in the Editor
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.146.37.150