guide for programmers


Writing game logic, triggers, input, raycasting and more.

Especially for those who are looking for an alternative to Unreal Engine or Unity, we continue a series of articles about a painless transition to UNIGINE from foreign engines. In the third issue, we will look at migration from Unreal Engine 4 from a programmer’s point of view.

general information

Game logic in a project on Unreal Engine 4 is implemented using classes C++ or Blueprint Visual Scripting — built-in visual node programming system. The Unreal Engine 4 editor allows you to create classes using the built-in Class Wizard by selecting the desired base type.

With UNIGINE you can create projects using the C++ and C# APIs. When creating a project, simply select the desired API and build system:

In this article, we will mainly touch on C++ programming, because full-fledged programming in Unreal Engine 4 is possible in this language.

For C++, you can choose from ready-made project templates for the following build systems:

Next, just select Open Code IDEto move on to developing logic in your chosen IDE for C++ projects:

In Unreal Engine 4, it is enough to inherit a class from the Game Framework base types, such as AActor, APawn, ACharacter, etc., to override their behavior in standard methods BeginPlay(), Tick() and EndPlay() and get the custom actor.

The component approach implies that the logic is implemented in custom components assigned to actors – classes inherited from UActorComponent and other components that extend the standard behavior defined in the methods InitializeComponent() and TickComponent().

In UNIGINE, the standard approach implies that application logic consists of three main components with different life cycles:

  • System logic (source file AppSystemLogic.cpp) exists for the lifetime of the application.

  • The logic of the world (source file AppWorldLogic.cpp) is only executed when the world is loaded.

  • Editor logic (source file AppEditorLogic.cpp) is executed only while the custom editor is running.

Every logic has standard methods, called in the main engine loop. For example, you can use the following world logic methods:

  • init() – to initialize resources when loading the world;

  • update() – to update every frame;

  • shutdown() – to destroy used resources when closing the world;

Keep in mind that the logic of the world is not tied to a specific world and will be called for any loaded world. However, you can split world-specific code between separate classes inherited from WorldLogic.

The component approach is also available in UNIGINE using the built-in component system. The component logic is defined in a class derived from ComponentBasebased on which the engine will generate a set of component parameters – property, which can be assigned to any node in the editor. Each component also has a set of methods that are called by the corresponding functions. main loop engine.

For an example of creating a simple game using a component system, see the article series “Quick Guide to Programming”.

Let’s compare how simple components are created in both engines. component header file Unreal Engine 4 will look something like this:

UCLASS()
class UMyComponent : public UActorComponent
{
    GENERATED_BODY()

public:
    UPROPERTY(EditAnywhere)
    int32 TotalDamage;


    // Called after the owning Actor was created
    void InitializeComponent();

    // Called when the component or the owning Actor is being destroyed
    void UninitializeComponent();

    // Component version of Tick
    void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction);
};

And in UNIGINE. The component system must first be initialized in the system logic (AppSystemLogic.cpp):

/* .. */
#include <UnigineComponentSystem.h>

/* .. */

int AppSystemLogic::init()
{
    Unigine::ComponentSystem::get()->initialize();
    return 1;
}

And then you can write a new component:

MyComponent.h:

#pragma once
#include <Unigine.h>
#include <UnigineComponentSystem.h>

using namespace Unigine;
class MyComponent : public ComponentBase
{
public:
    // объявление компонента MyComponent
    COMPONENT(MyComponent, ComponentBase);

    // объявление методов, вызываемых на определенных этапах цикла жизни компонента
    COMPONENT_INIT(init);
    COMPONENT_UPDATE(update);
    COMPONENT_SHUTDOWN(shutdown);

    // объявление параметра компонента, который будет доступен в редакторе
    PROP_PARAM(Float, speed, 30.0f);

    // определение имени Property, которое будет сгенерировано и ассоциировано с компонентом
    PROP_NAME("my_component");
protected:
    void init();
    void update();
    void shutdown();
};

MyComponent.cpp:

#include "MyComponent.h"

// регистрация компонента MyComponent
REGISTER_COMPONENT(MyComponent);

// вызов будет произведен при инициализации компонента
void MyComponent::init(){}

// будет вызван каждый кадр
void MyComponent::update(){}

// будет вызван при уничтожении компонента или ноды, которой он назначен
void MyComponent::shutdown(){}

Now we need to generate a property for our component. For this:

  1. Build the application using the IDE.

  2. Launch the application once to get the component property generated by the engine.

  3. Go to editor and appoint generated property node.

  4. Finally, the operation of the component’s logic can be tested by running the application.

To learn more about sequencing and how to create components, follow the links below:

A little about the API

All objects in Unreal Engine 4 inherit from UObject and can be accessed using standard C++ pointers or Unreal Smart Pointer Library smart pointers.

The UNIGINE API has smart pointer systemwhich control the existence of nodes and other objects in memory:

// создать ноду типа NodeType
<NodeType>Ptr nodename = <NodeType>::create(<construction_parameters>);
// удалить ноду из мира
nodename.deleteLater();

For example, this is how creating a mesh from an asset, editing it, assigning a new node of type ObjectMeshStatic and deleting it looks like:

    MeshPtr mesh = Mesh::create();
    mesh->load("fbx/model.fbx/model.mesh");
    mesh->addBoxSurface("box_surface", Math::vec3(0.5f, 0.5f, 0.5f));
    ObjectMeshStaticPtr my_object = ObjectMeshStatic::create(mesh);
    my_object.deleteLater();
    mesh.clear();

Instances of custom components, like any other classes, are stored using standard pointers:

MyComponent *my_component = getComponent<MyComponent>(node);

Data types

Data type

unreal engine four

UNIGINE

Numeric types

int8/uint8

int16/uint16

int32/uint32

int64/uint64,

float,

double

Standard C++ types:

signed and unsigned char, short, int, long, long long, float, double

Strings

Fstring:

FString MyStr = TEXT(“Hello, Unreal 4!”).

String:

String str(“Hello, UNIGINE 2!”);

Containers

TArray, TMap, TSet

Vector, Map, Set and more:

Vector nodes;

World::getNodes(nodes);

for(NodePtr n : nodes) { }

Vectors and matrices

FVector3f – FVector3d,

FMatrix44f – FMatrix44d and others

vec3-dvec3,

mat4 – dmat4 and other types in math library.

UNIGINE supports both single precision (Float) and double precision coordinates (Double), available depending on the SDK edition. Read about usage generic data typessuitable for any project.

Basic Code Examples

Console output

unreal engine four

UNIGINE

UE_LOG(LogTemp, Warning, TEXT("Your message"));

Log::message("Debug info: %s\n", text);

Log::message("Debug info: %d\n", number);

See also:

Loading a scene

unreal engine four

UNIGINE

UGameplayStatics::OpenLevel(GetWorld(), TEXT("MyLevelName"));

World::loadWorld("YourWorldName");

Accessing an Actor/Node from a Component

unreal engine four

UNIGINE

MyComponent->GetOwner();

NodePtr owning_node = node;