六一的部落格


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



Design Update / Refactoring


素材


字体


武器图片

均来自 Pixabay , 步枪和榴弹发射器长宽比接近 1:3 , 弹匣长宽比为 1:2


用于显示阵营颜色的图片



主菜单退出按钮图片

pixabay



窗口部件背景图

  • 按钮

    300x100

    普通状态



    鼠标悬浮



  • 生命条

    430x40


  • 武器

    430x150



调整武器图片

参照武器背景图, 择定位置, 加上透明填充. 这样做的好处在于武器的显示不受文本变化的影响. 当然, 为文本添加大小盒也是可以解决的

430x150




导入素材

拖入文件夹, 移动作为 Content/ExternalContent/DesignUpdate


说明

修改繁多, 以适合为重, 用以参考


API导航


Button

1UPROPERTY( BlueprintAssignable, Category = "Button|Event" )
2FOnButtonHoverEvent OnHovered;
3
4UPROPERTY( BlueprintAssignable, Category = "Button|Event" )
5FOnButtonHoverEvent OnUnhovered;

Image

1/**  */
2UFUNCTION(BlueprintCallable, Category="Appearance")
3void SetColorAndOpacity(FLinearColor InColorAndOpacity);

FString

  1. ChrN

    使用指定个数个前缀填充字符串
    1/**
    2​ * Returns a string that is full of a variable number of characters
    3 *
    4​ * @param NumCharacters Number of characters to put into the string
    5​ * @param Char Character to put into the string
    6​ * 
    7​ * @return The string of NumCharacters characters.
    8 */
    9 UE_NODISCARD static FString ChrN( int32 NumCharacters, TCHAR Char );
  2. Append

    在尾部追加字符串
    1/** Append a string and return a reference to this */
    2template <typename CharRangeType, typename TEnableIf<TIsCharRangeNotCArray<CharRangeType>::Value>::Type* = nullptr>
    3FORCEINLINE FString& Append(CharRangeType&& Str)
    4{
    5    AppendChars(GetData(Str), GetNum(Str));
    6    return *this;
    7}
  3. Len

    获取字符串长度
    1/** Get the length of the string, excluding terminating character */
    2UE_NODISCARD FORCEINLINE int32 Len() const
    3{
    4    return Data.Num() ? Data.Num() - 1 : 0;
    5}

窗口部件整理

  1. WBP_HealthBar
  2. WBP_Menu
    • WBP_LevelItem
    • WBP_ReturnToMainMenu
  3. WBP_PauseWidget
    • WBP_ReturnToMainMenu
  4. WBP_GameOverWidget
    • WBP_PlayerStatRow
    • WBP_ReturnToMainMenu
  5. WBP_AboveHUD

    已根据玩家是否存活, 玩家是否作为观察者来决定显示哪个HUD
    • WBP_SpectatorHUD
    • WBP_PlayerHUD
      • WBP_GameData

主菜单修改

移除 ExponentialHeightFog


使用烟雾特效


创建Niagara粒子系统

使用 Content/VFX/Projectile/NE_Smoke, 命名为NS_MenuSmoke

移动到 Content/Menu/UI , 双击打开

  1. 修改烟雾颜色变化: 由白色变为红色


    X Y Z 颜色
    起点 (0, 1) (0, 1) (0, 1) 白色
    终点 (1, 1) (1, 0) (1, 0) 红色


  2. 设置粒子数


  3. 修改粒子生存期


  4. 设置特效循环



修改关卡

  1. 关卡中添加PlayerStart


  2. 添加粒子系统



修改WBP_Menu

  1. 把内容移动到左上方



  2. 添加文本框: 提示选择关卡


  3. 添加分隔符: 分隔提示和关卡选项


  4. 设置按钮左对齐


  5. 设置游戏标题


  6. 设置提示文本


  7. 修改按钮背景和点击填充


  8. 修改按钮文本



修改退出按钮

为大小盒添加下级 Overlay

Overlay由两部分组成, 按钮文本和提示图片组成的水平盒, 以及与水平盒重合的按钮


修改大小盒大小


  • 水平盒

    由三部分组成, 复用按钮文本, 分隔符, 和包裹提示图片的大小盒


    1. 设置水平盒


    2. 设置按钮文本样式


    3. 设置间隔


    4. 设置图片大小盒: 保证图片为正方形


    5. 设置图片


  • 按钮

    1. 平铺, 取消样式


    2. 透明


    点击时是没效果滴~


