Need help with code structure

I’m trying to wrap my head around the best way to structure some code, and could use some suggestions as after many hours thinking about this I feel like the gaps in my knowledge are letting me down.

I have a whole section of my game where the player can perform a large number of different kinds of actions which do various things from changing the properties of existing objects/actors to creating new objects/actors. I want all of these actions to be undoable/redoable. To this end, I am using the Command pattern (Command · Design Patterns Revisited · Game Programming Patterns) to encapsulate every player action in an object that records state, so that it can be undone.

I then have a class for my CommandStack, which keeps track of these objects, and has for example this function which takes a new command and handles it:


CommandStack->AddCommand(UCommand* NewCommand);

Every command could be done one of two ways: (1) with a 2D UMG widget, or (2) with a 3D VR widget. Whichever way is used, on pressing the button a new Command object is created with the appropriate parameters, which then needs to be sent to the CommandStack.

This is where my knowledge of efficient/standard practices for good OOP structure breaks down.
My initial thought was to have a central Controller class (AActor derived?) which has many subsystems as components, such as the CommandStack (along with other systems like the SaveSystem for example). So every UI element would need a reference to the Controller, such that when a button is pushed it does something like this:


USetHeightCmd* NewCommand = NewObject<USetHeightCommand>(this);
NewCommand->SetPreviousValue(Widget->GetValue());
NewCommand->SetCurrentValue(Widget->GetInput());
ControllerRef->CommandStack->AddCommand(NewCommand);

But this means that every widget needs a reference to the Controller actor/object, so either needs to be given that reference on spawn, or has to get it through GetAllActorsOfClass for example. I suppose there’s nothing wrong with that, and it will work, but it seems clumsy and too tightly coupled to me, but I don’t know what the alternative should be. Something involving delegates perhaps (can’t say I totally understand delegates yet)?

I’ve been running into this issue more and more as I’m trying to structure everything, and while I totally get (and appreciate) keeping systems separate so everything is more modular and maintainable, I’m struggling to understand how to link all these things together without just making sure everything has a reference to everything else.

What are the correct/elegant ways to connect different systems like this?

I’ve been working on something recently where I only ever create on instance of a given actor (transient and created at runtime) at the game instance-level and I want absolutely no other part of the code to access to it in any direct way. And I loathe the singleton pattern.

It’s a pain in the ■■■ to do.

Basically, the best solution I’ve found for minimizing all related objects having a reference to one all-important class instance or what have you is to expose some static methods for initial create/registration and, in that static method, assign out delegates within that head honcho class to whatever is passed in. That way you never have to deal with direct access or references, but can still convey information back-and-forth as-needed.

For instance:



DECLARE_DELEGATE_TwoParams( FEntityPollSimulation, USimulationEntityComponent*, TArray< TScriptInterface< ISimulationDroplet > >& );

// In ASimulationCore
void EntityPoll( USimulationEntityComponent* EntityComponent, TArray< TScriptInterface< ISimulationDroplet > >& EntityPendingDropletsInOut );

// In the class that the simulation core 'manages' to some extent (but the class itself has no direct control over the simulation core):
    // Simulation core polling delegate.
FEntityPollSimulation PollSimulationDelegate;

// Executed as-needed:
PollSimulationDelegate.ExecuteIfBound( this, DropletsPending );


And that delegate, along with others, are bound in a static ASimulationCore::RegisterEntity. This may not be an ideal setup – as I just wrapped it up (and it’s a fairly enormous system) – but it’s much cleaner than what I’ve tried to do in the past.

I hope this somewhat addressed your question.

Hey, this is very interesting, thank you! I don’t fully understand it yet, but it seems helpful.

I guess what I want, and what it seems like many other people are hoping for in UE4, is a system where one class can broadcast events (including payloads), and another class can register to listen out for these events. And for those two classes to be totally disconnected, without needing to know about each others’ existence.

At first I thought delegates were going to be the answer, but now I (kind of) understand how they work, they are nothing like this. For one thing, because delegates are not abstract, the links are made between actual instances of objects.

So I guess if I have my controller object being responsible for instantiating the UI components, it could bind to them as it does so.

You can create static delegates, so you’d be able to call or subscribe to them from anywhere without knowing in advance which object is going to call it.

You could also put these in another class entirely, so both sides would only need to know about this delegate interface. One example usage in the engine would be FWorldDelegates.

Ah, amazing! Thanks so much @Zeblote, that’s exactly what I needed to know. For future reference, if anyone is trying to do the same kind of thing, here’s a really basic setup using a Sender class that simply broadcasts its object name, and a Receiver class that picks up whenever a Sender class broadcasts:

Sender.h


#pragma once

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

DECLARE_MULTICAST_DELEGATE_OneParam(FMyDelegate, FString)

UCLASS()
class DELEGATES_API ASender : public AActor
{
    GENERATED_BODY()

public:    
    // Sets default values for this actor's properties
    ASender();

    static FMyDelegate MyDel;

    UFUNCTION(BlueprintCallable)
        void SendMessage();
};

Sender.cpp


#include "Sender.h"

ASender::ASender()
{
    PrimaryActorTick.bCanEverTick = false;
}

FMyDelegate ASender::MyDel;

void ASender::SendMessage()
{
    UE_LOG(LogTemp, Warning, TEXT("Message Sent!"));
    MyDel.Broadcast(this->GetName());
}

Receiver.h


#pragma once

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

UCLASS()
class DELEGATES_API AReceiver : public AActor
{
    GENERATED_BODY()

public:    
    // Sets default values for this actor's properties
    AReceiver();

    UFUNCTION()
    void OnReceiveBroadcast(FString ObjectName);

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;
};

Receiver.cpp


#include "Receiver.h"
#include "Sender.h"

AReceiver::AReceiver()
{
    PrimaryActorTick.bCanEverTick = false;
}

void AReceiver::OnReceiveBroadcast(FString ObjectName)
{
    UE_LOG(LogTemp, Warning, TEXT("Message Received from: %s"), *ObjectName);
}

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

    ASender::MyDel.AddUObject(this, &AReceiver::OnReceiveBroadcast);
}

So then in a level I have a single Receiver actor, and any number of Sender actors who are firing the SendMessage() function on timers. The output looks like this:


LogTemp: Warning: Message Sent!
LogTemp: Warning: Message Received from: BP_Sender_1
LogTemp: Warning: Message Sent!
LogTemp: Warning: Message Received from: BP_Sender_2
LogTemp: Warning: Message Sent!
LogTemp: Warning: Message Received from: BP_Sender_3

This is exactly what I needed: the Sender class doesn’t need to know anything about the Receiver class, and doesn’t need to be linked to a specific instance. The Receiver class does know about the Sender class (from including the header only), but doesn’t need to be linked to actual instances of the Sender class. Perfect!

Thanks again!