【UE4C++-ActionRougelike-14】UMG扩展


【UE4C++-ActionRougelike-14】UMG扩展

一、创建AI血量显示

1、新建UserWidget类

以UserWidget为基类创建MyWorldUserWidget

UCLASS()
class ACTIONROGUELIKE_API UMyWorldUserWidget : public UUserWidget
{
	GENERATED_BODY()
protected:
    //使用 meta = (BindWidget) 属性将其与 UI 中的控件进行绑定。这意味着在 UMyWorldUserWidget 实例创建后,ParentSizeBox 成员变量将自动引用 UI 中的相应控件
	UPROPERTY(meta = (BindWidget))
	USizeBox* ParentSizeBox;

	// NativeTick 函数是 UMyWorldUserWidget 类的虚函数,用于在用户界面蓝图每帧更新时执行自定义逻辑
	virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
public:
    // UI的偏移量
	UPROPERTY(EditAnywhere, Category = "UI")
	FVector WorldOffset;
	//被附着的Actor
	UPROPERTY(BlueprintReadOnly, Category = "UI")
	AActor* AttachedActor;
};

在MyWorldUserWidget.cpp中给出实现

//在用户界面蓝图中的 Widget 实时跟随一个指定的 Actor,并将 Widget 定位到屏幕上的目标位置
void UMyWorldUserWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
{
	Super::NativeTick(MyGeometry, InDeltaTime);
	// 检查 AttachedActor 是否有效
	if (!IsValid(AttachedActor))
	{
		// 如果 AttachedActor 无效,将当前 Widget 从父控件中移除
		RemoveFromParent();
		UE_LOG(LogTemp, Warning, TEXT("AttachedActor no longer valid, removing Health Widget."));
		return;
	}
	FVector2D ScreenPosition;
	// 将 AttachedActor 的世界坐标投影到屏幕坐标
	if (UGameplayStatics::ProjectWorldToScreen(GetOwningPlayer(), AttachedActor->GetActorLocation() + WorldOffset, ScreenPosition))
	{
		// 获取当前视口的缩放比例
		float Scale = UWidgetLayoutLibrary::GetViewportScale(this);
		// 根据缩放比例对屏幕坐标进行缩放
		ScreenPosition /= Scale;
		if (ParentSizeBox)
		{
			// 将屏幕坐标设置为 ParentSizeBox 的渲染平移
			ParentSizeBox->SetRenderTranslation(ScreenPosition);
		}
	}
}

2、创建蓝图

以MyWorldUserWidget类为基类创建蓝图类MinionHealth_Widget,添加Canvas Panel->SizeBox(命名为ParentSizeBox)->Image。并且设置Image的材质为游戏材质入门中创建的M_HealthBar。

Image设置

在EventGraph中编写显示血量条逻辑:当血量改变时,对HealthbarImage参数进行修改,更新血量条

widget蓝图

3、添加血量条UI

在MyAICharacter中添加UMyWorldUserWidget*来表示当前激活的血量条Widget,和HealthBarWidgetClass表示血量条widget的类

class ACTIONROGUELIKE_API AMyAICharacter : public ACharacter
{
protected:
	//用于保存当前激活的血量条 widget
	UMyWorldUserWidget* ActiveHealthBar;
	//用于存储血量条 widget 的类
	UPROPERTY(EditDefaultsOnly, Category = "UI")
	TSubclassOf<UUserWidget> HealthBarWidgetClass;
}

在OnHealthChanged中编写创建和更新血量条widget的逻辑

void AMyAICharacter::OnHealthChanged(AActor* InstigatorActor, UMyAttributeComponent* OwningComp, float NewHealth, float Delta)
{
	if (Delta < 0.0f)
	{
		// 如果血条 UI 没有被创建,则创建血条 UI
		if (ActiveHealthBar == nullptr)
		{
			ActiveHealthBar = CreateWidget<UMyWorldUserWidget>(GetWorld(), HealthBarWidgetClass);
			if (ActiveHealthBar)
			{
				// 将血条 UI 关联到当前角色
				ActiveHealthBar->AttachedActor = this;
				// 将血条 UI 添加到视图中
				ActiveHealthBar->AddToViewport();
			}
		}
	}
}

4、效果演示

AI血量效果展示

二、HUD

HUD 是显示屏幕上覆盖的元素的基本对象。游戏中每个由人类控制的玩家 都有自己的 AHUD 类实例,这个实例会绘制到个人视口上。如果是分屏多人游戏, 多个视口会共享同一个屏幕,但每个HUD仍会绘制到其自己的视口上。要使用的HUD的 类型或类由正在使用的游戏类型指定。

1、创建分数Widget

创建显示分数UI的Credits_Widget和游戏时间信息UI的GameModeInfo_Widget。

1.1 分数UI
分数widget
1.2 游戏时间信息UI

添加Text控件表示时间信息,并绑定游戏时间更新函数GetGameTimeText()来更新Text控件

游戏时间信息

2、新建HUD

创建Widget蓝图Main_HUD,添加先前创建的Widget蓝图类:玩家血条PlayerHealth_Widget类、准星Crosshair_Widget类、分数Credit_Widget类、游戏信息GameModeInfo_Widget类,并设置好大小布局。(需要将PlayerHealth_Widget中的Canvas Panel删除才能在这里对其大小进行修改)

MainHUD蓝图

3、添加HUD到玩家屏幕

在PlayerCharacter_BP中修改玩家屏幕所添加的Widget

修改玩家屏幕显示Widget

4、效果演示

MainHUD效果演示

三、控制台指令

1、玩家出生

在GameModeBP中设置DefaultPawn为PlayerCharacter_BP,并在地图中加入PlayStart,此时运行会在PlayStart处开始游戏

2、控制台指令

2.1 治疗玩家

使用UFUNTION(Exec)标记函数,则函数可以在游戏运行时通过控制台命令来调用

//MyCharacter.h
//Exec宏,意味着该函数可以在游戏运行时通过控制台命令来调用
UFUNCTION(Exec)
void HealSelf(float Amount = 100);

//MyCharacter.cpp
void AMyCharacter::HealSelf(float Amount /* = 100 */)
{
	AttributeComp->ApplyHealthChange(this, Amount);
}
2.2 杀死所有AI
//MyGameModeBase.h
UFUNCTION(Exec)
void KillAll();

//MyGameModeBase.cpp
void AMyGameModeBase::KillAll()
{
	for (TActorIterator<AMyAICharacter> It(GetWorld()); It; ++It)
	{
		AMyAICharacter* Bot = *It;

		UMyAttributeComponent* AttributeComp = UMyAttributeComponent::GetAttributes(Bot);
		if (ensure(AttributeComp) && AttributeComp->IsAlive())
		{
			AttributeComp->Kill(this); 
		}
	}
}

//MyAttributeComponent.cpp
bool UMyAttributeComponent::Kill(AActor* InstigatorActor)
{
	return ApplyHealthChange(InstigatorActor, -GetHealthMax());
}

3、效果演示

控制台效果展示

文章作者: Woilin
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Woilin !
评论
  目录