选中关卡时, 叠加红色透明图片, 鼠标在关卡之上悬浮时, 显示红框


选中时, 使选中项有红色阴影

推荐 方法二

  • 方法一: 叠加红色透明图片

    • 修改WBP_LevelItem

      添加图片


    • 修改STULevelItemWidget

      1. 添加属性: 叠加图片

        protected

        ShootThemUp: Menu/UI/STULevelItemWidget.h
        1UPROPERTY(meta = (BindWidget))
        2UImage *CoverImage;
      2. 添加接口: 设置CoverImage可见性

        public

        ShootThemUp: Menu/UI/STULevelItemWidget.h
        1void SetCoverImageVisibility(bool Visible);
        ShootThemUp: Menu/UI/STULevelItemWidget.cpp
        1void USTULevelItemWidget::SetCoverImageVisibility(bool Visible)
        2{
        3    if (!CoverImage) return;
        4    CoverImage->SetVisibility(Visible ? ESlateVisibility::Visible : ESlateVisibility::Hidden);
        5}
    • 修改STUMenuWIdget

      ShootThemUp: Menu/UI/STUMenuWidget.cpp

      1// OnLevelSelected
      2
      3// LevelItem->SetFrameImageVisibility(LevelItem->GetLevelData().LevelName == LevelData.LevelName);
      4LevelItem->SetCoverImageVisibility(LevelItem->GetLevelData().LevelName == LevelData.LevelName);
  • 方法二: 选中时, 设置关卡缩略图颜色

    • 修改STULevelItemWidget

      添加接口: 设置关卡缩略图颜色

      public

      ShootThemUp: Menu/UI/STULevelItemWidget.h

      1void SetLevelImageColor(bool Selected);

      ShootThemUp: Menu/UI/STULevelItemWidget.cpp

      1void USTULevelItemWidget::SetLevelImageColor(bool Selected)
      2{
      3    LevelImage->SetColorAndOpacity(Selected ? FLinearColor::Red : FLinearColor::White);
      4}
    • 修改STUMenuWIdget

      ShootThemUp: Menu/UI/STUMenuWidget.cpp

      1// OnLevelSelected
      2
      3// LevelItem->SetCoverImageVisibility(LevelItem->GetLevelData().LevelName == LevelData.LevelName);
      4LevelItem->SetLevelImageColor(LevelItem->GetLevelData().LevelName == LevelData.LevelName);

鼠标悬浮时, 显示红框, 鼠标离开时, 移除红框

STULevelItemWidget

  1. 添加鼠标悬浮事件回调函数

    private

    ShootThemUp: Menu/UI/STULevelItemWidget.h

    1UFUNCTION()
    2void OnLevelHover();
    3
    4UFUNCTION()
    5void OnLevelUnHover();

    ShootThemUp: Menu/UI/STULevelItemWidget.cpp

    1void USTULevelItemWidget::OnLevelHover()
    2{
    3    SetFrameImageVisibility(true);
    4}
    5
    6void USTULevelItemWidget::OnLevelUnHover()
    7{
    8    SetFrameImageVisibility(false);
    9}
  2. 注册

    ShootThemUp: Menu/UI/STULevelItemWidget.cpp

    1// NativeOnInitialized
    2
    3LevelSelectButton->OnHovered.AddDynamic(this, &USTULevelItemWidget::OnLevelHover);
    4LevelSelectButton->OnUnhovered.AddDynamic(this, &USTULevelItemWidget::OnLevelUnHover);

调整

WBP_LevelItem

按钮必须在最后, 才能正确触发悬浮和点击



查看



修改WBP_ReturnToMainMenu

  1. 设置按钮

    按钮一般在右方


  2. 设置按钮文本



暂停菜单修改

  1. 修改暂停标题


  2. 修改按钮


  3. 修改按钮文本


  4. 修改间隔符



游戏结束菜单修改

  1. 把表头和表项窗口部件分开
  2. 既可以显示阵营编号, 也可以显示阵营颜色

分开记录和表头


修改WBP_PlayerStatRow

  1. 将水平盒最后的分隔符移到最前


  2. 设置高亮色

    PlayerIndicatorImage

    -
    Hex Linear 1C191E80
  3. 修改PlayerName默认文本为Name

  4. 设置文本框

    对齐 字体 字号 阴影 阴影颜色
    PLayerName 左对齐 BarlowCondensed-SemiBold 30 X = Y = 1.5 000000FF
    Kills 居中 同上 同上 同上 同上
    Deaths 居中 同上 同上 同上 同上
    Team 居中 同上 同上 同上 同上

    善用Copy和Paste



