Download

Why didn't I need to #include for UStaticMeshComponent* etc anymore?

Ok so in the past I tried to learn Unreal Engine (about a year ago or so) and I had learned about the IWYU header practice adopted by Unreal. To be honest at the time, it confused me a lot and I ran into double declaration problems or similar and gave up.

I am back to try learn again :smiley: But this time I was ready for doing the headers (I think!). However, in my first test I write this class and it appears I do not need to #include for the static mesh. (my pointer declaration named “cube_mesh” This code appears to me to run and function perfectly well without the #include

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Contestant.generated.h"

UCLASS()
class SMASHTV_API AContestant : public ACharacter
{
	GENERATED_BODY()

public:
	// Sets default values for this character's properties
	AContestant();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	
	

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	void MoveForward (float AxisValue);
	void MoveRight(float AxisValue);
	void MoveTurn(float AxisValue);

	UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
		UStaticMeshComponent* cube_mesh;

};


and the cpp…



#include "Contestant.h"

// Sets default values
AContestant::AContestant()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	cube_mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("cubemesh"));

	cube_mesh->SetupAttachment(GetMesh());

}

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

void AContestant::MoveForward(float AxisValue)
{
	
	if((Controller != nullptr) && (AxisValue != 0.0f))
	{
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator Yaw(0, Rotation.Yaw, 0);

		const FVector Direction = FRotationMatrix(Yaw).GetUnitAxis(EAxis::X);
		AddMovementInput(Direction, AxisValue);
	}
}

void AContestant::MoveRight(float AxisValue)
{
	if((Controller != nullptr) && (AxisValue != 0.0f))
	{
		const FRotator Rotation = Controller->GetControlRotation();
		const FRotator Yaw(0, Rotation.Yaw, 0);

		const FVector Direction = FRotationMatrix(Yaw).GetUnitAxis(EAxis::Y);
		AddMovementInput(Direction, AxisValue);
	}
}

void AContestant::MoveTurn(float AxisValue)
{
}

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

}

// Called to bind functionality to input
void AContestant::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis("Vertical", this, &AContestant::MoveForward);
	PlayerInputComponent->BindAxis("Horizontal", this, &AContestant::MoveRight);

}


There are usually two possible explanations for this:

The simple one is that it’s being included indirectly because it’s included by something you are including.

The more complicated explanation involves the unity build (nothing to do with Unity the engine :wink: ) which doesn’t build source directly, but combines cpp files into larger cpp and compiles those instead. Some of the reasons for this include build time, link time and other optimizations during compilation. The downside is that it can really mess with your builds because it’s an automated process. You can be building just fine, edit A.cpp and suddenly B.cpp will have a compile error because of a missing include because B was getting one of it’s includes from another cpp in the unity source file but B is now in a different unity file or it’s been re-ordered!

Ultimately, if it compiles you don’t really have to worry about it. If you add includes for IWYU pre-emptively it doesn’t matter since everything is "#pragma once"d and including the same thing from different places won’t matter. If you don’t include a header and don’t get a compile error, there’s no real harm, you may just have to include it later when you get a mysterious compile error about using an unknown type. If this is a solo project, you’re probably fine with the latter. In a team environment I recommend an automated build process that builds the project with the unity option disabled, so like a more conventional C++ program. I think I saw a GDC talk from the Fortnite team and they were doing this as well (which made me feel good for advocating for it at work before seeing that video).

1 Like

Thanks this is very helpful info for me. The ‘build process’ is still somewhat black magic to me at the moment, but it is something I intend to study more very soon.

The build process is basically 25 years of black magic compressed together like a diamond. But a lot less pretty.

1 Like