六一的部落格


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



Game Pause


说明

根据上节游戏状态, 会有3个窗口部件

游戏状态 窗口部件
InProgress WBP_PlayerHUDWidget
Pause WBP_PauseHUDWidget 暂停, 可选择继续 - 本节内容
GameOver 游戏结束, 显示统计数据 - 下节内容

本节实现暂停窗口: 游戏中按下 P 显示暂停窗口, 可于暂停窗口选择回到游戏


概览

  • 在STUGameHUD创建三种窗口部件
  • 依据游戏状态, 设置窗口部件可见性
  • 实现暂停窗口部件
  • 实现键位绑定

API导航


TMap

关联容器

-
Add 添加元素
[] 键作为下标, 获取值
Contains 查询是否存在给定键

TPair

键值对

-
::Value 获得键值对的值

UserWidget


可见性

  • UUserWidget::SetVisibility

    设置窗口组件可见性

    1/** Sets the visibility of the widget. */
    2virtual void SetVisibility(ESlateVisibility InVisibility) override;
  • ESlateVisibility

    可见选项

    -
    Visible 可见
    Hidden 隐藏
     1/** Is an entity visible? */
     2UENUM(BlueprintType)
     3enum class ESlateVisibility : uint8
     4{
     5    /** Visible and hit-testable (can interact with cursor). Default value. */
     6    Visible,
     7    /** Not visible and takes up no space in the layout (obviously not hit-testable). */
     8    Collapsed,
     9    /** Not visible but occupies layout space (obviously not hit-testable). */
    10    Hidden,
    11    /** Visible but not hit-testable (cannot interact with cursor) and children in the hierarchy (if any) are also not hit-testable. */
    12    HitTestInvisible UMETA(DisplayName = "Not Hit-Testable (Self & All Children)"),
    13    /** Visible but not hit-testable (cannot interact with cursor) and doesn't affect hit-testing on children (if any). */
    14    SelfHitTestInvisible UMETA(DisplayName = "Not Hit-Testable (Self Only)")
    15};

初始化

1virtual bool Initialize();

PlayerController


键位绑定所在

1/** Allows the PlayerController to set up custom input bindings. */
2virtual void SetupInputComponent();

成员InputComponent没在头文件中找到定义


鼠标受控

bShowMouseCursor
true 显示鼠标箭头
false 不显示鼠标箭头
1/** Whether the mouse cursor should be displayed. */
2UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=MouseInterface)
3uint32 bShowMouseCursor:1;

设置

1/** Setup an input mode. */
2virtual void SetInputMode(const FInputModeDataBase& InData);
FInputModeDataBase派生类
FInputModeUIOnly 只有UI可以响应用户输入
FInputModeGameOnly 只有玩家输入和PlayerController可以响应用户输入
FInputModeGameAndUI UI优先响应用户输入, 如果UI未作出处理, 玩家输入和PlayerController可以响应用户输入
 1/** Data structure used to setup an input mode that allows only the UI to respond to user input. */
 2struct ENGINE_API FInputModeUIOnly : public FInputModeDataBase
 3{
 4    // ...
 5};
 6
 7/** Data structure used to setup an input mode that allows only the player input / player controller to respond to user input. */
 8struct ENGINE_API FInputModeGameOnly : public FInputModeDataBase
 9{
10    // ...
11};
12
13
14/** Data structure used to setup an input mode that allows the UI to respond to user input, and if the UI doesn't handle it player input / player controller gets a chance. */
15struct ENGINE_API FInputModeGameAndUI : public FInputModeDataBase
16{
17    // ...
18};

GameModeBase


暂停游戏

-
PC 给出暂停行为的主导者, 用于权限检查
CanUnpauseDelegate 委托, 用于检查是否可以暂停

会暂停所有Actor的Tick

1/**
2 * Adds the delegate to the list if the player Controller has the right to pause
3 * the game. The delegate is called to see if it is ok to unpause the game, e.g.
4 * the reason the game was paused has been cleared.
5 * @param PC the player Controller to check for admin privs
6 * @param CanUnpauseDelegate the delegate to query when checking for unpause
7 */
8virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause());

清除暂停

使所有Actor的Tick运行起来

1/**
2 * Checks the list of delegates to determine if the pausing can be cleared. If
3 * the delegate says it's ok to unpause, that delegate is removed from the list
4 * and the rest are checked. The game is considered unpaused when the list is
5 * empty.
6 */
7virtual bool ClearPause();