拷贝WBP_PlayerStatRow获得表头, 命名为WBP_PlayerStatRowHead, 更改WBP_PlayerStatRowHead基类为UserWidget


修改WBP_PlayerStatRow, 更换字体

字体
PLayerName BarlowCondensed-Regular
Kills 同上
Deaths 同上
Team 同上

替换WBP_GameOverWidget中表头为WBP_PlayerStatRowHead


使用图片标识阵营


修改WBP_PlayerStatRow

  1. 为TeamTextBlock添加上级 Widget Switcher

    Widget Switcher 可以有多个下级元素, 同一时间只显示其中一个

  2. Widget Switcher 中添加 Image


  3. 设置当前使用图片标识Team, 即第二个元素, 索引为1



修改STUPlayerStatRowWidget

  1. 添加属性: 阵营图片

    protected

    ShootThemUp: UI/STUPlayerStatRowWidget.h
    1UPROPERTY(meta = (BindWidget))
    2UImage *TeamImage;
  2. 添加接口: 设置图片颜色

    public

    ShootThemUp: UI/STUPlayerStatRowWidget.h
    1void SetTeamImageColor(const FLinearColor &Color);
    ShootThemUp: UI/STUPlayerStatRowWidget.cpp
    1void USTUPlayerStatRowWidget::SetTeamImageColor(const FLinearColor &Color)
    2{
    3    if (!TeamImage) return;
    4    TeamImage->SetColorAndOpacity(Color);
    5}

在STUGameOverWidget中设置记录中的阵营颜色

ShootThemUp: UI/STUGameOverWidget.cpp

  • 方法一: 脑子抽了的人就会这么写

    STUGameModeBase添加接口: 返回游戏规则

    public

    ShootThemUp: STUGameModeBase.h
    1FGameData GetGameData() const { return GameData; }
    之前使用该数据成员分量时, 提醒过建议自行取出分量
     1#include "STUGameModeBase.h"
     2
     3// UpdatePlayersStat
     4
     5if (GetWorld())
     6{
     7    const auto GameMode = Cast<ASTUGameModeBase>(GetWorld()->GetAuthGameMode());
     8    if (GameMode)
     9    {
    10        const auto TeamID = PlayerState->GetTeamID();
    11        PlayerStatRowWidget->SetTeamImageColor(GameMode->GetGameData().TeamColors[TeamID - 1]);
    12    }
    13}
    TeamID显示用, 从1开始计数
  • 方法二
    1PlayerStatRowWidget->SetTeamImageColor(PlayerState->GetTeamColor());

查看

BP_STUGameModeBase

  1. 修改阵营颜色: 如果Alpha通道为0, 无显示; 材质对于这类型配置认为Alpha通道为1
  2. 修改 Round Time 为3, 方便测试



修改WBP_GameOverWidget

  1. 修改标题


  2. 修改按钮


  3. 修改按钮文本


  4. 修改按钮间间隔



查看



弹药库显示

剩余子弹数由十位数变为个位数, 在视觉上有跳动. 保持字符串占3个字符, 使用0填充

这个还依赖于等宽字体, 只是减少感官上的跳动


添加辅助函数: 使得剩余子弹数不跳动

protected

ShootThemUp: UI/STUPlayerHUDWidget.h

1UFUNCTION()
2FString FormatBullets(int32 BulletsNum) const;

ShootThemUp: UI/STUPlayerHUDWidget.cpp

 1FString USTUPlayerHUDWidget::FormatBullets(int32 BulletsNum) const
 2{
 3    const int32 MaxLen = 3;
 4    const TCHAR Prefix = '0'; /* PrefixSymbol */
 5
 6    FString Str = FString::FromInt(BulletsNum); /* BulletStr */
 7    const auto Rest = MaxLen - Str.Len(); /* SymbolsNumToAdd */
 8    if (Rest > 0)
 9    {
10        Str = FString::ChrN(Rest, Prefix).Append(Str);
11    }
12
13    return Str;
14}

设置武器示意图标




修改WBP_PlayerHUD弹药库显示

