RoveSoSimulator

Autonomous Rover Testing Simulator in Unreal Engine 5

View the Project on GitHub MissouriMRDT/RoveSoSimulator

Return to RoveSoDocs Guides for Today, Tomorrow, and Forever.

Notice: Some parts Clankered, and then looked through. May contain Hallucinations

Unreal Engine Game Development: Quick Start Guide

Welcome to the team! If you are new to computer science or transitioning from higher-level languages (like Python or JavaScript), Unreal Engine C++ might look intimidating at first. Don’t worry! This guide covers the essential patterns you need to understand to write safe, clean code without breaking the game (AI Nonsense. You will break the game, a lot).

This document covers general information for writing C++ with Unreal Engine. For information on Blueprints or using the Unreal Editor, see another document, which may or may not exist.

System/Version Notice

We are currently on Unreal Engine 5.6.1. We have several additions;

Unreal

Unreal Engine uses blueprints for most logic. These have buttons and sliders and all that, but logic is done using nodes, which is terrible. C++ files can replace blueprint nodes, so we use them.

To connect classes in C++ files to blueprints, Unreal needs to know what data and methods a class has. To do this, the Unreal Header Tool (UHT) reflects the files. UHT is also used by unreal to set up Garbage Collection and serialization. Here is a list of standards/references to make sure UHT does what you want it to;

Unreal classes tend to have a single letter prefix (the A at the start of ARoverVehiclePawn). They work as follows;

Prefix Type Class Managed by Garbage Collector?* Can place in World?
U Object / Subsystem Yes No
A Actor Yes Yes
F Struct/Math/String No (Manual or Stack) No
T Template Depends on contents No
I Interface Abstract type No

Most classes derive from an Unreal Class. In the editor, a blueprint can then be created of that new (derived) class.
For example, ARoverVehiclePawn derives from AWheeledVehiclePawn; the former is a custom Rover type by MRDT, the latter is from a plugin called ChaosVehicles.

RoverArmPawn.h is a good example of a reflected header, and here is a separately AI generated example with the key lines:

#include "MyCharacter.generated.h" // <-- The reflected file generated by the tool

UCLASS() // <-- Tells the tool to inspect this class
class AMyCharacter : public ACharacter
{
    GENERATED_BODY() // <-- Injects the reflection data here

    UPROPERTY(EditAnywhere, BlueprintReadWrite) // <-- Exposes this variable
    int32 Health;
};

Our Specifics

We have our own macros for certain things.

Log

LOG(stringWithPlaceholders, values) does what you expect, under the category RoveSoSimulator, using Unreal’s UE_LOG macro. It is effectively a default-argument + shorthand macro.
As far as I can tell (I haven’t used it for this), the first argument is a string which is output. In the string should be parts with a % and then 1-2 characters. These are value placeholders, so the arguments that follow will replace them in the message. Different characters after the % are needed for different values. |Code|Type| |—|—| |%s | FString* | |%d | Int | |%f | float|

This is sourced from the docs page on UE_LOG *In documentation, this is the one used for boolean and FVector, after converting each to strings.

Example of multiple data pieces, reformated from a UE_LOG example, and so untested;
LOG(TEXT("Current values are: vector %s, float %f, and integer %d"), *ExampleVector.ToString(), ExampleFloat, ExampleInteger);

Broad Macros

Some things, like the rovers’ cameras and control modes, are set up with macros. For reference, a macro is a preprocessor directive, so executes before compile time, and is generally used to change what the code is. Hovering over a macro in an IDE shows how it expands out
To make an enum and automatically make a list of strings with the same name (for debugging), “DO” macros and formatting macros are used;
(DO)

#define AthenaControlState(DO) \
	DO(UNCONTROLLED) \
	DO(DIRECTDRIVE) \
	DO(ROTATIONDRIVE) \
	AthenaControlStateFront(DO) \
	DO(VIDEOGAMING)

(Formatting)

#define MAKE_ENUM(VAR) VAR,
#define MAKE_STRINGS(VAR) #VAR,

In this example, AthenaControlState(MAKE_ENUM) expands first to MAKE_ENUM(UNCONTROLLED) MAKE_ENUM(DIRECTDRIVE) MAKE_ENUM(...) etc. AthenaControlStateFront is itself a “DO” macro, containing more control states. I’m not entirely sure how those two formatting macros work, but they do.

For another example,
Count is used to count the number of states directly.

#define COUNT(VAR) i++;

Count is used in these lines;

	{ int i = 0; AthenaControlState(COUNT); rover->TotalControlModes = i; }
	{ int i = 0; AthenaControlStateFront(COUNT); rover->FrontControlModes = i; }

Therefore expanding out to i++; i++; i++; i++; ... for the number of items in the macro. This then increments the variable i for an effective count.
It is theorectically possible to move the declaration of i into a macro as well, but that would make it much more complex than one line.

General Footnotes

This section is for any odd C++ formatting to know. Feel free to add entries.

U16 v. U8 strings; don’t use u"some string thats in unreal"; the u” is intepreted differently by compiler. Use the TEXT() Macro (argument is the string, with quotes)