[SOLVED] Child C++ Class UStaticMeshComponent not Assigning StaticMesh

I’ve been attempting to learn C++ over blueprints because I’ve known C++ for a while now and my peers have suggested it over blueprints. Currently, I have a parent class BaseGun which has some basic assignment properties for when I need more than one type of weapon. I also have a child class Rifle which is meant to be the first instance of a weapon in the game.

Using some constructors I am trying to assign some basic values for use later as well as the UStaticMeshComponent. After some research it appeared ConstructorHelpers::FObjectFinder was the best option however despite loading the directory to the static mesh I have it doesn’t load in the editor. I can assign the static mesh just fine in the editor, but I want to have it in the constructor of the class in case I need to make multiple instances of the gun.

BaseGun.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BaseGun.generated.h"

UCLASS()
class GROUNDUP_API ABaseGun : public AActor
{
	GENERATED_BODY()
	
...

public:
	virtual void Tick(float DeltaTime) override;

	void SetMBD(float value);
	float GetMBD();
	void SetDmg(float value);
	float GetDmg();
	void SetFR(float value);
	float GetFR();

	void SetMC(UStaticMeshComponent* mesh);

private:
	float MaxBulletDistance;
	float Damage;
	float FireRate;

	UPROPERTY(EditAnywhere)
		UStaticMeshComponent* MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("GunMesh"));
};

BaseGun.cpp

#include "BaseGun.h"

ABaseGun::ABaseGun()
{
	PrimaryActorTick.bCanEverTick = true;

}

...

void ABaseGun::SetMBD(float value) {
	MaxBulletDistance = value;
}
float ABaseGun::GetMBD() {
	return MaxBulletDistance;
}
void ABaseGun::SetDmg(float value) {
	Damage = value;
}
float ABaseGun::GetDmg() {
	return Damage;
}
void ABaseGun::SetFR(float value) {
	FireRate = value;
}
float ABaseGun::GetFR() {
	return FireRate;
}

void ABaseGun::SetMC(UStaticMeshComponent* mesh) {
	MeshComponent = mesh;
}

Rifle.h

#pragma once

#include "CoreMinimal.h"
#include "BaseGun.h"
#include "Rifle.generated.h"

UCLASS()
class GROUNDUP_API ARifle : public ABaseGun
{
	GENERATED_BODY()
public:
	ARifle();
protected:
	virtual void BeginPlay() override;
};

Rifle.cpp

#include "Rifle.h"

ARifle::ARifle()
{
	ARifle::SetMBD(5000.0);
	ARifle::SetDmg(2.0);
	ARifle::SetFR(0.1);

	static ConstructorHelpers::FObjectFinder<UStaticMeshComponent> Mesh(TEXT("GroundUp/Content/Models/Rifle/rifle"));
	ARifle::SetMC(Mesh.Object);
}

I think you need to add “/Game/” to your paths. So it would be “/Game/GroundUp/Content…” for you. But FWIW, I used to do this but now I just Use a UStaticMeshComponent* UPROPERTY in my C++ classes and just set the meshes or anything dynamic in via a corresponding blueprint. Ie If i were you
I would have a BP_Rifle blueprint which has the rifle modle set in it via the editor. I find that this is more flexible and easier to work with.

1 Like

Yeah, I suggest what @bluffdog mentions as well. It’s best to not hardcode asset paths in C++ code and instead setup a child BP class to assign/tweak visuals.

1 Like

I attempted to use the blueprint method of assigning the properties as you suggested and the FPS C++ example shows, however I’ve encountered a few issues.

In my cpp file for my BaseGun I attempted to create the default subobject and attach it to the RootComponent however this proved to crash my engine after every start as it said it already existed. I already tried to not attach it to the RootComponent and only use CreateDefaultSubobject but this didn’t remove the error.

I left only the header declaration for the variable hoping it would still be assignable, however when I derived a blueprint class from the C++ class Rifle I could see it had a mesh component however shows up in the BP as a variable but does not allow me to edit it.

Photo of BP_Rifle

BaseGun.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BaseGun.generated.h"