只讲结果, 自行组装

  1. 最外层是大小盒, 位于右下角, 高度和宽度与图片大小一致 430x150


  2. 第二层是Overlay, 因为图片要作为背景

    Overlay由三部分组成, 背景图, 武器矢量图, 和包含弹药库信息的水平盒. 背景图作为最下层, 必须排在第一个


Overlay

  1. 背景图


  2. 武器矢量图

    绑定函数 Get Weapon Icon


    之前的实现里, 会修改图片颜色, 现在已不需要


  3. 水平盒

    由两部分组成

    • 分隔: X = 25
    • 存放弹药信息的垂直盒

存放弹药信息的垂直盒

由三部分组成

  • 间隔: Y = 20
  • 子弹数
  • 弹匣图片和弹匣数组成的水平盒



子弹数


绑定函数 Get_Ammo_Bullets



弹匣图片和弹匣数组成的水平盒

由四部分组成

  • 分隔: X = 7
  • 弹匣图片的上级大小盒
  • 分隔: X = 5
  • 弹匣数



弹匣图片的上级大小盒

  1. 大小盒

    图片长宽比为1:2, 大小盒的长宽比与之一致


  2. 图片

    金色
    Hex Linear FF9940FF



弹匣数


文本绑定 Get_Ammo_Clips



回合数

WBP_GameData左上角显示回合数和当前回合倒计时

击杀数和死亡次数的显示稍后调整


垂直盒包含所有信息, 位于屏幕左上角




垂直盒由三部分组成

  • 回合数


  • 间隔 Y = 20

  • 回合剩余时长



生命条显示

将生命条窗口部件从WBP_PlayerHUD移动到WBP_GameData

生命条和击杀死亡信息组合显示


实现生命条逻辑, 打包击杀死亡信息


修改STUGameDataWidget

提供接口: 返回生命百分比

public

ShootThemUp: UI/STUGameDataWidget.h

1UFUNCTION(BlueprintCallable)
2float GetHealthPercent() const;

ShootThemUp: UI/STUGameDataWidget.cpp

 1#include "STUUtils.h"
 2#include "Components/STUHealthComponent.h"
 3
 4float USTUGameDataWidget::GetHealthPercent() const
 5{
 6    const auto HealthComponent = STUUtils::GetSTUPlayerComponent<USTUHealthComponent>(GetOwningPlayerPawn());
 7    if (!HealthComponent) return 0.0f;
 8
 9    return HealthComponent->GetHealthPercent();
10}

修改STUPlayerHUDWidget

屏蔽获取生命百分比逻辑


修改WBP_PlayerHUD

移除蓝图函数 Get Health Percent 中无效节点


修改WBP_GameData

  • 包含生命条和击杀死亡信息的垂直盒

    位于屏幕左下角



  • 击杀死亡信息

    顶级为水平盒, 由7部分组成. 中间为分隔, 左右两边的样式一样, 就不赘述了


    • 击杀数文本



    • 间隔: X = 10

    • 包含提示信息的垂直盒

      由两部分组成

      • 间隔: Y = 35

      • 提示文本


    • 间隔: X = 100

      分隔击杀数和死亡数

    • 死亡数文本



    • 间隔: X = 10

    • 包含提示信息的垂直盒

  • 生命条

    顶级为Overlay, 由两部分组成

    • 包含背景图的大小盒


      背景图


    • 进度条




修改WBP_PlayerHUD

顶级Overlay, 由两部分组成

  • WBP_GameData


  • 其他


    注意受伤告警图片铺满屏幕




低血量提示

protected

ShootThemUp: UI/STUGameDataWidget.h

 1class UProgressBar;
 2
 3UPROPERTY(meta = (BindWidget))
 4UProgressBar *HealthProgressBar;
 5
 6UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
 7float PercentColorThreshold = 0.3f;
 8
 9UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
10FLinearColor GoodColor = FLinearColor::Green;
11
12UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
13FLinearColor BadColor = FLinearColor::Red;

ShootThemUp: UI/STUGameDataWidget.cpp

1#include "Components/ProgressBar.h"
2
3// GetHealthPercent
4
5if (HealthProgressBar)
6{
7    HealthProgressBar->SetFillColorAndOpacity(HealthComponent->GetHealthPercent() > PercentColorThreshold ? GoodColor : BadColor);
8}

查看






打包设置

打包

当前一共有4个关卡, 如果打包,需要指定主菜单之外的关卡路径

Edit > Project Setting.. > Project > Packaging

Packaging > Advanced


关卡数组


