六一的部落格


关关难过关关过,前路漫漫亦灿灿。



Game Over Widget


API导航


PlayerState

修改和获取游戏角色名称

AIController控制的游戏角色, 名称通常为空, 而PlayerController控制的游戏角色, 其名称为主机名

1/** set the player name to S */
2virtual void SetPlayerName(const FString& S);
3
4/** returns current player name */
5UFUNCTION(BlueprintPure, Category = PlayerState)
6FString GetPlayerName() const;

Pawn

检查上级控制器是否为PlayerController, 意味着是否为玩家操控的游戏角色

 1/** See if this actor is currently being controlled */
 2UE_DEPRECATED(4.24, "IsControlled is deprecated. To check if this pawn is controlled by anything, then call IsPawnControlled. To check if this pawn is controlled only by the player then call IsPlayerControlled")
 3UFUNCTION(BlueprintCallable, Category=Pawn)
 4bool IsControlled() const;
 5
 6bool APawn::IsControlled() const
 7{
 8    APlayerController* const PC = Cast<APlayerController>(Controller);
 9    return(PC != nullptr);
10}

Controller

判断控制器类型是否为PlayerController

1/** Returns whether this Controller is a PlayerController.  */
2UFUNCTION(BlueprintCallable, Category=Pawn)
3bool IsPlayerController() const;

TextBlock

设置文本内容

1/**
2 * Directly sets the widget text.
3 * Warning: This will wipe any binding created for the Text property!
4 * @param InText The text to assign to the widget
5 */
6UFUNCTION(BlueprintCallable, Category="Widget", meta=(DisplayName="SetText (Text)"))
7virtual void SetText(FText InText);

Image

1class UMG_API UImage : public UWidget
2{
3    // ...
4};

Widget

UImage是其派生类

设置窗口部件可见性

1/** Sets the visibility of the widget. */
2UFUNCTION(BlueprintCallable, Category="Widget")
3virtual void SetVisibility(ESlateVisibility InVisibility);

VerticalBox

 1/**
 2 * A vertical box widget is a layout panel allowing child widgets to be automatically laid out
 3 * vertically.
 4 *
 5 * * Many Children
 6 * * Flows Vertical
 7 */
 8UCLASS(meta = (ShortTooltip = "A layout panel for automatically laying child widgets out vertically"))
 9class UMG_API UVerticalBox : public UPanelWidget
10{
11    // ...
12};

PanelWidget

UVerticalBox的基类

移除所有子节点

1/** Remove all child widgets from the panel widget. */
2UFUNCTION(BlueprintCallable, Category="Widget|Panel")
3virtual void ClearChildren();

添加子节点

1/**
2 * Adds a new child widget to the container.  Returns the base slot type, 
3 * requires casting to turn it into the type specific to the container.
4 */
5UFUNCTION(BlueprintCallable, Category="Widget|Panel")
6UPanelSlot* AddChild(UWidget* Content);

STUGameHUD创建游戏结束窗口


添加属性: 游戏结束窗口部件类型

ShootThemUp: UI/STUGameHUD.h

1UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
2TSubclassOf<UUserWidget> GameOverWidgetClass;

创建该类型窗口部件对象, 加入窗口部件对象容器

ShootThemUp: UI/STUGameHUD.cpp

1// InitGameWidgets
2GameWidgets.Add(ESTUMatchState::GameOver, CreateWidget<UUserWidget>(GetWorld(), GameOverWidgetClass));

设计游戏结束窗口

由两部分组成:

  1. 游戏结束窗口
  2. 单条玩家得分

创建两个C++类

-
基类 UserWidget
路径 UI
名称 STUGameOverWidget
属性 Public
-
基类 UserWidget
路径 UI
名称 STUPlayerStatRowWidget
属性 Public

创建两个蓝图窗口部件

Content/UI

基类
WBP_PlayerStatRow STUPlayerStatRowWidget
WBP_GameOverWidget STUGameOverWidget

设计WBP_PlayerStatRow

既用作玩家得分记录, 也用作记录表头

  1. 添加 Canvas Panel

  2. 添加 Vertical Box

    一条记录中的所有元素都包含在 Vertical Box

    勾选 Size To Content



