For the past month or so, I have been having trouble generating objects at runtime such that they have a variable assigned mesh, depending on a randomly generated value.
I am thinking that the issue arises because the mesh and material are not explicitly assigned in the constructor, they are simply not generating, and the resultant objects are invisible.
Because these obstacles are generated at runtime from a “spawner” object, I am thinking that maybe I can modify the *.h file and the constructor in the *.cpp file to pass an argument to the obstacle’s constructor, so it knows which mesh to assign upon instantiation.
I just want to run this by the community before I go for it, so I don’t wind up screwing up my project horribly.
Here is what I plan to do in the *.h file.
UCLASS()
class SCREECHTEST_API AFenceObstacle : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AFenceObstacle(int HeightMarker);
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
//Set a component to check for collisions
UPROPERTY(VisibleAnywhere)
UBoxComponent* BoxComponent;
//Create a visible mesh so we can see the fence
UPROPERTY(VisibleAnywhere)
UStaticMeshComponent* VisibleMesh;
//Create a material reference for the mesh
UPROPERTY(VisibleAnywhere)
UMaterialInstanceDynamic* MaterialInstance;
//Obstacle speed - MUST BE UPDATED REGULARLY FROM SPAWNER
float ObstacleSpeed;
};
And in the *.cpp file:
AFenceObstacle::AFenceObstacle(int HeightMarker)
{
// 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;
//Create a visible mesh for the fence. CreateDefaultSubobject cannot be called outside of constructors
VisibleMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("VisibleMesh"));
if (VisibleMesh) {
VisibleMesh->SetupAttachment(GetRootComponent());
}
if (HeightMarker > 0 && HeightMarker < 9) {
//Assign the appropriate mesh to the fence based on the assigned HeightMarker
auto const Path = FString::Printf(TEXT("/Game/Meshes/sm_obstacle_fence_size_%i.sm_obstacle_fence_size_%i"), HeightMarker, HeightMarker);
auto Mesh = LoadObject<UStaticMesh>(nullptr, TEXT("FenceMesh"), *Path);
if (Mesh) {
VisibleMesh->SetStaticMesh(Mesh);
static ConstructorHelpers::FObjectFinder<UMaterial>Material(TEXT("'/Game/Materials/MaterialWood.MaterialWood'"));
if (Material.Succeeded()) {
MaterialInstance = UMaterialInstanceDynamic::Create(Material.Object, VisibleMesh);
}
VisibleMesh->SetMaterial(0, MaterialInstance);
//DEBUG
VisibleMesh->SetRelativeScale3D(FVector(10.0, 10.0, 10.0));
//GUBED
}
}
else {
//If an erroneous HeightMarker value was assigned, show that in a debug message
check(GEngine != nullptr);
//Display a debug message for five seconds
//The -1 "Key" vale argument prevents the message from being updated or refreshed.
auto const err_msg = FString::Printf(TEXT("AssignMesh: Invalid fence height value: %i"), HeightMarker);
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Red, err_msg);
}
//Create the box component for collisions
BoxComponent = CreateDefaultSubobject<UBoxComponent>(TEXT("CollisionBox"));
check(BoxComponent != nullptr);
}