设计优化


Design Update / Refactoring


素材


字体


武器图片

均来自 Pixabay , 步枪和榴弹发射器长宽比接近 1:3 , 弹匣长宽比为 1:2


用于显示阵营颜色的图片



主菜单退出按钮图片

pixabay



窗口部件背景图

  • 按钮

    300x100

    普通状态



    鼠标悬浮



  • 生命条

    430x40


  • 武器

    430x150



调整武器图片

参照武器背景图, 择定位置, 加上透明填充. 这样做的好处在于武器的显示不受文本变化的影响. 当然, 为文本添加大小盒也是可以解决的

430x150




导入素材

拖入文件夹, 移动作为 Content/ExternalContent/DesignUpdate


说明

修改繁多, 以适合为重, 用以参考


API导航


Button

1UPROPERTY( BlueprintAssignable, Category = "Button|Event" )
2FOnButtonHoverEvent OnHovered;
3
4UPROPERTY( BlueprintAssignable, Category = "Button|Event" )
5FOnButtonHoverEvent OnUnhovered;

Image

1/**  */
2UFUNCTION(BlueprintCallable, Category="Appearance")
3void SetColorAndOpacity(FLinearColor InColorAndOpacity);

FString

  1. ChrN

    使用指定个数个前缀填充字符串
    1/**
    2​ * Returns a string that is full of a variable number of characters
    3 *
    4​ * @param NumCharacters Number of characters to put into the string
    5​ * @param Char Character to put into the string
    6​ * 
    7​ * @return The string of NumCharacters characters.
    8 */
    9 UE_NODISCARD static FString ChrN( int32 NumCharacters, TCHAR Char );
  2. Append

    在尾部追加字符串
    1/** Append a string and return a reference to this */
    2template <typename CharRangeType, typename TEnableIf<TIsCharRangeNotCArray<CharRangeType>::Value>::Type* = nullptr>
    3FORCEINLINE FString& Append(CharRangeType&& Str)
    4{
    5    AppendChars(GetData(Str), GetNum(Str));
    6    return *this;
    7}
  3. Len

    获取字符串长度
    1/** Get the length of the string, excluding terminating character */
    2UE_NODISCARD FORCEINLINE int32 Len() const
    3{
    4    return Data.Num() ? Data.Num() - 1 : 0;
    5}

窗口部件整理

  1. WBP_HealthBar
  2. WBP_Menu
    • WBP_LevelItem
    • WBP_ReturnToMainMenu
  3. WBP_PauseWidget
    • WBP_ReturnToMainMenu
  4. WBP_GameOverWidget
    • WBP_PlayerStatRow
    • WBP_ReturnToMainMenu
  5. WBP_AboveHUD

    已根据玩家是否存活, 玩家是否作为观察者来决定显示哪个HUD
    • WBP_SpectatorHUD
    • WBP_PlayerHUD
      • WBP_GameData

主菜单修改

移除 ExponentialHeightFog


使用烟雾特效


创建Niagara粒子系统

使用 Content/VFX/Projectile/NE_Smoke, 命名为NS_MenuSmoke

移动到 Content/Menu/UI , 双击打开

  1. 修改烟雾颜色变化: 由白色变为红色


    X Y Z 颜色
    起点 (0, 1) (0, 1) (0, 1) 白色
    终点 (1, 1) (1, 0) (1, 0) 红色


  2. 设置粒子数


  3. 修改粒子生存期


  4. 设置特效循环



修改关卡

  1. 关卡中添加PlayerStart


  2. 添加粒子系统



修改WBP_Menu

  1. 把内容移动到左上方



  2. 添加文本框: 提示选择关卡


  3. 添加分隔符: 分隔提示和关卡选项


  4. 设置按钮左对齐


  5. 设置游戏标题


  6. 设置提示文本


  7. 修改按钮背景和点击填充


  8. 修改按钮文本



修改退出按钮

为大小盒添加下级 Overlay

Overlay由两部分组成, 按钮文本和提示图片组成的水平盒, 以及与水平盒重合的按钮


修改大小盒大小


  • 水平盒

    由三部分组成, 复用按钮文本, 分隔符, 和包裹提示图片的大小盒


    1. 设置水平盒


    2. 设置按钮文本样式


    3. 设置间隔


    4. 设置图片大小盒: 保证图片为正方形


    5. 设置图片


  • 按钮

    1. 平铺, 取消样式


    2. 透明


    点击时是没效果滴~