Vertical Box

由两部分组成

  1. 添加 Overlay

  2. 添加 Spacer

    -
    Appearance > Size > Y 10, 纵向间隔



Overlay

由两部分组件; 其存在使得图片作为记录的背景

  1. 添加 Image

    用以高亮玩家信息

    修改变量名为 PlayerIndicatorImage , 之后会在代码中设置可见性

    -
    Appearance > Color and Opacity > Hex Linear 0028FFFF
    Appearance > Color and Opacity > A 0.5, 透明度
    Horizontal Alignment Fill
    Vertical Alignment Fill
    Behavior > Visibility Hidden, 默认不可见(不高亮)


  2. 添加 Horizontal Box

    记录文本


Horizontal Box

由5部分组成; 所有文本外均套有一个 Size Box; 为所有文本设置对齐方式; 为所有文本勾选 IsVariable , 并设置变量名

文本框默认内容 Size Box > Width Override Text > Appearance > Justification 对齐方式 变量名
PlayerName 400 默认左对齐 PlayerNameTextBlock
Kills 200 右对齐 KillsTextBlock
Deaths 200 右对齐 DeathsTextBlock
Team 200 右对齐 TeamTextBlock
  1. 添加 Text

    玩家名

    建议将文本框默认内容设为Name


  2. 添加 Text

    击杀数


  3. 添加 Text

    死亡次数

  4. 添加 Text

    阵营ID

  5. 添加 分隔符

    -
    Appearance > Size > X 50, 水平间隔



设计WBP_GameOverWidget


从WBP_PauseWidget拷贝已有设计

  1. 设置 Game Pause 文本居中


  2. 拷贝整个 Canvas Panel



设计WBP_GameOverWidget

  1. 粘贴 Canvas Panel


  2. 修改文本框内容


  3. 移除 Size Box

  4. 添加表头: WBP_PlayerStatRow

  5. 添加分隔符 Spacer

    -
    Appearance > Size > Y 40, 纵向间隔


  6. 添加垂直盒 Vertical Box , 用来存放玩家得分

    之后会在代码中往里添加记录: 勾选 Is Variable , 修改变量名为PlayerStatBox



修改STUGameModeBase设置游戏角色名称

如果是玩家操控的游戏角色, 设置名称为 Player , 将NPC命名为 Bot

ShootThemUp: STUGameModeBase.cpp

1// CreateTeamsInfo
2PlayerState->SetPlayerName(Controller->IsPlayerController() ? "Player" : "Bot");

另一种实现, 不建议使用 , 因为IsControlled已经过时了

 1const auto Pawn = Controller->GetPawn();
 2if (!Pawn) continue;
 3
 4if (Pawn->IsControlled())
 5{
 6    PlayerState->SetPlayerName("Player");
 7}
 8else
 9{
10    PlayerState->SetPlayerName("Bot");
11}

STUUtils添加静态函数: 将int32转换为FText

PlayerState中一些属性为int32类型, 而文本框内容设置接受FText类型

ShootThemUp: STUUtils.h

1static FText TextFromInt(int32 Number) { return FText::FromString(FString::FromInt(Number)); }

实现STUPlayerStatRowWidget


添加属性

变量: 文本框和图片

protected

ShootThemUp: UI/STUPlayerStatRowWidget.h

 1class UImage;
 2class UTextBlock;
 3
 4UPROPERTY(meta = (BindWidget))
 5UImage *PlayerIndicatorImage;
 6
 7UPROPERTY(meta = (BindWidget))
 8UTextBlock *PlayerNameTextBlock;
 9
10UPROPERTY(meta = (BindWidget))
11UTextBlock *KillsTextBlock;
12
13UPROPERTY(meta = (BindWidget))
14UTextBlock *DeathsTextBlock;
15
16UPROPERTY(meta = (BindWidget))
17UTextBlock *TeamTextBlock;

添加接口: 设置文本框内容, 设置高亮可见性

public

ShootThemUp: UI/STUPlayerStatRowWidget.h