Button

类似的委托还有OnPressed, OnReleased, OnHovered等等

1DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnButtonClickedEvent);
2
3/** Called when the button is clicked */
4UPROPERTY(BlueprintAssignable, Category="Button|Event")
5FOnButtonClickedEvent OnClicked;

在STUGameHUD中管理窗口部件


添加属性: 保存暂停窗口部件类型

protected

ShootThemUp: UI/STUGameHUD.h

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

添加属性: 游戏状态-窗口部件对象键值对

使用UPROPERTY宏托管指针

private

ShootThemUp: UI/STUGameHUD.h

1UPROPERTY()
2TMap<ESTUMatchState, UUserWidget *> GameWidgets;

添加美化接口: 创建窗口部件并添加到视口, 初始化键值对, 并设置窗口部件对象均不可见

private

ShootThemUp: UI/STUGameHUD.h

1void InitGameWidgets();
  1. 在BeginPlay中屏蔽PlayerHUDWidget初始化

    ShootThemUp: UI/STUGameHUD.cpp
    1/*
    2auto PlayerHUDWidget = CreateWidget<UUserWidget>(GetWorld(), PlayerHUDWidgetClass);
    3if (PlayerHUDWidget)
    4{
    5    PlayerHUDWidget->AddToViewport();
    6}
    7*/
  2. 在BeginPlay中调用

    ShootThemUp: UI/STUGameHUD.cpp
  3. 实现

    ShootThemUp: UI/STUGameHUD.cpp
     1void ASTUGameHUD::InitGameWidgets()
     2{
     3    GameWidgets.Add(ESTUMatchState::InProgress, CreateWidget<UUserWidget>(GetWorld(), PlayerHUDWidgetClass));
     4    GameWidgets.Add(ESTUMatchState::Pause, CreateWidget<UUserWidget>(GetWorld(), PauseWidgetClass));
     5
     6    for (auto GameWidgetPair : GameWidgets)
     7    {
     8        const auto GameWidget = GameWidgetPair.Value;
     9        if (!GameWidget) continue;
    10
    11        GameWidget->AddToViewport();
    12        GameWidget->SetVisibility(ESlateVisibility::Hidden);
    13    }
    14}

添加属性: 指向当前可见窗口部件

  1. 初始指向空
  2. 当GameMode调用StartPlay时, 第一次进行设置
  3. 使用UPROPERTY宏托管指针

private

ShootThemUp: UI/STUGameHUD.h

1UPROPERTY()
2UUserWidget *CurrentWidget = nullptr;

游戏状态发生改变时, 修改窗口部件可见性

ShootThemUp: UI/STUGameHUD.cpp

 1// OnMatchStateChanged
 2
 3if (CurrentWidget)
 4{
 5    CurrentWidget->SetVisibility(ESlateVisibility::Hidden);
 6}
 7
 8if (GameWidgets.Contains(NewState))
 9{
10    CurrentWidget = GameWidgets[NewState];
11}
12
13if (CurrentWidget)
14{
15    CurrentWidget->SetVisibility(ESlateVisibility::Visible);
16}

设计暂停窗口部件


创建C++类

-
基类 UUserWidget
路径 UI
名称 STUPauseWidget
属性 Public

创建蓝图窗口部件

去到 Content/UI , 创建蓝图窗口部件, 基类STUPauseWidget, 命名为WBP_PauseWidget


设置WBP_PauseWidget

  1. 添加 Canvas Panel

  2. 添加 Background Blur

    模糊背景, 后期处理特效

    -
    Anchors 平铺
    Offset 均为0
    BlurStrength 模糊强度: 4



  3. 添加垂直对齐盒

    -
    Anchors 居中
    Position X 0
    Position Y 0
    Alignment X = Y = 0.5
    Size To Content 勾选



  4. 添加文本

    -
    Text GAME PAUSE
    Font > Size 100


  5. 添加分隔符

    -
    Size > Y 纵向间距: 40


  6. 添加按钮

    默认为变量, 重命名为 ClearPauseButton


    -
    Horizontal Alignment 居中
    Vertical Alignment 居中


  7. 为按钮添加上级: 大小盒


    -
    Width 300
    Height 100


  8. 设置ClearPauseButton

    - Hex Linear
    Normal FF0010FF 常规
    Hover 000000FF 鼠标悬浮
    Pressed FF0010FF 点击时


  9. 添加文本



