Unreal Engine, from C++ spawn Blueprint inherited from C++ class, very small example: Difference between revisions

From Andreida
 
(19 intermediate revisions by the same user not shown)
Line 17: Line 17:
* File / Save Current Level as ... / Basic01
* File / Save Current Level as ... / Basic01
* Edit / Project Settings / Maps & Modes / Editor Startup Map: Basic01
* Edit / Project Settings / Maps & Modes / Editor Startup Map: Basic01
* Edit / Project Settings / Maps & Modes / Editor Game Default Map: Basic01
* Edit / Project Settings / Maps & Modes / Game Default Map: Basic01
* File / Save All


=== Create Classes ===
=== Create Classes ===
Line 43: Line 44:
public:
public:


AMiniActor();
AMiniActor();


protected:
protected:
Line 51: Line 52:
UPROPERTY(EditAnywhere, Category = "Structure", meta = (DisplayName = "Mesh"))
UPROPERTY(EditAnywhere, Category = "Structure", meta = (DisplayName = "Mesh"))
UStaticMesh* m_pMesh;
UStaticMesh* m_pMesh;

UPROPERTY(EditAnywhere, Category = "Structure", meta = (DisplayName = "Scene Component Root"))
USceneComponent* m_pScRoot;


UPROPERTY(EditAnywhere, Category = "Structure", meta = (DisplayName = "Static Mesh Component of Root"))
UPROPERTY(EditAnywhere, Category = "Structure", meta = (DisplayName = "Static Mesh Component of Root"))
Line 65: Line 63:


AMiniActor::AMiniActor()
AMiniActor::AMiniActor()
: m_pMesh(nullptr)
, m_pSmcRoot(nullptr)
{
{
m_pScRoot = CreateDefaultSubobject<USceneComponent>("Root");
RootComponent = CreateDefaultSubobject<USceneComponent>("Root");
RootComponent = m_pScRoot;


m_pSmcRoot = CreateDefaultSubobject<UStaticMeshComponent>("SmcRoot");
m_pSmcRoot = CreateDefaultSubobject<UStaticMeshComponent>("SmcRoot");

FAttachmentTransformRules transformRule = FAttachmentTransformRules::KeepRelativeTransform;
FAttachmentTransformRules transformRule = FAttachmentTransformRules::KeepRelativeTransform;
m_pSmcRoot->AttachToComponent(RootComponent, transformRule);
m_pSmcRoot->AttachToComponent(RootComponent, transformRule);
Line 91: Line 89:
===== Build =====
===== Build =====
Now build the project. Nothing works so don't even try to test it in the UE-Editor, but the code should compile and link. This is a class that is complete as it is.
Now build the project. Nothing works so don't even try to test it in the UE-Editor, but the code should compile and link. This is a class that is complete as it is.

===== Error 6 =====
If you want to build with Visual Studio and get something like
<pre>
Error MSB3073 The command "C:\ue\UE_5.3\[...]ShowActor.uproject" -WaitMutex -FromMsBuild" exited with code 6.
</pre>
then you can do this:
* UE-Editor
** Edit / Editor Preferences
*** Live Coding
**** Enable Live Coding: no
** File / Save All

Then build again.


==== class Nagtc ====
==== class Nagtc ====
Line 118: Line 130:
public:
public:


ANagtc();
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Generating Test Data", Meta = (DisplayName = "Number of Test objects"))
int32 m_nNumberOfTestObjects;

UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Generating Test Data", Meta = (DisplayName = "MiniActor Blueprint Class for Test 1"))
TSubclassOf<AMiniActor> m_MiniActorTest1;


static void test1(UWorld* pWorld);
static void test1(UWorld* pWorld);
Line 131: Line 139:


void test1();
void test1();

UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Generating Test Data", Meta = (DisplayName = "Number of Test objects"))
int32 m_nNumberOfTestObjects;

UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Generating Test Data", Meta = (DisplayName = "MiniActor Blueprint Class for Test 1"))
TSubclassOf<AMiniActor> m_MiniActorTest1;

static ANagtc* s_pNagtcInstance;
};
};
</pre>
</pre>
Line 139: Line 155:
#include "Engine/World.h"
#include "Engine/World.h"
#include "Kismet/GameplayStatics.h"
#include "Kismet/GameplayStatics.h"