1void SetPlayerIndicatorImageVisibility(bool Visible);
2void SetPlayerNameTextBlock(FString PlayerName);
3void SetKillsTextBlock(int32 Kills);
4void SetDeathsTextBlock(int32 Deaths);
5void SetTeamTextBlock(int32 TeamID);

ShootThemUp: UI/STUPlayerStatRowWidget.cpp

 1#include "STUUtils.h"
 2#include "Components/Image.h"
 3#include "Components/TextBlock.h"
 4
 5void USTUPlayerStatRowWidget::SetPlayerIndicatorImageVisibility(bool Visible)
 6{
 7    if (!PlayerIndicatorImage) return;
 8    PlayerIndicatorImage->SetVisibility(Visible ? ESlateVisibility::Visible : ESlateVisibility::Hidden);
 9}
10
11void USTUPlayerStatRowWidget::SetPlayerNameTextBlock(FString PlayerName)
12{
13    if (!PlayerNameTextBlock) return;
14    PlayerNameTextBlock->SetText(FText::FromString(PlayerName));
15}
16
17void USTUPlayerStatRowWidget::SetKillsTextBlock(int32 Kills)
18{
19    if (!KillsTextBlock) return;
20    KillsTextBlock->SetText(STUUtils::TextFromInt(Kills));
21}
22
23void USTUPlayerStatRowWidget::SetDeathsTextBlock(int32 Deaths)
24{
25    if (!DeathsTextBlock) return;
26    DeathsTextBlock->SetText(STUUtils::TextFromInt(Deaths));
27}
28
29void USTUPlayerStatRowWidget::SetTeamTextBlock(int32 TeamID)
30{
31    if (!TeamTextBlock) return;
32    TeamTextBlock->SetText(STUUtils::TextFromInt(TeamID));
33}

实现STUGameOverWidget


覆写Initialize, 注册游戏状态改变通知

ShootThemUp: UI/STUGameOverWidget.h

1#include "STUCoreTypes.h"
2
3// public
4virtual bool Initialize() override;
5
6// private
7void OnMatchStateChanged(ESTUMatchState NewState);

ShootThemUp: UI/STUGameOverWidget.cpp

 1#include "STUGameModeBase.h"
 2
 3bool USTUGameOverWidget::Initialize()
 4{
 5    if (GetWorld())
 6    {
 7        const auto GameMode = Cast<ASTUGameModeBase>(GetWorld()->GetAuthGameMode());
 8        if (GameMode)
 9        {
10            GameMode->OnMatchStateChanged.AddUObject(this, &USTUGameOverWidget::OnMatchStateChanged);
11        }
12    }
13
14    return Super::Initialize();
15}

添加属性: 记录盒

protected

ShootThemUp: UI/STUGameOverWidget.h

1class UVerticalBox;
2
3UPROPERTY(meta = (BindWidget))
4UVerticalBox *PlayerStatBox;

添加属性: 记录类型

protected

ShootThemUp: UI/STUGameOverWidget.h

1UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
2TSubclassOf<UUserWidget> PlayerStatRowWidgetClass;

添加美化函数: 往记录盒添加记录

private

ShootThemUp: UI/STUGameOverWidget.h

1void UpdatePlayersStat();

ShootThemUp: UI/STUGameOverWidget.cpp

 1#include "Player/STUPlayerState.h"
 2#include "UI/STUPlayerStatRowWidget.h"
 3#include "Components/VerticalBox.h"
 4
 5void USTUGameOverWidget::UpdatePlayersStat()
 6{
 7    if (!GetWorld() || !PlayerStatBox) return;
 8
 9    PlayerStatBox->ClearChildren();
10
11    for (auto It = GetWorld()->GetControllerIterator(); It; ++It)
12    {
13        const auto Controller = It->Get();
14        if (!Controller) continue;
15
16        const auto PlayerState = Cast<ASTUPlayerState>(Controller->PlayerState);
17        if (!PlayerState) continue;
18
19        const auto PlayerStatRowWidget = CreateWidget<USTUPlayerStatRowWidget>(GetWorld(), PlayerStatRowWidgetClass);
20        if (!PlayerStatRowWidget) continue;
21
22        PlayerStatRowWidget->SetPlayerNameTextBlock(PlayerState->GetPlayerName());
23        PlayerStatRowWidget->SetKillsTextBlock(PlayerState->GetKillsNum());
24        PlayerStatRowWidget->SetDeathsTextBlock(PlayerState->GetDeathsNum());
25        PlayerStatRowWidget->SetTeamTextBlock(PlayerState->GetTeamID());
26        PlayerStatRowWidget->SetPlayerIndicatorImageVisibility(Controller->IsPlayerController());
27
28        PlayerStatBox->AddChild(PlayerStatRowWidget);
29    }
30}