选中关卡时, 叠加红色透明图片, 鼠标在关卡之上悬浮时, 显示红框


选中时, 使选中项有红色阴影

推荐 方法二

  • 方法一: 叠加红色透明图片

    • 修改WBP_LevelItem

      添加图片


    • 修改STULevelItemWidget

      1. 添加属性: 叠加图片

        protected

        ShootThemUp: Menu/UI/STULevelItemWidget.h
        1UPROPERTY(meta = (BindWidget))
        2UImage *CoverImage;
      2. 添加接口: 设置CoverImage可见性

        public

        ShootThemUp: Menu/UI/STULevelItemWidget.h
        1void SetCoverImageVisibility(bool Visible);
        ShootThemUp: Menu/UI/STULevelItemWidget.cpp
        1void USTULevelItemWidget::SetCoverImageVisibility(bool Visible)
        2{
        3    if (!CoverImage) return;
        4    CoverImage->SetVisibility(Visible ? ESlateVisibility::Visible : ESlateVisibility::Hidden);
        5}
    • 修改STUMenuWIdget

      ShootThemUp: Menu/UI/STUMenuWidget.cpp

      1// OnLevelSelected
      2
      3// LevelItem->SetFrameImageVisibility(LevelItem->GetLevelData().LevelName == LevelData.LevelName);
      4LevelItem->SetCoverImageVisibility(LevelItem->GetLevelData().LevelName == LevelData.LevelName);
  • 方法二: 选中时, 设置关卡缩略图颜色

    • 修改STULevelItemWidget

      添加接口: 设置关卡缩略图颜色

      public

      ShootThemUp: Menu/UI/STULevelItemWidget.h

      1void SetLevelImageColor(bool Selected);

      ShootThemUp: Menu/UI/STULevelItemWidget.cpp

      1void USTULevelItemWidget::SetLevelImageColor(bool Selected)
      2{
      3    LevelImage->SetColorAndOpacity(Selected ? FLinearColor::Red : FLinearColor::White);
      4}
    • 修改STUMenuWIdget

      ShootThemUp: Menu/UI/STUMenuWidget.cpp

      1// OnLevelSelected
      2
      3// LevelItem->SetCoverImageVisibility(LevelItem->GetLevelData().LevelName == LevelData.LevelName);
      4LevelItem->SetLevelImageColor(LevelItem->GetLevelData().LevelName == LevelData.LevelName);

鼠标悬浮时, 显示红框, 鼠标离开时, 移除红框

STULevelItemWidget

  1. 添加鼠标悬浮事件回调函数

    private

    ShootThemUp: Menu/UI/STULevelItemWidget.h

    1UFUNCTION()
    2void OnLevelHover();
    3
    4UFUNCTION()
    5void OnLevelUnHover();

    ShootThemUp: Menu/UI/STULevelItemWidget.cpp

    1void USTULevelItemWidget::OnLevelHover()
    2{
    3    SetFrameImageVisibility(true);
    4}
    5
    6void USTULevelItemWidget::OnLevelUnHover()
    7{
    8    SetFrameImageVisibility(false);
    9}
  2. 注册

    ShootThemUp: Menu/UI/STULevelItemWidget.cpp

    1// NativeOnInitialized
    2
    3LevelSelectButton->OnHovered.AddDynamic(this, &USTULevelItemWidget::OnLevelHover);
    4LevelSelectButton->OnUnhovered.AddDynamic(this, &USTULevelItemWidget::OnLevelUnHover);

调整

WBP_LevelItem

按钮必须在最后, 才能正确触发悬浮和点击



查看



修改WBP_ReturnToMainMenu

  1. 设置按钮

    按钮一般在右方


  2. 设置按钮文本



暂停菜单修改

  1. 修改暂停标题


  2. 修改按钮


  3. 修改按钮文本


  4. 修改间隔符



游戏结束菜单修改

  1. 把表头和表项窗口部件分开
  2. 既可以显示阵营编号, 也可以显示阵营颜色

分开记录和表头


修改WBP_PlayerStatRow

  1. 将水平盒最后的分隔符移到最前


  2. 设置高亮色

    PlayerIndicatorImage

    -
    Hex Linear 1C191E80
  3. 修改PlayerName默认文本为Name

  4. 设置文本框

    对齐 字体 字号 阴影 阴影颜色
    PLayerName 左对齐 BarlowCondensed-SemiBold 30 X = Y = 1.5 000000FF
    Kills 居中 同上 同上 同上 同上
    Deaths 居中 同上 同上 同上 同上
    Team 居中 同上 同上 同上 同上

    善用Copy和Paste



