Can't seem to figure out how to get UCanvas init/operations to work

Hi. First of all, my knowledge of Unreal and its inner working is still beginner-level and my CPP is still green.
I made a simple UMG widget that has a Canvas, which contains an image in it and I want to control the position of said Canvas image in real-time through C++. So I re-parented the widget to a C++ class I made - ReticleWidget.

ReticleWidget.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Engine/Canvas.h"
#include "ReticleWidget.generated.h"


/**
 * 
 */
class UCanvas;
class UUserWidget;

UCLASS()
class UMGTEST_API UReticleWidget : public UUserWidget
{
	GENERATED_BODY()
	
public:
	
	UPROPERTY(Instanced, meta = (BindWidget))
	UCanvas* ReticleCanvas;

	float XInit, YInit;

	float GetX();

	float GetY();

	void SetX(float XCoord);

	void SetY(float YCoord);

	void ReticleUpdate();
};

ReticleWidget.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "ReticleWidget.h"

float UReticleWidget::GetX()
{
	return ReticleCanvas->OrgX;
}

float UReticleWidget::GetY()
{
	return ReticleCanvas->OrgY;
}

void UReticleWidget::SetX(float XCoord)
{
	ReticleCanvas->OrgX = XCoord;
}

void UReticleWidget::SetY(float YCoord)
{
	ReticleCanvas->OrgY = YCoord;
}

void UReticleWidget::ReticleUpdate()
{
	ReticleCanvas->Update();
}

And I’m trying to control the Canvas from a basic GameModeBase class as follows.
UMGTestGameModeBase.h

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "GameFramework/GameMode.h"
#include "Engine/Canvas.h"
#include "ReticleWidget.h"
#include "UMGTestGameModeBase.generated.h"

/**
 * 
 */
class UReticleWidget;

UCLASS()
class UMGTEST_API AUMGTestGameModeBase : public AGameModeBase
{
	GENERATED_BODY()

	protected:
	
	virtual void BeginPlay() override;

	virtual void Tick(float DeltaTime) override;

	float temp;

};

UMGTestGameModeBase.cpp

// Copyright Epic Games, Inc. All Rights Reserved.


#include "UMGTestGameModeBase.h"

void AUMGTestGameModeBase::BeginPlay()
{
	temp = UReticleWidget::GetX();
}

void AUMGTestGameModeBase::Tick(float DeltaTime)
{
	temp += 0.1;
	UReticleWidget::SetX(temp);
	UReticleWidget::ReticleUpdate();
}

And when I compile, I get these errors-
|Error|C2352|‘UReticleWidget::GetX’: illegal call of non-static member function|UMGTest|C:\Users\prana\Documents\Unreal Projects\UMGTest\Source\UMGTest\UMGTestGameModeBase.cpp|8||

I get three errors for each of the three functions I try to call from UReticleWidget.

Now, I’ve obviously tried making these static in the first place but in doing so, I make ReticleCanvas unusable because “a nonstatic member reference must be relative to a specific object” and then I obviously can’t try making the ReticleCanvas static in the first place. So what should be my course of action here? Any ideas? Thank you in advance.

2 things

  1. Not your problem though important: what you are doing here:
#include "ReticleWidget.h"

/**
 * 
 */
class UReticleWidget;

is both including the header AND forward declaring the class. if you include the header a class lives in, you don’t forward declare it. Normally you forward declare all classes required by the .h file without including the header file. This can be done if the header only uses those classes as pointer / reference properties or parameters. In the .cpp file (where those classes are actually used) you include their .h file. this improves compilation time and sometimes helps you avoid trouble with circular dependencies.

  1. your problem:
    you are calling a method as if it is static, because you are not calling it on an instance of the class:
void AUMGTestGameModeBase::BeginPlay()
{
	temp = UReticleWidget::GetX();
}

If the method is not going to be static, you should call it on an instance of UReticleWidget:

void AUMGTestGameModeBase::BeginPlay()
{
  UReticleWidget* ReticleWidget = CreateWidget<UReticleWidget>(GetYourPlayerControllerHere(), UReticleWidget::StaticClass());
  temp = ReticleWidget->GetX();
}
2 Likes

I’m not sure what your use case is - but I’ll also mention in passing that AHUD has a bunch of methods for drawing on the screen. In particular DrawMaterial:
AHUD::DrawMaterial | Unreal Engine Documentation

and the other Draw* functions might be interesting.

The reason I thought of this is because drawing a reticule is a lot easier with AHUD::DrawMaterial than going through UMG, (at least in my opinion).

1 Like

Thank you. That fixed my problem. I foolishly thought that the BIndWidget tag will automatically link the UMG widget, I won’t have to create a new one and upon further research, I find that I have a severely crippled understanding of how things work in Unreal. Again, thank you very much and I hope that this serves as a reminder for me to read the documentation more.