在处理函数中调用

ShootThemUp: UI/STUGameOverWidget.cpp

1void USTUGameOverWidget::OnMatchStateChanged(ESTUMatchState NewState)
2{
3    if (NewState == ESTUMatchState::GameOver)
4    {
5        UpdatePlayersStat();
6    }
7}

查看


验证

  1. 设置BP_STUGameHUD

    -
    GameOverWidgetClass WBP_GameOverWidget
  2. 设置WBP_GameOverWidget

    -
    PlayerStatRowWidgetClass WBP_PlayerStatRow


  3. 设置BP_STUGameModeBase

    -
    Rounds Num 1
    Round Time 3



存在问题

设置BP_STUGameModeBase

-
Players Num 20



为记录盒添加滚动条

  1. 为记录盒添加滚动盒


    此时运行, 无改变, 因为垂直盒勾选了 Size To Content

  2. 为滚动盒添加大小盒

    设置最大高度

    -
    Max Desired Height 300


  3. 查看

    记录盒上方和下方都有阴影, 滚动条轨迹不可见


  4. 优化滚动盒阴影


  5. 始终显示滚动条轨迹, 设置滚动条宽度



再次查看

  1. 滚动条效果


  2. 恢复玩家数

    BP_STUGameModeBase

    -
    Players Num 4

    因为大小盒高度不足300, 所以不显示滚动条


游戏结束显示玩家得分


Game Over Widget


API导航


PlayerState

修改和获取游戏角色名称

AIController控制的游戏角色, 名称通常为空, 而PlayerController控制的游戏角色, 其名称为主机名

1/** set the player name to S */
2virtual void SetPlayerName(const FString& S);
3
4/** returns current player name */
5UFUNCTION(BlueprintPure, Category = PlayerState)
6FString GetPlayerName() const;

Pawn

检查上级控制器是否为PlayerController, 意味着是否为玩家操控的游戏角色

 1/** See if this actor is currently being controlled */
 2UE_DEPRECATED(4.24, "IsControlled is deprecated. To check if this pawn is controlled by anything, then call IsPawnControlled. To check if this pawn is controlled only by the player then call IsPlayerControlled")
 3UFUNCTION(BlueprintCallable, Category=Pawn)
 4bool IsControlled() const;
 5
 6bool APawn::IsControlled() const
 7{
 8    APlayerController* const PC = Cast<APlayerController>(Controller);
 9    return(PC != nullptr);
10}

Controller

判断控制器类型是否为PlayerController

1/** Returns whether this Controller is a PlayerController.  */
2UFUNCTION(BlueprintCallable, Category=Pawn)
3bool IsPlayerController() const;

TextBlock

设置文本内容

1/**
2 * Directly sets the widget text.
3 * Warning: This will wipe any binding created for the Text property!
4 * @param InText The text to assign to the widget
5 */
6UFUNCTION(BlueprintCallable, Category="Widget", meta=(DisplayName="SetText (Text)"))
7virtual void SetText(FText InText);

Image

1class UMG_API UImage : public UWidget
2{
3    // ...
4};

Widget

UImage是其派生类

设置窗口部件可见性

1/** Sets the visibility of the widget. */
2UFUNCTION(BlueprintCallable, Category="Widget")
3virtual void SetVisibility(ESlateVisibility InVisibility);

