// Project Lab - NHTV Igad #include "UnrealProject.h" #include "DefaultPlayerController.h" #include "IngameHUD.h" #include "AbilityInfo.h" #include "AbilityState.h" #include "NetworkPlayer.h" #include "HealthBar.h" #include "CreatureSpawn.h" #include "PlayerSlot.h" #include "DefaultGameState.h" #include "DefaultPlayerState.h" #include "MiniMapWidget.h" #include "ToolTipWidget.h" #include "CombatText/CombatTextWidget.h" #include "SpellInfoDisplay.h" #include "ButtonBarSwitcher.h" #include "BaseSkillObject.h" #include "WidgetLayoutLibrary.h" #include "NetworkGhost.h" #include "TouhouBoss.h" #include "MiniBossCreature.h" #include "StatBar.h" #include static UClass* healthBarWidgetClass; static UClass* playerSlotWidgetClass; UIngameHUD::UIngameHUD(const FObjectInitializer& init) :Super(init) { ConstructorHelpers::FClassFinder HealthBarWidgetCF(TEXT("/Game/Assets/GUI/WEEGEE_HealthBar")); healthBarWidgetClass = HealthBarWidgetCF.Class; miniMap = nullptr; } void UIngameHUD::NativeConstruct() { m_myTeam = 0; m_character = nullptr; Super::NativeConstruct(); m_spellInfoDisplay = Cast(WidgetTree->FindWidget("SpellInfoDisplay")); miniMap = Cast(WidgetTree->FindWidget("Minimap")); toolTips = Cast(WidgetTree->FindWidget("ToolTipLayer")); combatText = Cast(WidgetTree->FindWidget("CombatTextLayer")); buttonBarSwitcher = Cast(WidgetTree->FindWidget("ButtonBarSwitcher")); healthBarLayer = Cast(WidgetTree->FindWidget("HealthBarLayer")); // Find stat display items m_playerStatDisplay.hpBar = Cast(WidgetTree->FindWidget("HP")); m_playerStatDisplay.manaBar = Cast(WidgetTree->FindWidget("Mana")); m_playerStatDisplay.expBar = Cast(WidgetTree->FindWidget("Exp")); m_allyStatDisplay.hpBar = Cast(WidgetTree->FindWidget("HP1")); m_allyStatDisplay.manaBar = Cast(WidgetTree->FindWidget("Mana1")); m_allyStatDisplay.name = Cast(WidgetTree->FindWidget("Name1")); m_InitStatDisplay(m_playerStatDisplay); m_InitStatDisplay(m_allyStatDisplay); check(healthBarLayer); } void UIngameHUD::NativeDestruct() { Super::NativeDestruct(); } void UIngameHUD::NativeTick(const FGeometry& MyGeometry, float InDeltaTime) { Super::NativeTick(MyGeometry, InDeltaTime); auto p = m_healthBars.CreateIterator(); while (p) { m_UpdateHealthBar(p.Key(), p.Value()); ++p; } ADefaultPlayerState* ps = Cast(GetOwningPlayer()->PlayerState); if (IsValid(ps)) { m_UpdateStatDisplay(ps, m_playerStatDisplay); m_UpdateStatDisplay(ps->teamMate, m_allyStatDisplay); } //UWorld* world = GetWorld(); //check(world); //ADefaultGameState* state = Cast(world->GetGameState()); } void UIngameHUD::NativeOnAssignCharacter(class ANetworkPossessable* pawn /*= nullptr*/, TArray skillsetPrototype /*= TArray()*/) { m_character = pawn; // Cast to ghost or player ANetworkPlayer* player = Cast(pawn); ANetworkGhost* ghost = Cast(pawn); if(ghost) { // Grey out buttons in ghost mode buttonBarSwitcher->SetGlobalEnable(false); } else if(player) { // Enable buttons back in player mode buttonBarSwitcher->SetGlobalEnable(true); // Set skill prototypes if(buttonBarSwitcher) { for(int32 i = 0; i < skillsetPrototype.Num(); i++) { // Don't assign buttons for passive skills if(skillsetPrototype[i].selectedEffect->passive) continue; switch(skillsetPrototype[i].abilityType) { case 0: buttonBarSwitcher->AssignSkillButton(skillsetPrototype[i], false); break; case 1: buttonBarSwitcher->AssignSkillButton(skillsetPrototype[i], true); break; case 2: if(skillsetPrototype[i].selectedEffect && !skillsetPrototype[i].selectedEffect->passive) { GERROR("Non-passive skill added to skill with shape type == passive, " + skillsetPrototype[i].skillObject->GetName() + " <= " + skillsetPrototype[i].selectedEffect->GetName()); } } } } m_myTeam = player->GetTeam(); } OnAssignCharacter(pawn); } void UIngameHUD::OnLevelUp(TArray updatedSkills) { if (m_spellInfoDisplay && GetPlayer()) m_spellInfoDisplay->OnLevelUp(GetPlayer(), updatedSkills); if (buttonBarSwitcher) { for (int32 i = 0; i < updatedSkills.Num(); i++) { buttonBarSwitcher->SetSkillButtonEnabled(updatedSkills[i], true); } } } void UIngameHUD::UpdateCooldowns(TArray abilityStates, ANetworkPlayer* player) { if (buttonBarSwitcher) buttonBarSwitcher->UpdateCooldowns(abilityStates, player); } void UIngameHUD::OnCharacterCreated(ANetworkCharacter* character) { if (m_healthBars.Find(character)) { // When OnCharacterCreated is called twice GWWARNING(L"OnCharacterCreated called more thatn once"); return; } UHealthBar* widget = CreateWidget(GetOwningPlayer(), healthBarWidgetClass); check(widget); healthBarLayer->AddChild(widget); m_healthBars.Add(character, widget); m_UpdateHealthBar(character, widget); } void UIngameHUD::OnCharacterDestroyed(ANetworkCharacter* character) { auto it = m_healthBars.Find(character); if (it) { (*it)->RemoveFromViewport(); m_healthBars.Remove(character); } else { // When OnCharacterDestroyed is called twice GWWARNING(L"OnCharacterDestroyed called more than once"); } } ANetworkPlayer* UIngameHUD::GetTeamMate() const { if (Cast(m_character)) { ANetworkPlayer* teamMate = Cast(m_character)->GetTeamMate(); return teamMate; } return nullptr; } ANetworkPlayer* UIngameHUD::GetPlayer() const { return Cast(m_character); } ANetworkGhost* UIngameHUD::GetGhost() const { return Cast(m_character); } class ADefaultPlayerState* UIngameHUD::GetPlayerState() const { if (!m_character) return nullptr; return Cast(m_character->PlayerState); } void UIngameHUD::m_UpdateHealthBar(class ANetworkCharacter* character, class UHealthBar* bar) { APlayerController* pc = GetOwningPlayer(); if (!IsValid(pc)) return; FVector screenPos; const float height = character->GetCapsuleComponent()->GetScaledCapsuleHalfHeight(); const FVector position = character->GetActorLocation(); const FVector worldLocation = FVector(position.X, position.Y, position.Z + height); // Check if is approximately in camera view const FVector forward = pc->PlayerCameraManager->GetCameraRotation().RotateVector(FVector(1.0f, 0.0f, 0.0f)); const FVector dir = (worldLocation - pc->PlayerCameraManager->GetCameraLocation()).GetSafeNormal(); float dot = FVector::DotProduct(forward, dir); if (dot < 0.01f) { bar->SetVisibility(ESlateVisibility::Hidden); return; } bar->SetVisibility(ESlateVisibility::Visible); pc->ProjectWorldLocationToScreenWithDistance(FVector(position.X, position.Y, position.Z + height), screenPos); const float viewportScale = UWidgetLayoutLibrary::GetViewportScale(healthBarLayer); uint32 otherTeam = character->GetTeam(); // Check witch bar style to use bool useExtendedBarStyle = character->playerName.Len() > 0; if(useExtendedBarStyle) { bar->SetStyle(0); bar->UpdateMana(character->GetMana(), character->GetMaxMana(), character->GetBlockedMana()); bar->SetName(character->playerName); } else { bar->SetStyle(1); bar->SetName(""); } bar->UpdateAlignment(otherTeam == m_myTeam); bar->UpdateHealth(character->GetHealth(), character->GetMaxHealth()); // Set the icon next to the bar EMinimapIcon icon = EMinimapIcon::None; if(character->IsA()) { icon = EMinimapIcon::Crown; } else if(character->IsA()) { icon = EMinimapIcon::MiniBoss; } bar->SetIcon(icon); // Set the on-screen position UCanvasPanelSlot* asSlot = Cast(bar->Slot); if (IsValid(asSlot)) { asSlot->SetAutoSize(true); asSlot->SetAlignment(FVector2D(0.5f, 1)); const FVector2D setPos = FVector2D(screenPos.X, screenPos.Y) / viewportScale; asSlot->SetPosition(FVector2D(FPlatformMath::RoundToFloat(setPos.X), FPlatformMath::RoundToFloat(setPos.Y))); } } void UIngameHUD::m_UpdateStatDisplay(class ADefaultPlayerState* state, const FStatDisplay& sd) { ANetworkPlayer* player = state ? state->character : nullptr; if(sd.hpBar) { if(!player) sd.hpBar->SetStat(0.0f, true); else { sd.hpBar->SetStat(player->GetHealth(), player->GetMaxHealth(), true); } } if(sd.manaBar) { if(!player) { sd.manaBar->SetBlocked(0.0f); sd.manaBar->SetStat(0, 1, true); } else { sd.manaBar->SetStat(player->GetMana(), player->GetMaxMana(), true); sd.manaBar->SetBlocked((float)player->GetBlockedMana() / (float)player->GetMaxMana()); } } if(sd.expBar) { if(state) { if(state->GetLevel() == state->GetMaxLevel()) sd.expBar->Update(1.0f, state->GetMaxLevel(), true); else sd.expBar->Update((float)state->GetExperience() / (float)state->GetExperienceToLevel(), state->GetLevel(), false); } else { sd.expBar->Update(0.0f, 0, false); } } if(sd.name) { if(state) { state->UpdatePersona(); sd.name->SetText(FText::FromString(state->nickname)); } else { sd.name->SetText(FText()); } } if(sd.avatar && state) { sd.avatar->SetBrushFromTexture(state->avatar); } } void UIngameHUD::m_InitStatDisplay(const FStatDisplay& sd) { if(sd.hpBar) { sd.hpBar->SetBarColor(EBarColor::GreenGradient); } if(sd.manaBar) { sd.manaBar->SetBarColor(EBarColor::BlueGradient); } }