> For the complete documentation index, see [llms.txt](https://docs.nrnagents.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nrnagents.ai/getting-started/unreal-code-examples.md).

# Unreal Code Examples

Basic Integration

{% tabs %}
{% tab title="First Tab" %}

```cpp
void PlayerController::BeginPlay()
{
    Super::BeginPlay();
    	
    World = NewObject<UARCWorld>(this);
    ARCActionSpace = NewObject<UARCActionSpace>(this);
    ARCStateSpace = NewObject<UARCStateSpace>(this);

    Model = UARCBPLibrary::LoadModel(ModelConfig, false);
}

void PlayerController::Tick(float Delta)
{
    Super::Tick(Delta);

    // Create the world representation which we will convert to the state space matrix
    World->InitializeWorld(
        // All world attributes/objects that are relevant for the AI
    );
    
    // Get the state space for the model
    TArray<double> State = ARCStateSpace->GetState(*World);
    
    if (human)
    {
        // Convert the inputs into something the ARC agent can understand
        TMap<FString, bool> Action = ARCActionSpace->ConvertInputToBools(*World);
        
        // Add the observed state and action to the dataset
        Model->Collect(State, Action);
    } else {
        // If ARC agent is controlling, then perform inference
        auto ModelAction = UARCBPLibrary::SelectAction(Model,State);
        
        // Execute the action in-game
        auto Action = ARCActionSpace->ConvertActions(ModelAction);    
    }
}
```

Then at the end of the game, you can send the data you collected to the trainer platform as follows:

```csharp
Model->UploadData();
```

OR

If you have the API access to train in-game, then you can directly train within the game loop as follows:

```csharp
Model->Train();
```

{% endtab %}
{% endtabs %}

State Space

{% tabs %}
{% tab title="First Tab" %}
First we will create the header file

```c
#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "ARCStateSpace.generated.h"

class Pawn;

UCLASS(Blueprintable)
class UARCWorld : public UObject
{
    GENERATED_BODY()

public:
    UARCWorld(const FObjectInitializer& ObjectInitializer);

    TObjectPtr<APawn> LeftPaddlePawn;
    TObjectPtr<AActor> BallActor;

    void InitializeWorld(TObjectPtr<APawn> InLeftPaddlePawn, TObjectPtr<AActor> InBallActor)
    {
        LeftPaddlePawn = InLeftPaddlePawn;
        BallActor = InBallActor;
    }
};

UCLASS(Blueprintable)
class UARCStateSpace : public UObject
{
    GENERATED_BODY()

public:
    UARCStateSpace(const FObjectInitializer& ObjectInitializer);
    static TArray<double> GetState(const UARCWorld& World);
private:
    double Bound(double x);
};
```

Then we will create the C++ file

```cpp
#pragma once

#include "ARCStateSpace.h"

UARCWorld::UARCWorld(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
}

UARCStateSpace::UARCStateSpace(const FObjectInitializer& ObjectInitializer)
    : Super(ObjectInitializer)
{
}

TArray<double> UARCStateSpace::GetState(const UARCWorld& World)
{
    const double GameAreaHeight = 8.0;
    const double GameAreaWidth = 16.0;

    double LeftPaddleY = World.LeftPaddlePawn->GetActorLocation().Y;
    double BallY = World.BallActor->GetActorLocation().Y;
    double BallX = World.BallActor->GetActorLocation().X;
    FVector BallVel = World.BallActor->GetVelocity();
    
    double AbsolutePaddlePos = (LeftPaddleY / GameAreaHeight) * 2.0;
    double YDist = (BallY - LeftPaddleY) / GameAreaHeight;
    double XDist = Bound((-BallX / GameAreaWidth) * 2.0);
    double XVel = Bound(BallVel.X / 8.0);
    double YVel = Bound(BallVel.Y / 8.0);

    return { AbsolutePaddlePos, YDist, XDist, XVel, YVel };
}

double UARCStateSpace::Bound(double x)
{
    return FMath::Clamp(x, -1.0, 1.0);
}
```

{% endtab %}
{% endtabs %}

Action space

{% tabs %}
{% tab title="First Tab" %}
First we will create the header file

```c
#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "ARCStateSpace.h"
#include "ARCActionSpace.generated.h"

UCLASS(Blueprintable)
class UARCActionSpace : public UObject
{
    GENERATED_BODY()

public:
    UARCActionSpace(const FObjectInitializer& ObjectInitializer);
    TMap<FString, bool> ConvertInputToBools(const UARCWorld& World);
    FVector ConvertActions(TMap<FString, bool> Action);
};
```

Then we will create the C++ file

```cpp
#pragma once

#include "ARCActionSpace.h"

UARCActionSpace::UARCActionSpace(const FObjectInitializer& ObjectInitializer)
{
}

FVector UARCActionSpace::ConvertActions(TMap<FString, bool> Action)
{
    FVector MovementInput = FVector::ZeroVector;
    if (actions["up"])
    {
        MovementInput = FVector(0.0f, 1.0f, 0.0f);
    }
    else if (actions["down"])
    {
        MovementInput = FVector(0.0f, -1.0f, 0.0f);
    }
    return MovementInput;
}

TMap<FString, bool> UARCActionSpace::ConvertInputToBools(const UARCWorld& World)
{
    TMap<FString, bool> Action;
    FVector PaddleVelocity = World.LeftPaddlePawn->GetVelocity();

    Action.Add("up", PaddleVelocity.Y > 0.0f);
    Action.Add("down", PaddleVelocity.Y < 0.0f);
    Action.Add("idle", PaddleVelocity.Y == 0.0f);

    return Action;
}
```

{% endtab %}
{% endtabs %}

Data Collection

```cpp
Model->Collect(State, Action);
```

```cpp
Model->SetCollectionInterval(15); // Collect every 15 frames
```

Model Initialization

```cpp
ModelConfig.ArchitectureId = "my-first-model";
ModelConfig.UserId = "user-id";
ModelConfig.SlotIdx = 0;

Model = UARCBPLibrary::CreateModel(ModelConfig);
```

Inference

<pre class="language-cpp"><code class="lang-cpp"><strong>auto Action = UARCBPLibrary::SelectAction(Model, State);
</strong>
// Sample from the distribution to select an action
auto Probabilities = UARCBPLibrary::GetProbabilities(Model, State);
</code></pre>