VerticalBox

 1/**
 2 * A vertical box widget is a layout panel allowing child widgets to be automatically laid out
 3 * vertically.
 4 *
 5 * * Many Children
 6 * * Flows Vertical
 7 */
 8UCLASS(meta = (ShortTooltip = "A layout panel for automatically laying child widgets out vertically"))
 9class UMG_API UVerticalBox : public UPanelWidget
10{
11    // ...
12};

PanelWidget

UVerticalBox的基类

移除所有子节点

1/** Remove all child widgets from the panel widget. */
2UFUNCTION(BlueprintCallable, Category="Widget|Panel")
3virtual void ClearChildren();

添加子节点

1/**
2 * Adds a new child widget to the container.  Returns the base slot type, 
3 * requires casting to turn it into the type specific to the container.
4 */
5UFUNCTION(BlueprintCallable, Category="Widget|Panel")
6UPanelSlot* AddChild(UWidget* Content);

STUGameHUD创建游戏结束窗口


添加属性: 游戏结束窗口部件类型

ShootThemUp: UI/STUGameHUD.h

1UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
2TSubclassOf<UUserWidget> GameOverWidgetClass;

创建该类型窗口部件对象, 加入窗口部件对象容器

ShootThemUp: UI/STUGameHUD.cpp

1// InitGameWidgets
2GameWidgets.Add(ESTUMatchState::GameOver, CreateWidget<UUserWidget>(GetWorld(), GameOverWidgetClass));

设计游戏结束窗口

由两部分组成:

  1. 游戏结束窗口
  2. 单条玩家得分

创建两个C++类

-
基类 UserWidget
路径 UI
名称 STUGameOverWidget
属性 Public
-
基类 UserWidget
路径 UI
名称 STUPlayerStatRowWidget
属性 Public

创建两个蓝图窗口部件

Content/UI

基类
WBP_PlayerStatRow STUPlayerStatRowWidget
WBP_GameOverWidget STUGameOverWidget

设计WBP_PlayerStatRow

既用作玩家得分记录, 也用作记录表头

  1. 添加 Canvas Panel

  2. 添加 Vertical Box

    一条记录中的所有元素都包含在 Vertical Box

    勾选 Size To Content



Vertical Box

由两部分组成

  1. 添加 Overlay

  2. 添加 Spacer

    -
    Appearance > Size > Y 10, 纵向间隔



Overlay

由两部分组件; 其存在使得图片作为记录的背景

  1. 添加 Image

    用以高亮玩家信息

    修改变量名为 PlayerIndicatorImage , 之后会在代码中设置可见性

    -
    Appearance > Color and Opacity > Hex Linear 0028FFFF
    Appearance > Color and Opacity > A 0.5, 透明度
    Horizontal Alignment Fill
    Vertical Alignment Fill
    Behavior > Visibility Hidden, 默认不可见(不高亮)


  2. 添加 Horizontal Box

    记录文本


Horizontal Box

由5部分组成; 所有文本外均套有一个 Size Box; 为所有文本设置对齐方式; 为所有文本勾选 IsVariable , 并设置变量名

文本框默认内容 Size Box > Width Override Text > Appearance > Justification 对齐方式 变量名
PlayerName 400 默认左对齐 PlayerNameTextBlock
Kills 200 右对齐 KillsTextBlock
Deaths 200 右对齐 DeathsTextBlock
Team 200 右对齐 TeamTextBlock
  1. 添加 Text

    玩家名

    建议将文本框默认内容设为Name


  2. 添加 Text

    击杀数


  3. 添加 Text

    死亡次数

  4. 添加 Text

    阵营ID

  5. 添加 分隔符

    -
    Appearance > Size > X 50, 水平间隔



设计WBP_GameOverWidget


从WBP_PauseWidget拷贝已有设计

  1. 设置 Game Pause 文本居中


  2. 拷贝整个 Canvas Panel



设计WBP_GameOverWidget

  1. 粘贴 Canvas Panel


  2. 修改文本框内容


  3. 移除 Size Box

  4. 添加表头: WBP_PlayerStatRow

  5. 添加分隔符 Spacer

    -
    Appearance > Size > Y 40, 纵向间隔


  6. 添加垂直盒 Vertical Box , 用来存放玩家得分

    之后会在代码中往里添加记录: 勾选 Is Variable , 修改变量名为PlayerStatBox