ANagtc* ANagtc::s_pNagtcInstance = nullptr;

ANagtc::ANagtc(void)
: m_nNumberOfTestObjects(0)
, m_MiniActorTest1(nullptr)
{
/// empty
}


/// static
/// static
ANagtc*
void
ANagtc::test1(UWorld* pWorld)
ANagtc::getInstanceFromWorld(UWorld* pWorld)
{
{
if (pWorld == nullptr)
ANagtc* pNagtc = getInstanceFromWorld(pWorld);
return nullptr;
if (pNagtc)

if (s_pNagtcInstance != nullptr)
return s_pNagtcInstance;

TArray<AActor*> arrActorsToFind;
UGameplayStatics::GetAllActorsOfClass(pWorld, ANagtc::StaticClass(), arrActorsToFind);

if (arrActorsToFind.Num() == 1)
{
{
s_pNagtcInstance = Cast<ANagtc>(arrActorsToFind[0]);
pNagtc->test1();
return s_pNagtcInstance;
}
}

return nullptr;
}
}



void
void
Line 170: Line 207:
}
}


/// static
ANagtc*
void
ANagtc::getInstanceFromWorld(UWorld* pWorld)
ANagtc::test1(UWorld* pWorld)
{
{
ANagtc* pNagtc = getInstanceFromWorld(pWorld);
TArray<AActor*> arrActorsToFind;
if (pNagtc)
UGameplayStatics::GetAllActorsOfClass(pWorld, ANagtc::StaticClass(), arrActorsToFind);

if (arrActorsToFind.Num() == 1)
{
{
ANagtc* pNagtc = Cast<ANagtc>(arrActorsToFind[0]);
pNagtc->test1();
return pNagtc;
}
}

return nullptr;
}
}
</pre>
</pre>
Line 234: Line 267:


==== Set your GameMode as the used one ====
==== Set your GameMode as the used one ====
* WorldSetting / Game Mode / GameMode Override: MyGameMode
* (Window / ) WorldSettings / Game Mode / GameMode Override: MyGameMode

===== MyGameMode not in ComboBox =====
If you don't see "MyGameMode" in the ComboBox after "GameMode Override", then close the UE-Editor (not VS) and start again:
* ctrl-F5 in VS or
* double click the file "ShowActor.uproject" or
* open it with the Unreal Engine Launcher.


==== Create Blueprint from your C++ Actor MiniActor ====
==== Create Blueprint from your C++ Actor MiniActor ====
Line 245: Line 284:
* Mesh:
* Mesh:
** Show Engine Content
** Show Engine Content
** Cube, Static Mesh (100x100x100 not the 256x256x256)
** Cube, Static Mesh (Approx Size: 100x100x100 not the 256x256x256)
* Compile
* Compile
* Close
* Close
* File / Save All
* Save the Blueprint


==== Put Nagtc actor into the world ====
==== Put Nagtc actor into the world ====
Line 258: Line 297:


=== Test it all ===
=== Test it all ===
* File / Save all
* Change "PlayerStart" / Transform
* Change "PlayerStart" / Transform
** Location: -200 / 0 / 70
** Location: -200 / 0 / 100
** Rotation: 0 / 0 / 40
** Rotation: 0 / 0 / 40
* File / Save all
* Play the level
* Play the level
** Left click into the world and move your view around to see what you just created
** Left click into the world and move your view around to see what you just created

= back =
[[Unreal Engine|(back to Unreal Engine)]]

Latest revision as of 10:02, 9 May 2024

Prepare Project