添加键位绑定

Edit > Project Settings.. > Engine > Input

-
键位 P
绑定类型 动作映射 Action Mapping
键位描述 PauseGame



STUGameModeBase实现设置/取消暂停功能

  • 在基类函数基础上, 更新游戏状态
  • 注意到, 返回类型为布尔, 即存在设置不成功的情况

public

ShootThemUp: STUGameModeBase.h

1virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause()) override;
2virtual bool ClearPause() override;

ShootThemUp: STUGameModeBase.cpp

 1bool ASTUGameModeBase::SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate)
 2{
 3    const auto PauseSet = Super::SetPause(PC, CanUnpauseDelegate);
 4
 5    if (PauseSet)
 6    {
 7        SetMatchState(ESTUMatchState::Pause);
 8    }
 9
10    return PauseSet;
11}
12
13bool ASTUGameModeBase::ClearPause()
14{
15    const auto PauseCleared = Super::ClearPause();
16
17    if (PauseCleared)
18    {
19        SetMatchState(ESTUMatchState::InProgress);
20    }
21
22    return PauseCleared;
23}

绑定键位描述

考虑到游戏角色会死亡, 而复活冷却也可以使用暂停功能: 为PlayerController添加键位绑定

  1. 添加回调函数

    private

    ShootThemUp: Player/STUPlayerController.h
    1void OnPauseGame();
  2. 覆写SetupInputComponent: 绑定键位

    protected

    ShootThemUp: Player/STUPlayerController.h
    1virtual void SetupInputComponent() override;
    ShootThemUp: Player/STUPlayerController.cpp
    1void ASTUPlayerController::SetupInputComponent()
    2{
    3    Super::SetupInputComponent();
    4    if (!InputComponent) return;
    5    InputComponent->BindAction("PauseGame", IE_Pressed, this, &ASTUPlayerController::OnPauseGame);
    6}
  3. 实现回调函数

    ShootThemUp: Player/STUPlayerController.cpp
    1#include "GameFrameWork/GameModeBase.h"
    2#include "Engine/World.h"
    3
    4void ASTUPlayerController::OnPauseGame()
    5{
    6    if (!GetWorld() || !GetWorld()->GetAuthGameMode()) return;
    7
    8    GetWorld()->GetAuthGameMode()->SetPause(this);
    9}

实现STUPauseWidget


获取按钮

和蓝图窗口部件中按钮的变量名一致

protected

ShootThemUp: UI/STUPauseWidget.h

1class UButton;
2
3UPROPERTY(meta = (BindWidget))
4UButton *ClearPauseButton;

添加点击按钮的回调函数

private

ShootThemUp: UI/STUPauseWidget.h

1UFUNCTION()
2void OnClearPause();

ShootThemUp: UI/STUPauseWidget.cpp

1#include "GameFramework/GameModeBase.h"
2
3void USTUPauseWidget::OnClearPause()
4{
5    if (!GetWorld() || !GetWorld()->GetAuthGameMode()) return;
6
7    GetWorld()->GetAuthGameMode()->ClearPause();
8}

为按钮点击事件绑定回调函数

覆写Initialize

public

ShootThemUp: UI/STUPauseWidget.h

1virtual bool Initialize() override;

注意: 未调用基类Initialize, ClearPauseButton为空

ShootThemUp: UI/STUPauseWidget.cpp

 1#include "Components/Button.h"
 2
 3bool USTUPauseWidget::Initialize()
 4{
 5    bool InitStatus = Super::Initialize();
 6
 7    if (ClearPauseButton)
 8    {
 9        ClearPauseButton->OnClicked.AddDynamic(this, &USTUPauseWidget::OnClearPause);
10    }
11
12    return InitStatus;
13}

查看

  1. 设置 BP_STUGameHUD

    -
    Pause Widget Class WBP_PauseWidget


  2. 设置 BP_STUGameModeBase

    -
    Round Time 30
  3. 鼠标不在按钮上


  4. 鼠标在 Continue


当前

  • 运行游戏后, 需要鼠标点击一下才能进入游戏
  • 按下 P 后, 需要按下 Shift-F1 使鼠标脱离控制
  • 点击 Continue 后, 还需鼠标点击一下