拷贝WBP_PlayerStatRow获得表头, 命名为WBP_PlayerStatRowHead, 更改WBP_PlayerStatRowHead基类为UserWidget


修改WBP_PlayerStatRow, 更换字体

字体
PLayerName BarlowCondensed-Regular
Kills 同上
Deaths 同上
Team 同上

替换WBP_GameOverWidget中表头为WBP_PlayerStatRowHead


使用图片标识阵营


修改WBP_PlayerStatRow

  1. 为TeamTextBlock添加上级 Widget Switcher

    Widget Switcher 可以有多个下级元素, 同一时间只显示其中一个

  2. Widget Switcher 中添加 Image


  3. 设置当前使用图片标识Team, 即第二个元素, 索引为1



修改STUPlayerStatRowWidget

  1. 添加属性: 阵营图片

    protected

    ShootThemUp: UI/STUPlayerStatRowWidget.h
    1UPROPERTY(meta = (BindWidget))
    2UImage *TeamImage;
  2. 添加接口: 设置图片颜色

    public

    ShootThemUp: UI/STUPlayerStatRowWidget.h
    1void SetTeamImageColor(const FLinearColor &Color);
    ShootThemUp: UI/STUPlayerStatRowWidget.cpp
    1void USTUPlayerStatRowWidget::SetTeamImageColor(const FLinearColor &Color)
    2{
    3    if (!TeamImage) return;
    4    TeamImage->SetColorAndOpacity(Color);
    5}

在STUGameOverWidget中设置记录中的阵营颜色

ShootThemUp: UI/STUGameOverWidget.cpp

  • 方法一: 脑子抽了的人就会这么写

    STUGameModeBase添加接口: 返回游戏规则

    public

    ShootThemUp: STUGameModeBase.h
    1FGameData GetGameData() const { return GameData; }
    之前使用该数据成员分量时, 提醒过建议自行取出分量
     1#include "STUGameModeBase.h"
     2
     3// UpdatePlayersStat
     4
     5if (GetWorld())
     6{
     7    const auto GameMode = Cast<ASTUGameModeBase>(GetWorld()->GetAuthGameMode());
     8    if (GameMode)
     9    {
    10        const auto TeamID = PlayerState->GetTeamID();
    11        PlayerStatRowWidget->SetTeamImageColor(GameMode->GetGameData().TeamColors[TeamID - 1]);
    12    }
    13}
    TeamID显示用, 从1开始计数
  • 方法二
    1PlayerStatRowWidget->SetTeamImageColor(PlayerState->GetTeamColor());

查看

BP_STUGameModeBase

  1. 修改阵营颜色: 如果Alpha通道为0, 无显示; 材质对于这类型配置认为Alpha通道为1
  2. 修改 Round Time 为3, 方便测试



修改WBP_GameOverWidget

  1. 修改标题


  2. 修改按钮


  3. 修改按钮文本


  4. 修改按钮间间隔



查看



弹药库显示

剩余子弹数由十位数变为个位数, 在视觉上有跳动. 保持字符串占3个字符, 使用0填充

这个还依赖于等宽字体, 只是减少感官上的跳动


添加辅助函数: 使得剩余子弹数不跳动

protected

ShootThemUp: UI/STUPlayerHUDWidget.h

1UFUNCTION()
2FString FormatBullets(int32 BulletsNum) const;

ShootThemUp: UI/STUPlayerHUDWidget.cpp

 1FString USTUPlayerHUDWidget::FormatBullets(int32 BulletsNum) const
 2{
 3    const int32 MaxLen = 3;
 4    const TCHAR Prefix = '0'; /* PrefixSymbol */
 5
 6    FString Str = FString::FromInt(BulletsNum); /* BulletStr */
 7    const auto Rest = MaxLen - Str.Len(); /* SymbolsNumToAdd */
 8    if (Rest > 0)
 9    {
10        Str = FString::ChrN(Rest, Prefix).Append(Str);
11    }
12
13    return Str;
14}

设置武器示意图标




修改WBP_PlayerHUD弹药库显示