Create Project

  • Games / Blank
    • C++
    • Desktop
    • Maximum
    • Starter Content: no
    • Raytracing: no
    • Location: your choice
    • Project Name: ShowActor
  • Create

Change Map to Basic

When the UE-Editor is open:

  • File / New Level / Basic / Create
  • File / Save Current Level as ... / Basic01
  • Edit / Project Settings / Maps & Modes / Editor Startup Map: Basic01
  • Edit / Project Settings / Maps & Modes / Game Default Map: Basic01
  • File / Save All

Create Classes

class MiniActor

This is the class from which we will create a blueprint which we will then spawn.

  • Tools / New C++ Class
    • Parent Class: Actor
    • Name: MiniActor
    • Create Class
Header File: MiniActor.h
#pragma once

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

UCLASS(Blueprintable)
class SHOWACTOR_API AMiniActor : public AActor
{
  GENERATED_BODY()
	
public:	

  AMiniActor();

protected:

  virtual void BeginPlay() override;

  UPROPERTY(EditAnywhere, Category = "Structure", meta = (DisplayName = "Mesh"))
  UStaticMesh* m_pMesh;

  UPROPERTY(EditAnywhere, Category = "Structure", meta = (DisplayName = "Static Mesh Component of Root"))
  UStaticMeshComponent* m_pSmcRoot;
};
Source File: MiniActor.cpp
#include "MiniActor.h"

AMiniActor::AMiniActor()
  : m_pMesh(nullptr)
  , m_pSmcRoot(nullptr)
{
  RootComponent = CreateDefaultSubobject<USceneComponent>("Root");

  m_pSmcRoot = CreateDefaultSubobject<UStaticMeshComponent>("SmcRoot");
  FAttachmentTransformRules transformRule = FAttachmentTransformRules::KeepRelativeTransform;
  m_pSmcRoot->AttachToComponent(RootComponent, transformRule);

  PrimaryActorTick.bCanEverTick = false;
}

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

  if (m_pMesh != nullptr)
  {
    m_pSmcRoot->SetStaticMesh(m_pMesh);
  }
}

Build

Now build the project. Nothing works so don't even try to test it in the UE-Editor, but the code should compile and link. This is a class that is complete as it is.

Error 6

If you want to build with Visual Studio and get something like

Error	MSB3073	The command "C:\ue\UE_5.3\[...]ShowActor.uproject" -WaitMutex -FromMsBuild" exited with code 6.	

then you can do this:

  • UE-Editor
    • Edit / Editor Preferences
      • Live Coding
        • Enable Live Coding: no
    • File / Save All

Then build again.

class Nagtc

We need "something" to tell UE what blueprint we want to spawn and how many. There are many places where you can do it. This is just an example.

  • Nagtc: (N)ot (a) (g)lobal (t)rash (c)an
  • Tools / New C++ Class
    • Parent Class: Actor
    • Name: Nagtc
    • Create Class
Header File: Nagtc.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MiniActor.h"
#include "Nagtc.generated.h"

UCLASS()
class SHOWACTOR_API ANagtc : public AActor
{
  GENERATED_BODY()
	
public:

  ANagtc();

  static void test1(UWorld* pWorld);

protected:

  static ANagtc* getInstanceFromWorld(UWorld* pWorld);

  void test1();

  UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Generating Test Data", Meta = (DisplayName = "Number of Test objects"))
  int32	m_nNumberOfTestObjects;

  UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Generating Test Data", Meta = (DisplayName = "MiniActor Blueprint Class for Test 1"))
  TSubclassOf<AMiniActor> m_MiniActorTest1;

  static ANagtc* s_pNagtcInstance;
};
Source File: Nagtc.cpp
#include "Nagtc.h"
#include "Engine/World.h"
#include "Kismet/GameplayStatics.h"

ANagtc* ANagtc::s_pNagtcInstance = nullptr;