STUPlayerController设置鼠标受控

private

ShootThemUp: Player/STUPlayerController.h

1#include "STUCoreTypes.h"
2
3void OnMatchStateChanged(ESTUMatchState NewState);

ShootThemUp: UI/STUPauseWidget.cpp

 1void ASTUPlayerController::OnMatchStateChanged(ESTUMatchState NewState)
 2{
 3    if (NewState == ESTUMatchState::InProgress)
 4    {
 5        bShowMouseCursor = false;
 6        SetInputMode(FInputModeGameOnly());
 7    }
 8    else
 9    {
10        bShowMouseCursor = true;
11        SetInputMode(FInputModeUIOnly());
12    }
13}

添加BeginPlay函数, 在其中注册游戏状态改变服务

protected

ShootThemUp: Player/STUPlayerController.h

1virtual void BeginPlay() override;

ShootThemUp: Player/STUPlayerController.cpp

 1// #include "GameFrameWork/GameModeBase.h"
 2#include "Engine/World.h"
 3#include "STUGameModeBase.h"
 4
 5void ASTUPlayerController::BeginPlay()
 6{
 7    Super::BeginPlay();
 8
 9    if (GetWorld())
10    {
11        const auto GameMode = Cast<ASTUGameModeBase>(GetWorld()->GetAuthGameMode());
12        if (GameMode)
13        {
14            GameMode->OnMatchStateChanged.AddUObject(this, &ASTUPlayerController::OnMatchStateChanged);
15        }
16    }
17}

说明

如果只设置bShowMouseCursor

  • 游戏开始时, 仍需鼠标点击一下
  • 按下 P 之后, 鼠标箭头出现, 但活动区域仅限视口, 且鼠标悬浮在按钮之上时, 按钮未变成黑色

    Selected Viewport
  • 鼠标尝试点击按钮, 这才和之前 Shift-F1 效果一样, 鼠标脱离控制

修改

之前误把Initialize声明在 private 区域, 移动到 public

ShootThemUp: UI/STUPlayerHUDWidget.h


暂停窗口


Game Pause


说明

根据上节游戏状态, 会有3个窗口部件

游戏状态 窗口部件
InProgress WBP_PlayerHUDWidget
Pause WBP_PauseHUDWidget 暂停, 可选择继续 - 本节内容
GameOver 游戏结束, 显示统计数据 - 下节内容

本节实现暂停窗口: 游戏中按下 P 显示暂停窗口, 可于暂停窗口选择回到游戏


概览

  • 在STUGameHUD创建三种窗口部件
  • 依据游戏状态, 设置窗口部件可见性
  • 实现暂停窗口部件
  • 实现键位绑定

API导航


TMap

关联容器

-
Add 添加元素
[] 键作为下标, 获取值
Contains 查询是否存在给定键

TPair

键值对

-
::Value 获得键值对的值

UserWidget


可见性

  • UUserWidget::SetVisibility

    设置窗口组件可见性

    1/** Sets the visibility of the widget. */
    2virtual void SetVisibility(ESlateVisibility InVisibility) override;
  • ESlateVisibility

    可见选项

    -
    Visible 可见
    Hidden 隐藏
     1/** Is an entity visible? */
     2UENUM(BlueprintType)
     3enum class ESlateVisibility : uint8
     4{
     5    /** Visible and hit-testable (can interact with cursor). Default value. */
     6    Visible,
     7    /** Not visible and takes up no space in the layout (obviously not hit-testable). */
     8    Collapsed,
     9    /** Not visible but occupies layout space (obviously not hit-testable). */
    10    Hidden,
    11    /** Visible but not hit-testable (cannot interact with cursor) and children in the hierarchy (if any) are also not hit-testable. */
    12    HitTestInvisible UMETA(DisplayName = "Not Hit-Testable (Self & All Children)"),
    13    /** Visible but not hit-testable (cannot interact with cursor) and doesn't affect hit-testing on children (if any). */
    14    SelfHitTestInvisible UMETA(DisplayName = "Not Hit-Testable (Self Only)")
    15};

初始化

1virtual bool Initialize();

PlayerController


键位绑定所在

1/** Allows the PlayerController to set up custom input bindings. */
2virtual void SetupInputComponent();