//class UStaticMeshComponent;

UCLASS()
class GROUNDUP_API ABaseGun : public AActor
{
	GENERATED_BODY()

	UPROPERTY(VisibleDefaultsOnly, Category = Mesh)
	UStaticMeshComponent* GunMesh;
	
public:	
	// Sets default values for this actor's properties
	ABaseGun();

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

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

	void SetMBD(float value);
	float GetMBD();
	void SetDmg(float value);
	float GetDmg();
	void SetFR(float value);
	float GetFR();

private:
	float MaxBulletDistance;
	float Damage;
	float FireRate;

	UStaticMeshComponent* MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("GunMesh"));
};

BaseGun.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "BaseGun.h"

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

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

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

}

void ABaseGun::SetMBD(float value) {
	MaxBulletDistance = value;
}
float ABaseGun::GetMBD() {
	return MaxBulletDistance;
}
void ABaseGun::SetDmg(float value) {
	Damage = value;
}
float ABaseGun::GetDmg() {
	return Damage;
}
void ABaseGun::SetFR(float value) {
	FireRate = value;
}
float ABaseGun::GetFR() {
	return FireRate;
}

Rifle.h and Rifle.cpp have no code bodies at the moment

Were you able to compile this project with BaseGun.h and BaseGun.cpp as they are? In the header file you commented-out the forward declaration of UStaticMeshComponent. You need to forward declare it. In the cpp file you didn’t include the header file for UStaticMeshComponent, which is

#include "Components/StaticMeshComponent.h"
1 Like

You should be calling CreateDefaultSubobject from the constructor, not within the header file (I’m surprised if that even compiles). For example, your header should have:

public:
    UPROPERTY(EditAnywhere)
    class UStaticMeshComponent* MeshComponent;

And then in the constructor:

ABaseGun::ABaseGun()
{
    MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("GunMesh"));
    SetRootComponent(MeshComponent);
    PrimaryActorTick.bCanEverTick = true;
}

You can then create a Blueprint inheriting from ABaseGun in the editor and set the static mesh for your static mesh component there.

2 Likes

What is ARifle::SetMC function?

On your Rifle class, you need to make a UStaticMeshComponent then use CreateDefaultSubobject on cpp.

Rifle.h

public:
ARifle();
UStaticMeshComponent* RifleMeshComponent;

Rifle.cpp

ARifle::ARifle()
{
//TEXT("RifleMesh") is the display name in the editor.
RifleMeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("RifleMesh"));
//TEXT("StaticMesh'/Game/Geometry/Meshes/1M_Cube.1M_Cube'") reference can be obtained by right click the object you wanted, and click "Copy Reference"
RifleMeshComponent->SetStaticMesh(ConstructorHelpers::FObjectFinder<UStaticMesh>(TEXT("StaticMesh'/Game/Geometry/Meshes/1M_Cube.1M_Cube'")).Object);
}

To use ConstructorHelpers, remember to include UObject/ConstructorHelpers.h.
To make the static mesh component editable in blueprint, add UPROPERTY().

UPROPERTY(EditAnywhere)
UStaticMeshComponent* RifleMeshComponent;
1 Like

BaseGun::SetMC(UStaticMeshComponent) was an archaic method I designed to attempt to assign the mesh for its children classes. It has since been deleted as my most recent reply implies.

Do I really have to create a UStaticMeshComponent for each class? My original intention was to have UStaticMeshComponent be created in BaseGun, inherited by the children of that class and then assigned in their respective code/blueprint.

Once I get home I will try and implement the fix with the header file @Marius557 said and the location of the declaration @LivelyGeek said. Didn’t realize I commented the header out.

Of course no, UStaticMeshComponent in BaseGun will always be inherited.

1 Like

I could have sworn it compiled this morning however it didn’t when I got home so maybe I’m mistaken.

@LivelyGeek worked like a charm. Called it from the Rifle.cpp though considering my implementation. @Marius557 included it in BaseGun.h instead of the BaseGun.cpp and it worked perfect just like you said (obviously because BaseGun.cpp includes BaseGun.h)