修改STUGameModeBase设置游戏角色名称

如果是玩家操控的游戏角色, 设置名称为 Player , 将NPC命名为 Bot

ShootThemUp: STUGameModeBase.cpp

1// CreateTeamsInfo
2PlayerState->SetPlayerName(Controller->IsPlayerController() ? "Player" : "Bot");

另一种实现, 不建议使用 , 因为IsControlled已经过时了

 1const auto Pawn = Controller->GetPawn();
 2if (!Pawn) continue;
 3
 4if (Pawn->IsControlled())
 5{
 6    PlayerState->SetPlayerName("Player");
 7}
 8else
 9{
10    PlayerState->SetPlayerName("Bot");
11}

STUUtils添加静态函数: 将int32转换为FText

PlayerState中一些属性为int32类型, 而文本框内容设置接受FText类型

ShootThemUp: STUUtils.h

1static FText TextFromInt(int32 Number) { return FText::FromString(FString::FromInt(Number)); }

实现STUPlayerStatRowWidget


添加属性

变量: 文本框和图片

protected

ShootThemUp: UI/STUPlayerStatRowWidget.h

 1class UImage;
 2class UTextBlock;
 3
 4UPROPERTY(meta = (BindWidget))
 5UImage *PlayerIndicatorImage;
 6
 7UPROPERTY(meta = (BindWidget))
 8UTextBlock *PlayerNameTextBlock;
 9
10UPROPERTY(meta = (BindWidget))
11UTextBlock *KillsTextBlock;
12
13UPROPERTY(meta = (BindWidget))
14UTextBlock *DeathsTextBlock;
15
16UPROPERTY(meta = (BindWidget))
17UTextBlock *TeamTextBlock;

添加接口: 设置文本框内容, 设置高亮可见性

public

ShootThemUp: UI/STUPlayerStatRowWidget.h

1void SetPlayerIndicatorImageVisibility(bool Visible);
2void SetPlayerNameTextBlock(FString PlayerName);
3void SetKillsTextBlock(int32 Kills);
4void SetDeathsTextBlock(int32 Deaths);
5void SetTeamTextBlock(int32 TeamID);

ShootThemUp: UI/STUPlayerStatRowWidget.cpp

 1#include "STUUtils.h"
 2#include "Components/Image.h"
 3#include "Components/TextBlock.h"
 4
 5void USTUPlayerStatRowWidget::SetPlayerIndicatorImageVisibility(bool Visible)
 6{
 7    if (!PlayerIndicatorImage) return;
 8    PlayerIndicatorImage->SetVisibility(Visible ? ESlateVisibility::Visible : ESlateVisibility::Hidden);
 9}
10
11void USTUPlayerStatRowWidget::SetPlayerNameTextBlock(FString PlayerName)
12{
13    if (!PlayerNameTextBlock) return;
14    PlayerNameTextBlock->SetText(FText::FromString(PlayerName));
15}
16
17void USTUPlayerStatRowWidget::SetKillsTextBlock(int32 Kills)
18{
19    if (!KillsTextBlock) return;
20    KillsTextBlock->SetText(STUUtils::TextFromInt(Kills));
21}
22
23void USTUPlayerStatRowWidget::SetDeathsTextBlock(int32 Deaths)
24{
25    if (!DeathsTextBlock) return;
26    DeathsTextBlock->SetText(STUUtils::TextFromInt(Deaths));
27}
28
29void USTUPlayerStatRowWidget::SetTeamTextBlock(int32 TeamID)
30{
31    if (!TeamTextBlock) return;
32    TeamTextBlock->SetText(STUUtils::TextFromInt(TeamID));
33}

实现STUGameOverWidget


覆写Initialize, 注册游戏状态改变通知

ShootThemUp: UI/STUGameOverWidget.h

1#include "STUCoreTypes.h"
2
3// public
4virtual bool Initialize() override;
5
6// private
7void OnMatchStateChanged(ESTUMatchState NewState);