成员InputComponent没在头文件中找到定义


鼠标受控

bShowMouseCursor
true 显示鼠标箭头
false 不显示鼠标箭头
1/** Whether the mouse cursor should be displayed. */
2UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=MouseInterface)
3uint32 bShowMouseCursor:1;

设置

1/** Setup an input mode. */
2virtual void SetInputMode(const FInputModeDataBase& InData);
FInputModeDataBase派生类
FInputModeUIOnly 只有UI可以响应用户输入
FInputModeGameOnly 只有玩家输入和PlayerController可以响应用户输入
FInputModeGameAndUI UI优先响应用户输入, 如果UI未作出处理, 玩家输入和PlayerController可以响应用户输入
 1/** Data structure used to setup an input mode that allows only the UI to respond to user input. */
 2struct ENGINE_API FInputModeUIOnly : public FInputModeDataBase
 3{
 4    // ...
 5};
 6
 7/** Data structure used to setup an input mode that allows only the player input / player controller to respond to user input. */
 8struct ENGINE_API FInputModeGameOnly : public FInputModeDataBase
 9{
10    // ...
11};
12
13
14/** Data structure used to setup an input mode that allows the UI to respond to user input, and if the UI doesn't handle it player input / player controller gets a chance. */
15struct ENGINE_API FInputModeGameAndUI : public FInputModeDataBase
16{
17    // ...
18};

GameModeBase


暂停游戏

-
PC 给出暂停行为的主导者, 用于权限检查
CanUnpauseDelegate 委托, 用于检查是否可以暂停

会暂停所有Actor的Tick

1/**
2 * Adds the delegate to the list if the player Controller has the right to pause
3 * the game. The delegate is called to see if it is ok to unpause the game, e.g.
4 * the reason the game was paused has been cleared.
5 * @param PC the player Controller to check for admin privs
6 * @param CanUnpauseDelegate the delegate to query when checking for unpause
7 */
8virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause());

清除暂停

使所有Actor的Tick运行起来

1/**
2 * Checks the list of delegates to determine if the pausing can be cleared. If
3 * the delegate says it's ok to unpause, that delegate is removed from the list
4 * and the rest are checked. The game is considered unpaused when the list is
5 * empty.
6 */
7virtual bool ClearPause();

Button

类似的委托还有OnPressed, OnReleased, OnHovered等等

1DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnButtonClickedEvent);
2
3/** Called when the button is clicked */
4UPROPERTY(BlueprintAssignable, Category="Button|Event")
5FOnButtonClickedEvent OnClicked;

在STUGameHUD中管理窗口部件


添加属性: 保存暂停窗口部件类型

protected

ShootThemUp: UI/STUGameHUD.h

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

添加属性: 游戏状态-窗口部件对象键值对

使用UPROPERTY宏托管指针

private

ShootThemUp: UI/STUGameHUD.h

1UPROPERTY()
2TMap<ESTUMatchState, UUserWidget *> GameWidgets;

添加美化接口: 创建窗口部件并添加到视口, 初始化键值对, 并设置窗口部件对象均不可见

private

ShootThemUp: UI/STUGameHUD.h

1void InitGameWidgets();
  1. 在BeginPlay中屏蔽PlayerHUDWidget初始化

    ShootThemUp: UI/STUGameHUD.cpp
    1/*
    2auto PlayerHUDWidget = CreateWidget<UUserWidget>(GetWorld(), PlayerHUDWidgetClass);
    3if (PlayerHUDWidget)
    4{
    5    PlayerHUDWidget->AddToViewport();
    6}
    7*/
  2. 在BeginPlay中调用

    ShootThemUp: UI/STUGameHUD.cpp
  3. 实现

    ShootThemUp: UI/STUGameHUD.cpp
     1void ASTUGameHUD::InitGameWidgets()
     2{
     3    GameWidgets.Add(ESTUMatchState::InProgress, CreateWidget<UUserWidget>(GetWorld(), PlayerHUDWidgetClass));
     4    GameWidgets.Add(ESTUMatchState::Pause, CreateWidget<UUserWidget>(GetWorld(), PauseWidgetClass));
     5
     6    for (auto GameWidgetPair : GameWidgets)
     7    {
     8        const auto GameWidget = GameWidgetPair.Value;
     9        if (!GameWidget) continue;
    10
    11        GameWidget->AddToViewport();
    12        GameWidget->SetVisibility(ESlateVisibility::Hidden);
    13    }
    14}

