Blueprint and C++

Hello. Help a newbie. In a new C++ project I’m creating a character called Cube.

ACube::ACube()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you dont need it.
	PrimaryActorTick.bCanEverTick = true;

	static ConstructorHelpers::FObjectFinder<UStaticMesh>C(TEXT("StaticMesh'/Game/StarterContent/Shapes/Shape_Cube.Shape_Cube'"));

	UStaticMeshComponent* Cube = CreateDefaultSubobject<UStaticMeshComponent>("Cube");
	Cube->SetupAttachment(RootComponent);
	Cube->SetStaticMesh(C.Object);
}

Then I create a Blueprint Class.

I open Blueprint and write the following code.

1

I don’t see a message on my screen.
Blueprint is not working in this case or am I doing something wrong?

You need to place the actor in the world and either press play or simulate for it’s tick to be called.

1 Like

It is because there were no instance in any of your game world at all.

1 Like

I have a cube on the stage and I press the Play button

I made a project showing both c++ and blueprint tick

CubeProj.zip (3.1 MB)


.h

#pragma once

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

UCLASS()
class CUBEPROJ_API ACube : public AActor
{
	GENERATED_BODY()
	
public:	

	ACube();

protected:

	virtual void BeginPlay() override;

public:	

	virtual void Tick(float DeltaTime) override;

	UFUNCTION(BlueprintCallable)
	void ShowMessage(FString Message, FColor Color, int32 key);
};

.cpp

#include "Cube.h"

// Sets default values
ACube::ACube()
{
	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you dont need it.
	PrimaryActorTick.bCanEverTick = true;

	static ConstructorHelpers::FObjectFinder<UStaticMesh>C(TEXT("StaticMesh'/Game/Shapes/1M_Cube_Chamfer.1M_Cube_Chamfer'"));

	UStaticMeshComponent* Cube = CreateDefaultSubobject<UStaticMeshComponent>("Cube");
	Cube->SetupAttachment(RootComponent);
	Cube->SetStaticMesh(C.Object);
}

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

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

	// C++ version of tick
	FString m = "Cube is ticking from c++ Delta :" + FString::SanitizeFloat(DeltaTime);
	ShowMessage(m, FColor::Orange,2);
	
}


void ACube::ShowMessage(FString Message, FColor Color, int32 key) 
{
	if (GEngine) {
		GEngine->AddOnScreenDebugMessage(key, 1, Color, Message);
	}
}
1 Like

Thank you friend, you spent a lot of time on me.
I figured it out a little, I have to put the Blueprint version of the Cube on stage then only the Blueprint works. So the question is closed and I have another question.
I created a variable in blueprint.

Can I access this variable in C++?

GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, FString::SanitizeFloat(Var));

You can access blueprint variables but it’s very tedious and counterproductive

I would highly suggest making a c++ base class with the variable as a UPROPERTY and then deriving from that class.

Or alternatively you could have a getter and setter function that is a BlueprintImplementableEvent (it calls blueprints from c++)

example

UFUNCTION(BlueprintImplementableEvent,BlueprintCallable)
void SetVar(float passedVariable);

UFUNCTION(BlueprintImplementableEvent,BlueprintCallable)
float GetVar();

Then from within the blueprint derived from the function you could set a blueprint variable or retrieve it by implementing the functions (they will show up to be implemented in the functions section on the left side inside of the blueprint).

This way is less susceptible to breaking if you change the variable from within blueprints.

1 Like

Thanks I got it. Now the most important question.
I display the message once.

In C++ code I create another cube

void ACube::BeginPlay()
{
	Super::BeginPlay();
	
	GetWorld()->SpawnActor<ACube>(FVector(15.f, 150.f, 70.f), FRotator(0.f));
}

At startup I have two cubes on the stage, and the message is displayed once. In the second cube Blueprint does not work. Can I create a Blueprint version of the second cube so that Blueprint can work in it too?

You shouldn’t be spawning the cube at begin play of the same class. You will cause the engine to run a recurring function, each following cube will spawn a next one causing the engine to lock up.

If you want to spawn a specific class derived from a class then you can use TSubclassOf

in the case of the cube you would use

UPROPERTY(BlueprintReadWrite,EditAnywhere)
TSubclassOf<ACube>  CubeBP;

sub

Then you can pass in the blueprint variation of the class.
Note: This does not let you access the bp’s variables created via blueprints though only the c++ ones.

1 Like

I don’t understand. How should I use TSubclassOf?
What should I do with CubeBP?

TSubclassOf lets you assign a blueprint inside of c++ if you need it.

1 Like

I understood why this code does not block the engine for me. I have two cubes on the stage and it seems to work the way I want.

I need it, but I don’t understand how to do it. Can you give an example of the code, if it’s not difficult?

The TSubClassOf is just a way to spawn blueprint object variants of a c++ class from within c++. Normally you don’t have access to them directly.
If you expose a variable to the engine as TSubClassOf then you can pick the corresponding blueprint actor from within the engine.

Then you can modify if from withing c++ (at least the attributes that are exposed to the c++ class)

Normally there is a barrier between c++ and blueprints and this is a way to get around it :wink:

1 Like

I can write

ACube* CubeC = GetWorld()->SpawnActor<ACube>(FVector(100.f, 100.f, 70.f), FRotator(0.f));

And I can’t write like that

TSubclassOf<ACube> CubeBP = GetWorld()->SpawnActor<ACube>(FVector(100.f, 100.f, 70.f), FRotator(0.f));

So I don’t understand how to create it.

Where custom bp is based on AMyActor
in header

UPROPERTY(BlueprintReadWrite, EditAnywhere)
	TSubclassOf<AMyActor> myActor;

in cpp (at least at begin play or later)

FActorSpawnParameters Spawnparams;
FTransform SpawnTransform = FTransform(FRotator::ZeroRotator, FVector(10, 10, 10));
AMyActor * SpawnedBP = GetWorld()->SpawnActor<AMyActor>(myActor, SpawnTransform, Spawnparams);

It will spawn the blueprint version that you pass in the editor

the TSubclassOf hold the Class not the actor so treat is as you would a class.

1 Like

Thanks, everything works now.

.h

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "Cube.generated.h"

UCLASS()
class CUBEHEALTH_API ACube : public APawn
{
	GENERATED_BODY()

public:
	ACube();

	enum S
	{
		State1,
		State2,
		State3
	};
	S State;
}

Can I pass a State variable to Blueprint?

Move the enum above the uclass and make it a blueprit type

1 Like