ANagtc::ANagtc(void)
    : m_nNumberOfTestObjects(0)
    , m_MiniActorTest1(nullptr)
{
    /// empty
}

///  static
ANagtc*
ANagtc::getInstanceFromWorld(UWorld* pWorld)
{
  if (pWorld == nullptr)
    return nullptr;

  if (s_pNagtcInstance != nullptr)
    return s_pNagtcInstance;

  TArray<AActor*> arrActorsToFind;
  UGameplayStatics::GetAllActorsOfClass(pWorld, ANagtc::StaticClass(), arrActorsToFind);

  if (arrActorsToFind.Num() == 1)
  {
    s_pNagtcInstance = Cast<ANagtc>(arrActorsToFind[0]);
    return s_pNagtcInstance;
  }

  return nullptr;
}


void
ANagtc::test1()
{
  if (m_nNumberOfTestObjects > 0 && m_MiniActorTest1.Get() != nullptr)
  {
    double fX = 0;
    double fY = 0;
    double fZ = 0;
    for (int n = 0; n < m_nNumberOfTestObjects; ++n)
    {
      FVector locator(fX, fY, fZ);
      AActor* pActor = GetWorld()->SpawnActor(m_MiniActorTest1, &locator);

      fY += 100;
      fZ += 50;
    }
  }
}

///  static
void
ANagtc::test1(UWorld* pWorld)
{
  ANagtc* pNagtc = getInstanceFromWorld(pWorld);
  if (pNagtc)
  {
    pNagtc->test1();
  }
}
Build

Now build the project. Nothing works so don't even try to test it in the UE-Editor, but the code should compile and link. This is a class that is complete as it is, if you created MiniActor before.

class MyGameMode

  • Tools / New C++ Class
    • Parent Class: GameModeBase
    • Name: MyGameMode
    • Create Class
Header File: MyGameMode.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "MyGameMode.generated.h"

UCLASS()
class SHOWACTOR_API AMyGameMode : public AGameModeBase
{
  GENERATED_BODY()

public:

  virtual void  BeginPlay() override;
};
Source File: MyGameMode.cpp
#include "MyGameMode.h"
#include "Nagtc.h"

void
AMyGameMode::BeginPlay()
{
  Super::BeginPlay();
  ANagtc::test1(GetWorld());
}
Build

Now build the project. Nothing works so don't even try to test it in the UE-Editor, but the code should compile and link. This is a class that is complete as it is, if you created MiniActor and Nagtc before.

Configuring stuff inside the UE-Editor

Set your GameMode as the used one

  • (Window / ) WorldSettings / Game Mode / GameMode Override: MyGameMode
MyGameMode not in ComboBox

If you don't see "MyGameMode" in the ComboBox after "GameMode Override", then close the UE-Editor (not VS) and start again:

  • ctrl-F5 in VS or
  • double click the file "ShowActor.uproject" or
  • open it with the Unreal Engine Launcher.

Create Blueprint from your C++ Actor MiniActor

  • Content Browser / C++ Classes / MiniActor
    • Right-click / Create Blueprint class based on MiniActor
      • Name: BP_MyMiniActor

If the Blueprint is not already open, open it in the UE-Editor.

  • Mesh:
    • Show Engine Content
    • Cube, Static Mesh (Approx Size: 100x100x100 not the 256x256x256)
  • Compile
  • Close
  • File / Save All

Put Nagtc actor into the world

  • Content Browser / C++ / Nagtc
  • Drag Nagtc into the world
  • Select Nagtc in the Outliner (and switch back from "World Settings" to "Details")
    • Number of Test objects: 25
    • MiniActor Blueprint Class for Test 1: BP_MyMiniActor

Test it all

  • Change "PlayerStart" / Transform
    • Location: -200 / 0 / 100
    • Rotation: 0 / 0 / 40
  • File / Save all
  • Play the level
    • Left click into the world and move your view around to see what you just created

back

(back to Unreal Engine)