添加属性: 指向当前可见窗口部件

  1. 初始指向空
  2. 当GameMode调用StartPlay时, 第一次进行设置
  3. 使用UPROPERTY宏托管指针

private

ShootThemUp: UI/STUGameHUD.h

1UPROPERTY()
2UUserWidget *CurrentWidget = nullptr;

游戏状态发生改变时, 修改窗口部件可见性

ShootThemUp: UI/STUGameHUD.cpp

 1// OnMatchStateChanged
 2
 3if (CurrentWidget)
 4{
 5    CurrentWidget->SetVisibility(ESlateVisibility::Hidden);
 6}
 7
 8if (GameWidgets.Contains(NewState))
 9{
10    CurrentWidget = GameWidgets[NewState];
11}
12
13if (CurrentWidget)
14{
15    CurrentWidget->SetVisibility(ESlateVisibility::Visible);
16}

设计暂停窗口部件


创建C++类

-
基类 UUserWidget
路径 UI
名称 STUPauseWidget
属性 Public

创建蓝图窗口部件

去到 Content/UI , 创建蓝图窗口部件, 基类STUPauseWidget, 命名为WBP_PauseWidget


设置WBP_PauseWidget

  1. 添加 Canvas Panel

  2. 添加 Background Blur

    模糊背景, 后期处理特效

    -
    Anchors 平铺
    Offset 均为0
    BlurStrength 模糊强度: 4



  3. 添加垂直对齐盒

    -
    Anchors 居中
    Position X 0
    Position Y 0
    Alignment X = Y = 0.5
    Size To Content 勾选



  4. 添加文本

    -
    Text GAME PAUSE
    Font > Size 100


  5. 添加分隔符

    -
    Size > Y 纵向间距: 40


  6. 添加按钮

    默认为变量, 重命名为 ClearPauseButton


    -
    Horizontal Alignment 居中
    Vertical Alignment 居中


  7. 为按钮添加上级: 大小盒


    -
    Width 300
    Height 100


  8. 设置ClearPauseButton

    - Hex Linear
    Normal FF0010FF 常规
    Hover 000000FF 鼠标悬浮
    Pressed FF0010FF 点击时


  9. 添加文本



添加键位绑定

Edit > Project Settings.. > Engine > Input

-
键位 P
绑定类型 动作映射 Action Mapping
键位描述 PauseGame



STUGameModeBase实现设置/取消暂停功能

  • 在基类函数基础上, 更新游戏状态
  • 注意到, 返回类型为布尔, 即存在设置不成功的情况

public

ShootThemUp: STUGameModeBase.h

1virtual bool SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate = FCanUnpause()) override;
2virtual bool ClearPause() override;

ShootThemUp: STUGameModeBase.cpp

 1bool ASTUGameModeBase::SetPause(APlayerController* PC, FCanUnpause CanUnpauseDelegate)
 2{
 3    const auto PauseSet = Super::SetPause(PC, CanUnpauseDelegate);
 4
 5    if (PauseSet)
 6    {
 7        SetMatchState(ESTUMatchState::Pause);
 8    }
 9
10    return PauseSet;
11}
12
13bool ASTUGameModeBase::ClearPause()
14{
15    const auto PauseCleared = Super::ClearPause();
16
17    if (PauseCleared)
18    {
19        SetMatchState(ESTUMatchState::InProgress);
20    }
21
22    return PauseCleared;
23}

绑定键位描述

考虑到游戏角色会死亡, 而复活冷却也可以使用暂停功能: 为PlayerController添加键位绑定

  1. 添加回调函数

    private

    ShootThemUp: Player/STUPlayerController.h
    1void OnPauseGame();
  2. 覆写SetupInputComponent: 绑定键位

    protected

    ShootThemUp: Player/STUPlayerController.h
    1virtual void SetupInputComponent() override;
    ShootThemUp: Player/STUPlayerController.cpp
    1void ASTUPlayerController::SetupInputComponent()
    2{
    3    Super::SetupInputComponent();
    4    if (!InputComponent) return;
    5    InputComponent->BindAction("PauseGame", IE_Pressed, this, &ASTUPlayerController::OnPauseGame);
    6}
  3. 实现回调函数

    ShootThemUp: Player/STUPlayerController.cpp
    1#include "GameFrameWork/GameModeBase.h"
    2#include "Engine/World.h"
    3
    4void ASTUPlayerController::OnPauseGame()
    5{
    6    if (!GetWorld() || !GetWorld()->GetAuthGameMode()) return;
    7
    8    GetWorld()->GetAuthGameMode()->SetPause(this);
    9}

