【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。
在EventGraph中编写显示血量条逻辑:当血量改变时,对HealthbarImage参数进行修改,更新血量条
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、效果演示
二、HUD
HUD 是显示屏幕上覆盖的元素的基本对象。游戏中每个由人类控制的玩家 都有自己的 AHUD
类实例,这个实例会绘制到个人视口上。如果是分屏多人游戏, 多个视口会共享同一个屏幕,但每个HUD仍会绘制到其自己的视口上。要使用的HUD的 类型或类由正在使用的游戏类型指定。
1、创建分数Widget
创建显示分数UI的Credits_Widget和游戏时间信息UI的GameModeInfo_Widget。
1.1 分数UI
1.2 游戏时间信息UI
添加Text控件表示时间信息,并绑定游戏时间更新函数GetGameTimeText()来更新Text控件
2、新建HUD
创建Widget蓝图Main_HUD,添加先前创建的Widget蓝图类:玩家血条PlayerHealth_Widget类、准星Crosshair_Widget类、分数Credit_Widget类、游戏信息GameModeInfo_Widget类,并设置好大小布局。(需要将PlayerHealth_Widget中的Canvas Panel删除才能在这里对其大小进行修改)
3、添加HUD到玩家屏幕
在PlayerCharacter_BP中修改玩家屏幕所添加的Widget
4、效果演示
三、控制台指令
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());
}