Skip to content
This repository has been archived by the owner on Oct 19, 2020. It is now read-only.

Actors and components

pixeltris edited this page Jun 3, 2019 · 9 revisions

This covers the basics of using AActor and UActorComponent

Enabling tick

The properties AActor.PrimaryActorTick / UActorComponent.PrimaryComponentTick are used to control the ticking functionality of actors and components. These properties are of type FTickFunction which is a struct (essentially a pointer to the C++ FTickFunction).

Enabling AActor tick:

[UClass]
class ATickTest1 : AActor
{
    public override void Initialize(FObjectInitializer initializer)
    {
        base.Initialize(initializer);
        PrimaryActorTick.SetStartWithTickEnabled(true);
        PrimaryActorTick.SetCanEverTick(true);
    }

    protected override void ReceiveTick_Implementation(float DeltaSeconds)
    {
        base.ReceiveTick_Implementation(DeltaSeconds);
    }
}

Enabling UActorComponent tick:

[UClass]
class UTickTest2 : UActorComponent
{
    public override void Initialize(FObjectInitializer initializer)
    {
        base.Initialize(initializer);
        PrimaryComponentTick.SetStartWithTickEnabled(true);
        PrimaryComponentTick.SetCanEverTick(true);
    }

    protected override void ReceiveTick_Implementation(float DeltaSeconds)
    {
        base.ReceiveTick_Implementation(DeltaSeconds);
    }
}

It's best to enable tick in the Initialize function as the ticker is registered with the engine tickers just before the C# BeginPlay function is called. If you need to enable the ticker in BeginPlay you may need to manually register the ticker via FTickFunction.RegisterTickFunction.

Adding components to an AActor

This is an example of adding a UStaticMeshComponent as the RootComponent and then attaching a UTextRendererComponent.

[UClass]
class ATestActor : AActor
{
    [UProperty, EditAnywhere, BlueprintReadWrite]
    public UStaticMeshComponent Mesh { get; set; }

    [UProperty, EditAnywhere, BlueprintReadWrite]
    public UTextRenderComponent TextRenderer { get; set; }

    public override void Initialize(FObjectInitializer initializer)
    {
        UStaticMesh cubeMesh = ConstructorHelpers.FObjectFinder<UStaticMesh>.Find("StaticMesh'/Engine/BasicShapes/Cube.Cube'");
        if (cubeMesh != null)
        {
            Mesh = initializer.CreateDefaultSubobject<UStaticMeshComponent>(this, (FName)"Mesh");
            Mesh.SetStaticMesh(cubeMesh);
            RootComponent = Mesh;

            TextRenderer = initializer.CreateDefaultSubobject<UTextRenderComponent>(this, (FName)"TextRenderer");
            TextRenderer.SetupAttachment(Mesh);
            using (FText text = FText.FromString("Text component test"))
            {
                TextRenderer.SetText(text);
            }
        }
    }
}

Spawning an AActor and adding components at runtime

This is an example of spawning an AActor and adding a UStaticMeshComponent at runtime in the BeginPlay function of a AGameMode defined type.

[UClass]
class ATestGameMode : AGameMode
{
    protected override void BeginPlay()
    {
        base.BeginPlay();

        UStaticMesh cubeMesh = ConstructorHelpers.FObjectFinder<UStaticMesh>.Find("StaticMesh'/Engine/BasicShapes/Cube.Cube'");
        if (cubeMesh != null)
        {
            AActor actor = World.SpawnActor<AActor>(default(FVector), default(FRotator));
            UStaticMeshComponent meshComponent = NewObject<UStaticMeshComponent>(actor, (FName)"Mesh");
            meshComponent.SetStaticMesh(cubeMesh);
            meshComponent.RegisterComponent();
            actor.RootComponent = meshComponent;
        }
    }
}

Exposing components

By default components wont show up in the "Add Component" list in the editor. To enable this add the [BlueprintSpawnableComponent] attribute.

[UClass, BlueprintSpawnableComponent]
class UTestComponent : UActorComponent
{
}

Finding actors / components

This finds all actors of type ASomeActor in the world, then finds all mesh components on those actors and disables the renderer.

[UClass]
class AFindActorsTest : AActor
{
    protected override void BeginPlay()
    {
        base.BeginPlay();
        ASomeActor[] actors = UGameplayStatics.GetAllActorsOfClass<ASomeActor>(this);
        foreach (ASomeActor actor in actors)
        {
            UStaticMeshComponent[] components = actor.GetComponentsByClass<UStaticMeshComponent>();
            foreach (UStaticMeshComponent component in components)
            {
                component.SetHiddenInGame(true);
            }
        }
    }
}

Binding input

The most common way of handling input is the SetupPlayerInputComponent function of a ACharacter derived class.

[UClass]
class AInputTestCharacter : ACharacter
{
    protected override void SetupPlayerInputComponent(UInputComponent playerInputComponent)
    {
        base.SetupPlayerInputComponent(playerInputComponent);

        // Set-up "Trigger" in the input bindings in the editor.
        playerInputComponent.BindAction("Trigger", EInputEventType.Pressed, OnTrigger);
    }

    // Must be marked as a [UFunction] so that the engine can call this function when the button is pressed
    [UFunction]
    private void OnTrigger()
    {
        PrintString("OnTrigger", FLinearColor.Red);
    }
}

It's also possible to handle input on any AActor instance by enabling input for that actor and then binding the inputs. The following shows an example of explicitly binding the 'C' keyboard key, and allowing that input event to also be handled elsewhere by disabling ConsumeInput.

[UClass]
class AInputTestActor : AActor
{
    protected override void BeginPlay()
    {
        base.BeginPlay();

        APlayerController playerController = World.GetFirstPlayerController();
        if (playerController != null)
        {
            EnableInput(playerController);// This will create InputComponent (if not already created)
            FInputKeyBindingHandle handle = InputComponent.BindKey(EKeys.C, EInputEventType.Pressed, CPressed);
            handle.ConsumeInput = false;
        }
    }

    [UFunction]
    void CPressed()
    {
        World.PrintString(GetFullName(), FLinearColor.Red);
    }
}