实现STUPauseWidget


获取按钮

和蓝图窗口部件中按钮的变量名一致

protected

ShootThemUp: UI/STUPauseWidget.h

1class UButton;
2
3UPROPERTY(meta = (BindWidget))
4UButton *ClearPauseButton;

添加点击按钮的回调函数

private

ShootThemUp: UI/STUPauseWidget.h

1UFUNCTION()
2void OnClearPause();

ShootThemUp: UI/STUPauseWidget.cpp

1#include "GameFramework/GameModeBase.h"
2
3void USTUPauseWidget::OnClearPause()
4{
5    if (!GetWorld() || !GetWorld()->GetAuthGameMode()) return;
6
7    GetWorld()->GetAuthGameMode()->ClearPause();
8}

为按钮点击事件绑定回调函数

覆写Initialize

public

ShootThemUp: UI/STUPauseWidget.h

1virtual bool Initialize() override;

注意: 未调用基类Initialize, ClearPauseButton为空

ShootThemUp: UI/STUPauseWidget.cpp

 1#include "Components/Button.h"
 2
 3bool USTUPauseWidget::Initialize()
 4{
 5    bool InitStatus = Super::Initialize();
 6
 7    if (ClearPauseButton)
 8    {
 9        ClearPauseButton->OnClicked.AddDynamic(this, &USTUPauseWidget::OnClearPause);
10    }
11
12    return InitStatus;
13}

查看

  1. 设置 BP_STUGameHUD

    -
    Pause Widget Class WBP_PauseWidget


  2. 设置 BP_STUGameModeBase

    -
    Round Time 30
  3. 鼠标不在按钮上


  4. 鼠标在 Continue


当前

  • 运行游戏后, 需要鼠标点击一下才能进入游戏
  • 按下 P 后, 需要按下 Shift-F1 使鼠标脱离控制
  • 点击 Continue 后, 还需鼠标点击一下

STUPlayerController设置鼠标受控

private

ShootThemUp: Player/STUPlayerController.h

1#include "STUCoreTypes.h"
2
3void OnMatchStateChanged(ESTUMatchState NewState);

ShootThemUp: UI/STUPauseWidget.cpp

 1void ASTUPlayerController::OnMatchStateChanged(ESTUMatchState NewState)
 2{
 3    if (NewState == ESTUMatchState::InProgress)
 4    {
 5        bShowMouseCursor = false;
 6        SetInputMode(FInputModeGameOnly());
 7    }
 8    else
 9    {
10        bShowMouseCursor = true;
11        SetInputMode(FInputModeUIOnly());
12    }
13}

添加BeginPlay函数, 在其中注册游戏状态改变服务

protected

ShootThemUp: Player/STUPlayerController.h

1virtual void BeginPlay() override;

ShootThemUp: Player/STUPlayerController.cpp

 1// #include "GameFrameWork/GameModeBase.h"
 2#include "Engine/World.h"
 3#include "STUGameModeBase.h"
 4
 5void ASTUPlayerController::BeginPlay()
 6{
 7    Super::BeginPlay();
 8
 9    if (GetWorld())
10    {
11        const auto GameMode = Cast<ASTUGameModeBase>(GetWorld()->GetAuthGameMode());
12        if (GameMode)
13        {
14            GameMode->OnMatchStateChanged.AddUObject(this, &ASTUPlayerController::OnMatchStateChanged);
15        }
16    }
17}

说明

如果只设置bShowMouseCursor

  • 游戏开始时, 仍需鼠标点击一下
  • 按下 P 之后, 鼠标箭头出现, 但活动区域仅限视口, 且鼠标悬浮在按钮之上时, 按钮未变成黑色

    Selected Viewport
  • 鼠标尝试点击按钮, 这才和之前 Shift-F1 效果一样, 鼠标脱离控制

修改

之前误把Initialize声明在 private 区域, 移动到 public

ShootThemUp: UI/STUPlayerHUDWidget.h