ShootThemUp: UI/STUGameOverWidget.cpp

 1#include "STUGameModeBase.h"
 2
 3bool USTUGameOverWidget::Initialize()
 4{
 5    if (GetWorld())
 6    {
 7        const auto GameMode = Cast<ASTUGameModeBase>(GetWorld()->GetAuthGameMode());
 8        if (GameMode)
 9        {
10            GameMode->OnMatchStateChanged.AddUObject(this, &USTUGameOverWidget::OnMatchStateChanged);
11        }
12    }
13
14    return Super::Initialize();
15}

添加属性: 记录盒

protected

ShootThemUp: UI/STUGameOverWidget.h

1class UVerticalBox;
2
3UPROPERTY(meta = (BindWidget))
4UVerticalBox *PlayerStatBox;

添加属性: 记录类型

protected

ShootThemUp: UI/STUGameOverWidget.h

1UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
2TSubclassOf<UUserWidget> PlayerStatRowWidgetClass;

添加美化函数: 往记录盒添加记录

private

ShootThemUp: UI/STUGameOverWidget.h

1void UpdatePlayersStat();

ShootThemUp: UI/STUGameOverWidget.cpp

 1#include "Player/STUPlayerState.h"
 2#include "UI/STUPlayerStatRowWidget.h"
 3#include "Components/VerticalBox.h"
 4
 5void USTUGameOverWidget::UpdatePlayersStat()
 6{
 7    if (!GetWorld() || !PlayerStatBox) return;
 8
 9    PlayerStatBox->ClearChildren();
10
11    for (auto It = GetWorld()->GetControllerIterator(); It; ++It)
12    {
13        const auto Controller = It->Get();
14        if (!Controller) continue;
15
16        const auto PlayerState = Cast<ASTUPlayerState>(Controller->PlayerState);
17        if (!PlayerState) continue;
18
19        const auto PlayerStatRowWidget = CreateWidget<USTUPlayerStatRowWidget>(GetWorld(), PlayerStatRowWidgetClass);
20        if (!PlayerStatRowWidget) continue;
21
22        PlayerStatRowWidget->SetPlayerNameTextBlock(PlayerState->GetPlayerName());
23        PlayerStatRowWidget->SetKillsTextBlock(PlayerState->GetKillsNum());
24        PlayerStatRowWidget->SetDeathsTextBlock(PlayerState->GetDeathsNum());
25        PlayerStatRowWidget->SetTeamTextBlock(PlayerState->GetTeamID());
26        PlayerStatRowWidget->SetPlayerIndicatorImageVisibility(Controller->IsPlayerController());
27
28        PlayerStatBox->AddChild(PlayerStatRowWidget);
29    }
30}

在处理函数中调用

ShootThemUp: UI/STUGameOverWidget.cpp

1void USTUGameOverWidget::OnMatchStateChanged(ESTUMatchState NewState)
2{
3    if (NewState == ESTUMatchState::GameOver)
4    {
5        UpdatePlayersStat();
6    }
7}

查看


验证

  1. 设置BP_STUGameHUD

    -
    GameOverWidgetClass WBP_GameOverWidget
  2. 设置WBP_GameOverWidget

    -
    PlayerStatRowWidgetClass WBP_PlayerStatRow


  3. 设置BP_STUGameModeBase

    -
    Rounds Num 1
    Round Time 3



存在问题

设置BP_STUGameModeBase

-
Players Num 20



为记录盒添加滚动条

  1. 为记录盒添加滚动盒


    此时运行, 无改变, 因为垂直盒勾选了 Size To Content

  2. 为滚动盒添加大小盒

    设置最大高度

    -
    Max Desired Height 300


  3. 查看

    记录盒上方和下方都有阴影, 滚动条轨迹不可见


  4. 优化滚动盒阴影


  5. 始终显示滚动条轨迹, 设置滚动条宽度



再次查看

  1. 滚动条效果


  2. 恢复玩家数

    BP_STUGameModeBase

    -
    Players Num 4

    因为大小盒高度不足300, 所以不显示滚动条