Download

(LocalMultiplayer) HUD item roulette

Hi,

I’m working on an item rotation system (item roulette) like in mario kart. My idea was that my PlayerController determines which item should be obtained after collecting an itembox. It passes the information to my own HUD and this creates with the help of a timeline the illusion of an item rotation. So far so good, this seems to work quite well. However I do have a local multiplayer game (without splitscreen!) where all players share one screen (and one camera). I do want each player to have their own place to display the current item. It should look like this:

460e0f077144a7655c63cc4a1dacd003fc6fde82.png

I do see in PIE that I’ve got a HUD for each playerController but since they all share the same viewport only the HUD of the first player is drawn (at least thats my guess why I only see one item box). How would I go about implementing an itembox for each player? Would I really have to implement 4 timelines (for each player one timeline) and several functions in my HUD to cover up for all of them? Or is there an easier way to tell each playerController to draw their HUD onto the screen, so each HUD handles only it’s own itembox / itemrotation? If i activate splitscreen mode (which i dont want to) i can notice that each player has its own item drawn. So I need to tell each PC to draw onto the viewport from player 1 or something like this, right?

Here is my HUD:


// @author Theo

#include "Theosechs.h"
#include "Kismet/KismetMathLibrary.h"
#include "BrawlingPlayerController.h"
#include "BrawlHUD.h"



ABrawlHUD::ABrawlHUD()
{
	PrimaryActorTick.bCanEverTick = true;
	static ConstructorHelpers::FObjectFinder<UTexture2D> ItemTextureTextureOb(TEXT("/Game/UI/HUD/HUDMain"));

	ItemTexture = ItemTextureTextureOb.Object;

	itemIcons[0] = UCanvas::MakeIcon(ItemTexture, 128, 0, 64, 64);
	itemIcons[1] = UCanvas::MakeIcon(ItemTexture, 64, 64, 64, 64);
	itemIcons[2] = UCanvas::MakeIcon(ItemTexture, 128, 64, 64, 64);
	itemIcons[3] = UCanvas::MakeIcon(ItemTexture, 192, 64, 64, 64);
	itemIcons[4] = UCanvas::MakeIcon(ItemTexture, 64, 0, 64, 64);

	TexColor = FColor(255, 255, 255, 255);
	
	//TimeLine
	const ConstructorHelpers::FObjectFinder<UCurveFloat> Curve(TEXT("CurveFloat'/Game/Effects/Curves/ItemRotation.ItemRotation'"));
	TimeLine = FTimeline{};
	FOnTimelineFloat progressFunction{};
	progressFunction.BindUFunction(this, "UpdateTimeLine");
	TimeLine.AddInterpFloat(Curve.Object, progressFunction, FName{ TEXT("SLOWROTATION") });
	
	//bind the end event
	FOnTimelineEvent FinishEvent;
	FinishEvent.BindUFunction(this, "OnTimeLineEnd");
	TimeLine.SetTimelineFinishedFunc(FinishEvent);

	x = 0;
	y = 0;
}

void ABrawlHUD::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);
	if (TimeLine.IsPlaying()) {
		TimeLine.TickTimeline(DeltaTime);
	}
}

void ABrawlHUD::DrawHUD()
{
	Super::DrawHUD();

	if (Canvas == nullptr) {
		return;
	}

	ScaleUI = Canvas->ClipY / 1080.0f;

	//items
	DrawItems();
	DrawItemFrames();
}

void ABrawlHUD::DrawItemFrames()
{

}

void ABrawlHUD::DrawItems()
{
	if (x == 0 && y == 0) {
		x = UKismetMathLibrary::RandomFloatInRange(100, 600); //750
		y = UKismetMathLibrary::RandomFloatInRange(100, 600); //50
	}

	Canvas->SetDrawColor(TexColor);
	Canvas->DrawIcon(itemIcons[itemCount], (x * ScaleUI), (y * ScaleUI), 2 * ScaleUI);
}

void ABrawlHUD::SlowItemRotation()
{
	GetWorldTimerManager().SetTimer(ItemRotationTimer, this, &ABrawlHUD::RotateItems, ItemRotationSpeed, true);
}

void ABrawlHUD::RotateItems()
{
	//get item count from gamemode
	if (itemCount < 4)
	{
		itemCount++;
	}
	else
	{
		itemCount = 0;
	}

	GetWorldTimerManager().SetTimer(ItemRotationTimer, this, &ABrawlHUD::RotateItems, ItemRotationSpeed, false);
}

void ABrawlHUD::UpdateTimeLine(float Value)
{
	ItemRotationSpeed = Value;
}

void ABrawlHUD::OnTimeLineEnd()
{
	itemCount = 0;
	GetWorldTimerManager().ClearTimer(ItemRotationTimer);
}

void ABrawlHUD::StartItemRotation()
{
	TimeLine.PlayFromStart();

	if (!GetWorldTimerManager().IsTimerActive(ItemRotationTimer)) {
		GetWorldTimerManager().SetTimer(ItemRotationTimer, this, &ABrawlHUD::RotateItems, ItemRotationSpeed, false);
	}
}



Cheers

So I read that someone got kinda the same issue here. Hoewever (s)he found a solution:

But when I try to access the other HUDs from my player #1’s HUD in this manner:


void ABrawlHUD::DrawHUD()
{
	Super::DrawHUD();


	if (Canvas == nullptr) {
		return;
	}

	for (TActorIterator<ABrawlHUD> ActorItr(GetWorld()); ActorItr; ++ActorItr)
	{
		if (*ActorItr != this) {
			ABrawlHUD* test = *ActorItr;
			test->IsCanvasValid_WarnIfNot();
			if (test->Canvas) {
				GEngine->AddOnScreenDebugMessage(-1, 5, FColor::Red, TEXT("hallo"));
				test->DrawHUD();
			}
		}
	}
}

i get the “canvas draw functions may only be called during the handling of the drawhud event” - warning and I can’t get the other HUDs to draw.



void ABrawlHUD::DrawHUD()
{
	Super::DrawHUD();

	if (Canvas == nullptr) {
		return;
	}

	for (TActorIterator<ABrawlHUD> ActorItr(GetWorld()); ActorItr; ++ActorItr)
	{
		(*ActorItr)->DrawHud( Canvas );
	}
}

// Add this method to your header.
void ABrawlHud::DrawHud( UCanvas* Canvas )
{
	// Draw your stuff for each player here.
}


Try that.

It works. Thank you very very much. :slight_smile: