Udemy: Unreal Engine C The Ultimate Game Developer Course: Section 4 - jgoffeney/Cesium4Unreal GitHub Wiki

Back

Actors and Actor Components

Issue

The first step is trying to create a new C++ Actor class. If you try to add a new directory to the path and then create the class then the files will be inside the new directory but the rather than the .cpp file having #include "MyHeader.h" it has #include "NewDirectory/MyHeader.h" and a compile error occurs. Remove the extra directory and then it is fine.

Actor

An Actor object has BeginPlay() and Tick() functions. It is also automatically blueprintable because it inherits it from the Actor class.

Components

A Component is a UObject designed to be a sub-object within Actors. This allows parts of actors to be swapped to alter its functionality.

Scene Component

Each actor starts with a DefaultSceneRoot which is a scene component. It has a transform but not much else. The scene root is a container for the other components. The DefaultSceneRoot can't be deleted but it is easily replaced by dragging another component on to it (and not just another scene component). If the replacement component is deleted then it is replaced by a new DefaultSceneRoot. Essentially an actor is required to have a component with a transform to set translation, rotation and scale.

Primitive Component

Primitive components are actor components like meshes, colliders and audio.

Adding a new Component via C++

To give an actor a static mesh you add the following to the header to make the mesh available within the various Unreal systems.

UPROPERTY(VisibleAnywhere, Category="ActorMeshComponents")
UStaticMeshComponent* staticMesh;

Then in the source class constructor:

staticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CustomStaticMesh"));

Note when constructing Unreal objects you need to use special creation methods and not just new.

Position Vectors

This section was an introduction to the Transform property for meshes within editor.

The FVector

The FVector is a struct to hold an x/y/z value for working with the transform properties. But it also has many, many functions for performing vector operations. The F is because the vector type is float.

The following code uses the SetActorLocation() function to set the initial location of an object of AFloater to the origin.

void AFloater::BeginPlay()
{
	Super::BeginPlay();

	SetActorLocation(FVector(0.0f, 0.0f, 0.0f));
}

Note: As long as a C++ class is a subclass of Actor it can be dragged directly into a scene without being a Blueprint. However unless a mesh component has been added it will not be visible on play.

To make the initial location an editable value then add it to the header file as a public variable. The EditInstanceOnly parameter indicates changing the initial location value in the editor will only affect the object instance and not the default. If you create a blueprint from the C++ class then you can access the initial location via the event graph menu but not from the properties due to using BlueprintReadWrite and EditInstanceOnly, respectively.

// The vector to set the initial location on start up
UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category="FloaterVectors")
FVector initialLocation = FVector(0.0f);

This variable is used to store the location where it was set within the editor. The parameter VisibleInstanceOnly indicate you can see the property in the editor but can't change it.

// The vector to store the location when set in the editor
UPROPERTY(VisibleInstanceOnly, BlueprintReadWrite, Category = "FloaterVectors")
FVector placedLocation = FVector(0.0f);

To set the value of placedLocation the function GetActorLocation is called.

// Called when the game starts or when spawned
void AFloater::BeginPlay()
{
	Super::BeginPlay();

	placedLocation = GetActorLocation();

	SetActorLocation(initialLocation);
}

To set a variable only visible in the Blueprint version use the property EditDefaultsOnly. It will not appear on any of the instance details but will in the blueprint editor. Fun Fact: if you use a b to start a boolean variable name Unreal knows to automatically remove it when displaying the name in the editor.

// Do you want to enable initialize the object location
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "Floater Variables")
bool bInitializeFloaterLocations;

By wrapping the SetActorLocation() call with the boolean then initial location behavior is enabled and disabled for all blueprint instances within the blueprint editor. If false they remain at their editor placement and it true they are set to the provided location values.

This vector variable's property parameters indicate it is only visible within the blueprint as read only for the details and as a graph node. It is not visible on the blueprint instances in the scene.

UPROPERTY(VisibleDefaultsOnly, BlueprintReadOnly, Category = "Floater Variables")
FVector worldOrigin;

And this vector's values can be edited from the original blueprint or from the individual instances. If set in the blueprint then the value is the default for each instance (which can then be changed).

UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Floater Variables")
FVector initialDirection;

Intro to Collision

A mesh does not have a default collision volume. But if you open the mesh object in the editor there are menus for adding simple and/or complex collision where the latter uses the mesh itself. The former can be added in the collision menu as a type of primitive like a cube or sphere.

The collision section was editor based and did not have much in the way of C++ content except making the associated static mesh Blueprint accessible via the UPROPERTY.

Sweeping

When a sweep flag is set to true for an object then it causes the object to stop moving when it hits the first blocking volume. In our example the second parameter for AddActorLocalOffset is this flag.

// Called every frame
void AFloater::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (bShouldFloat) {
		FHitResult hitResult;
		AddActorLocalOffset(initialDirection, true, &hitResult);
	}

}

Note: when using the UE_LOG macro if you want to provide formatted values for TEXT then you include then afterwards and not within like a printf.

UE_LOG(LogTemp, Warning, TEXT("Hit Location: X = %f, Y = %f, Z = %f"), hitLocation.X, hitLocation.Y, hitLocation.Z);

If you want more control over collisions then you can go to an objects Details->Collision->Collision Presets and select Custom. This add an Object Type which lets you essentially set a default tag for what this object is detected as. It also adds a table of world object types to desired behaviors on collision (ignore, overlap or block). If object A is WorldStatic and object B is WorldDynamic then if either is set to ignore the other then they will pass through each other.

Local vs World Offset

The examples have used AddActorLocalOffset. Since it is a local offset it is relative to the local coordinate space of object. If the object does not have rotation then the local offset appears to be the same as it would be in world space. But if the object is rotated then the direction of the offset will also be rotated. The viewport has a button to switch between the local and world coordinate gizmo for a selected object. The function AddActorWorldOffset would ignore local rotations and just move with respect to the world grid.

Rotation

In addition to FVector for position there is FRotator for rotation which has pitch, yaw and roll variables. These are used with functions like AddActorLocalRotation and AddActorWorldRotation.

Force and Torque

The function AddForce can be used to apply an initial force to an object. It takes an FVector as input and by setting it as a UPROPERTY you can play with the vector values until you find the force you want.

To apply torque the functions AddTorqueInRadians and AddTorqueInDegrees exist. This applies a rotational force.

Random Numbers

The struct FMath is a container for many static Unreal math functions. The function FMath::FRand() will automatically return a float value in the range 0 to 1. The function FMath::FRandRange(float, float) will return a value between the input float values.

The Sine Function

FMath contains trigonometry functions and this section uses sine with amplitude, phase shift, period and vertical offset to make the actor bob up and down.

// Called every frame
void AFloater::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (bShouldFloat) {
		FVector newLocation = GetActorLocation();
		newLocation.Z = initialLocation.Z + + verticalShift +  FMath::Sin(period * _runningTime - phaseShift) * amplitude;

		SetActorLocation(newLocation);

		_runningTime += DeltaTime;
	}

}

Deleting Classes

This describes how to remove C++ classes from Unreal. To remove a Blueprint you can delete it and when the Delete Assets popup shows you can press Force Delete to remove any current references and get rid of the Blueprint. If you try to delete a C++ class then nothing happens. Instead you need to remove the files via Visual Studio (or delete the files directly along with the project Binaries directory).