只讲结果, 自行组装

  1. 最外层是大小盒, 位于右下角, 高度和宽度与图片大小一致 430x150


  2. 第二层是Overlay, 因为图片要作为背景

    Overlay由三部分组成, 背景图, 武器矢量图, 和包含弹药库信息的水平盒. 背景图作为最下层, 必须排在第一个


Overlay

  1. 背景图


  2. 武器矢量图

    绑定函数 Get Weapon Icon


    之前的实现里, 会修改图片颜色, 现在已不需要


  3. 水平盒

    由两部分组成

    • 分隔: X = 25
    • 存放弹药信息的垂直盒

存放弹药信息的垂直盒

由三部分组成

  • 间隔: Y = 20
  • 子弹数
  • 弹匣图片和弹匣数组成的水平盒



子弹数


绑定函数 Get_Ammo_Bullets



弹匣图片和弹匣数组成的水平盒

由四部分组成

  • 分隔: X = 7
  • 弹匣图片的上级大小盒
  • 分隔: X = 5
  • 弹匣数



弹匣图片的上级大小盒

  1. 大小盒

    图片长宽比为1:2, 大小盒的长宽比与之一致


  2. 图片

    金色
    Hex Linear FF9940FF



弹匣数


文本绑定 Get_Ammo_Clips



回合数

WBP_GameData左上角显示回合数和当前回合倒计时

击杀数和死亡次数的显示稍后调整


垂直盒包含所有信息, 位于屏幕左上角




垂直盒由三部分组成

  • 回合数


  • 间隔 Y = 20

  • 回合剩余时长



生命条显示

将生命条窗口部件从WBP_PlayerHUD移动到WBP_GameData

生命条和击杀死亡信息组合显示


实现生命条逻辑, 打包击杀死亡信息


修改STUGameDataWidget

提供接口: 返回生命百分比

public

ShootThemUp: UI/STUGameDataWidget.h

1UFUNCTION(BlueprintCallable)
2float GetHealthPercent() const;

ShootThemUp: UI/STUGameDataWidget.cpp

 1#include "STUUtils.h"
 2#include "Components/STUHealthComponent.h"
 3
 4float USTUGameDataWidget::GetHealthPercent() const
 5{
 6    const auto HealthComponent = STUUtils::GetSTUPlayerComponent<USTUHealthComponent>(GetOwningPlayerPawn());
 7    if (!HealthComponent) return 0.0f;
 8
 9    return HealthComponent->GetHealthPercent();
10}

修改STUPlayerHUDWidget

屏蔽获取生命百分比逻辑


修改WBP_PlayerHUD

移除蓝图函数 Get Health Percent 中无效节点


修改WBP_GameData

  • 包含生命条和击杀死亡信息的垂直盒

    位于屏幕左下角



  • 击杀死亡信息

    顶级为水平盒, 由7部分组成. 中间为分隔, 左右两边的样式一样, 就不赘述了


    • 击杀数文本



    • 间隔: X = 10

    • 包含提示信息的垂直盒

      由两部分组成

      • 间隔: Y = 35

      • 提示文本


    • 间隔: X = 100

      分隔击杀数和死亡数

    • 死亡数文本



    • 间隔: X = 10

    • 包含提示信息的垂直盒

  • 生命条

    顶级为Overlay, 由两部分组成

    • 包含背景图的大小盒


      背景图


    • 进度条




修改WBP_PlayerHUD

顶级Overlay, 由两部分组成

  • WBP_GameData


  • 其他


    注意受伤告警图片铺满屏幕




低血量提示

protected

ShootThemUp: UI/STUGameDataWidget.h

 1class UProgressBar;
 2
 3UPROPERTY(meta = (BindWidget))
 4UProgressBar *HealthProgressBar;
 5
 6UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
 7float PercentColorThreshold = 0.3f;
 8
 9UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
10FLinearColor GoodColor = FLinearColor::Green;
11
12UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
13FLinearColor BadColor = FLinearColor::Red;

ShootThemUp: UI/STUGameDataWidget.cpp

1#include "Components/ProgressBar.h"
2
3// GetHealthPercent
4
5if (HealthProgressBar)
6{
7    HealthProgressBar->SetFillColorAndOpacity(HealthComponent->GetHealthPercent() > PercentColorThreshold ? GoodColor : BadColor);
8}

查看






打包设置

打包

当前一共有4个关卡, 如果打包,需要指定主菜单之外的关卡路径

Edit > Project Setting.. > Project > Packaging

Packaging > Advanced


关卡数组