六一的部落格


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



Respawn Component


说明

  1. 之前都是通过控制器复活游戏角色, 而控制器类型并不统一, 有PlayerController和AIController. 考虑到复用, 将回合中复活逻辑存放在组件
  2. 游戏角色死亡, 经过指定时间后, 允许复活. 但指定时间必须不大于游戏角色死亡时回合剩余时间; 游戏角色复活后, 拥有一定的时间行动
    -
    RespawnTime 冷却时间
    MinRoundActivityTime 回合中最小行动时间
  3. 之前文章结构尝试过从枝末攀附到衔接处, 或从框架延伸到枝叶. 本节先从RespawnComponent入手, 之后和GameModeBase的重建游戏角色逻辑搭上线, 最后再添加为PlayerController和AIController的组件
  4. 将RespawnComponent命名为RespawnColdComponent更合理一些

创建RespawnComponent

-
基类 ActorComponent
路径 Components
名称 STURespawnComponent
属性 Public

整理RespawnComponent框架

  1. 构造函数中取消每秒更新

    ShootThemUp: Components/STURespawnComponent.cpp
    1PrimaryComponentTick.bCanEverTick = false;
  2. 屏蔽TickComponent的声明和定义
  3. 屏蔽BeginPlay的声明和定义

修改游戏规则

添加属性: 复活冷却时间

ShootThemUp: STUCoreTypes.h

1UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (ClampMin = "3", ClampMax = "20"))
2int32 RespawnTime = 5; // in seconds

实现RespawnComponent


添加属性: 定时器描述符 + 冷却计数

private

ShootThemUp: Components/STURespawnComponent.h

1// private
2int32 RespawnCountDown = 0;        
3FTimerHandle RespawnTimer;

添加接口: 定时器回调函数

private

ShootThemUp: Components/STURespawnComponent.h

1void OnRespawnCountDown();

ShootThemUp: Components/STURespawnComponent.cpp

 1#include "Engine/World.h"
 2
 3void USTURespawnComponent::OnRespawnCountDown()
 4{
 5    if (!GetWorld()) return;
 6
 7    --RespawnCountDown;
 8
 9    if (!RespawnCountDown)
10    {
11        GetWorld()->GetTimerManager().ClearTimer(RespawnTimer);
12        SendRespawnRequest();
13    }
14}

添加辅助接口: 调用GameMode复活接口

private

ShootThemUp: Components/STURespawnComponent.h

1void SendRespawnRequest();

ShootThemUp: Components/STURespawnComponent.cpp

 1#include "STUGameModeBase.h"
 2
 3void USTURespawnComponent::SendRespawnRequest()
 4{
 5    if (!GetWorld()) return;
 6
 7    const auto GameMode = Cast<ASTUGameModeBase>(GetWorld()->GetAuthGameMode());
 8    if (!GameMode) return;
 9
10    GameMode->RespawnRequest(Cast<AController>(GetOwner()));
11}

添加接口: 开启定时器

public

ShootThemUp: Components/STURespawnComponent.h

1void RespawnCold(int32 RespawnTime);

和关卡中的计时器逻辑类似

ShootThemUp: Components/STURespawnComponent.cpp

1void USTURespawnComponent::RespawnCold(int32 RespawnTime)
2{
3    if (!GetWorld()) return;
4
5    RespawnCountDown = RespawnTime;
6    GetWorld()->GetTimerManager().SetTimer(RespawnTimer, this, &USTURespawnComponent::OnRespawnCountDown, 1.0f, true);
7}

修改关卡逻辑


添加接口: 通过控制器复活游戏角色

public

ShootThemUp: STUGameModeBase.h

1void RespawnRequest(AController *Controller);

ShootThemUp: STUGameModeBase.cpp

1void ASTUGameModeBase::RespawnRequest(AController *Controller)
2{
3    ResetOnePlayer(Controller);
4}

游戏角色死亡后进入复活冷却

private

ShootThemUp: STUGameModeBase.h

1void RespawnCold(AController *Controller);

ShootThemUp: STUGameModeBase.cpp

 1#include "STUUtils.h"
 2#include "Components/STURespawnComponent.h"
 3
 4void ASTUGameModeBase::RespawnCold(AController *Controller)
 5{
 6    const auto RespawnAvailable = RoundCountDown > GameData.RespawnTime + MinRoundActivityTime;
 7    if (!RespawnAvailable) return;
 8
 9    auto RespawnComponent = STUUtils::GetSTUPlayerComponent<USTURespawnComponent>(Controller);
10    if (!RespawnComponent) return;
11
12    RespawnComponent->RespawnCold(GameData.RespawnTime);
13}

死亡事件发生时调用

1// Killed
2RespawnCold(VictimController);

游戏角色复活后最小活动时间

  • 可以存放在GameData中, 也可以存放在GameModeBase
  • 没什么配置的必要

ShootThemUp: STUGameModeBase.h

1constexpr static int32 MinRoundActivityTime = 10;

当前流程梳理

  1. 游戏角色死亡后, ASTUGameModeBase::Killed被调用, 通过ASTUGameModeBase::RespawnCold进行冷却计时
  2. ASTUGameModeBase::RespawnCold调用控制器RespawnComponent的USTURespawnComponent::RespawnCold, 开启定时器
  3. 定时器每秒触发, 当计数器为0时, 调用ASTUGameModeBase::RespawnRequest尝试复活游戏角色

为AIController添加RespawnComponent

protected

ShootThemUp: AI/STUAIController.h

1class USTURespawnComponent;
2
3UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
4USTURespawnComponent *STURespawnComponent;

ShootThemUp: AI/STUAIController.cpp

1#include "Components/STURespawnComponent.h"
2
3// 构造函数
4STURespawnComponent = CreateDefaultSubobject<USTURespawnComponent>("STURespawnComponent");

为PlayerController添加RespawnComponent


添加组件

protected

ShootThemUp: Player/STUPlayerController.h

1class USTURespawnComponent;
2
3UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
4USTURespawnComponent *STURespawnComponent;

添加构造函数

public

ShootThemUp: Player/STUPlayerController.h

1ASTUPlayerController();

初始化组件

ShootThemUp: Player/STUPlayerController.cpp

1#include "Components/STURespawnComponent.h"
2
3ASTUPlayerController::ASTUPlayerController()
4{
5    STURespawnComponent = CreateDefaultSubobject<USTURespawnComponent>("STURespawnComponent");
6}    

查看

- 单位(s)
当前回合时长 30
回合最小活动时间 10
复活冷却 5
  • NPC死亡后可以复活
  • 死亡时, 回合剩余时间大于15s时, 可以复活
  • 死亡时, 回合剩余时间小于15s时, 在下一回合复活

允许游戏角色回合中复活


Respawn Component


说明

  1. 之前都是通过控制器复活游戏角色, 而控制器类型并不统一, 有PlayerController和AIController. 考虑到复用, 将回合中复活逻辑存放在组件
  2. 游戏角色死亡, 经过指定时间后, 允许复活. 但指定时间必须不大于游戏角色死亡时回合剩余时间; 游戏角色复活后, 拥有一定的时间行动
    -
    RespawnTime 冷却时间
    MinRoundActivityTime 回合中最小行动时间
  3. 之前文章结构尝试过从枝末攀附到衔接处, 或从框架延伸到枝叶. 本节先从RespawnComponent入手, 之后和GameModeBase的重建游戏角色逻辑搭上线, 最后再添加为PlayerController和AIController的组件
  4. 将RespawnComponent命名为RespawnColdComponent更合理一些

创建RespawnComponent

-
基类 ActorComponent
路径 Components
名称 STURespawnComponent
属性 Public

整理RespawnComponent框架

  1. 构造函数中取消每秒更新

    ShootThemUp: Components/STURespawnComponent.cpp
    1PrimaryComponentTick.bCanEverTick = false;
  2. 屏蔽TickComponent的声明和定义
  3. 屏蔽BeginPlay的声明和定义

修改游戏规则

添加属性: 复活冷却时间

ShootThemUp: STUCoreTypes.h

1UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (ClampMin = "3", ClampMax = "20"))
2int32 RespawnTime = 5; // in seconds

实现RespawnComponent


添加属性: 定时器描述符 + 冷却计数

private

ShootThemUp: Components/STURespawnComponent.h

1// private
2int32 RespawnCountDown = 0;        
3FTimerHandle RespawnTimer;

添加接口: 定时器回调函数

private

ShootThemUp: Components/STURespawnComponent.h

1void OnRespawnCountDown();

ShootThemUp: Components/STURespawnComponent.cpp

 1#include "Engine/World.h"
 2
 3void USTURespawnComponent::OnRespawnCountDown()
 4{
 5    if (!GetWorld()) return;
 6
 7    --RespawnCountDown;
 8
 9    if (!RespawnCountDown)
10    {
11        GetWorld()->GetTimerManager().ClearTimer(RespawnTimer);
12        SendRespawnRequest();
13    }
14}

添加辅助接口: 调用GameMode复活接口

private

ShootThemUp: Components/STURespawnComponent.h

1void SendRespawnRequest();

ShootThemUp: Components/STURespawnComponent.cpp

 1#include "STUGameModeBase.h"
 2
 3void USTURespawnComponent::SendRespawnRequest()
 4{
 5    if (!GetWorld()) return;
 6
 7    const auto GameMode = Cast<ASTUGameModeBase>(GetWorld()->GetAuthGameMode());
 8    if (!GameMode) return;
 9
10    GameMode->RespawnRequest(Cast<AController>(GetOwner()));
11}

添加接口: 开启定时器

public

ShootThemUp: Components/STURespawnComponent.h

1void RespawnCold(int32 RespawnTime);

和关卡中的计时器逻辑类似

ShootThemUp: Components/STURespawnComponent.cpp

1void USTURespawnComponent::RespawnCold(int32 RespawnTime)
2{
3    if (!GetWorld()) return;
4
5    RespawnCountDown = RespawnTime;
6    GetWorld()->GetTimerManager().SetTimer(RespawnTimer, this, &USTURespawnComponent::OnRespawnCountDown, 1.0f, true);
7}

修改关卡逻辑


添加接口: 通过控制器复活游戏角色

public

ShootThemUp: STUGameModeBase.h

1void RespawnRequest(AController *Controller);

ShootThemUp: STUGameModeBase.cpp

1void ASTUGameModeBase::RespawnRequest(AController *Controller)
2{
3    ResetOnePlayer(Controller);
4}

游戏角色死亡后进入复活冷却

private

ShootThemUp: STUGameModeBase.h

1void RespawnCold(AController *Controller);

ShootThemUp: STUGameModeBase.cpp

 1#include "STUUtils.h"
 2#include "Components/STURespawnComponent.h"
 3
 4void ASTUGameModeBase::RespawnCold(AController *Controller)
 5{
 6    const auto RespawnAvailable = RoundCountDown > GameData.RespawnTime + MinRoundActivityTime;
 7    if (!RespawnAvailable) return;
 8
 9    auto RespawnComponent = STUUtils::GetSTUPlayerComponent<USTURespawnComponent>(Controller);
10    if (!RespawnComponent) return;
11
12    RespawnComponent->RespawnCold(GameData.RespawnTime);
13}

死亡事件发生时调用

1// Killed
2RespawnCold(VictimController);

游戏角色复活后最小活动时间

  • 可以存放在GameData中, 也可以存放在GameModeBase
  • 没什么配置的必要

ShootThemUp: STUGameModeBase.h

1constexpr static int32 MinRoundActivityTime = 10;

当前流程梳理

  1. 游戏角色死亡后, ASTUGameModeBase::Killed被调用, 通过ASTUGameModeBase::RespawnCold进行冷却计时
  2. ASTUGameModeBase::RespawnCold调用控制器RespawnComponent的USTURespawnComponent::RespawnCold, 开启定时器
  3. 定时器每秒触发, 当计数器为0时, 调用ASTUGameModeBase::RespawnRequest尝试复活游戏角色

为AIController添加RespawnComponent

protected

ShootThemUp: AI/STUAIController.h

1class USTURespawnComponent;
2
3UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
4USTURespawnComponent *STURespawnComponent;

ShootThemUp: AI/STUAIController.cpp

1#include "Components/STURespawnComponent.h"
2
3// 构造函数
4STURespawnComponent = CreateDefaultSubobject<USTURespawnComponent>("STURespawnComponent");

为PlayerController添加RespawnComponent


添加组件

protected

ShootThemUp: Player/STUPlayerController.h

1class USTURespawnComponent;
2
3UPROPERTY(VisibleAnywhere, BlueprintReadWrite)
4USTURespawnComponent *STURespawnComponent;

添加构造函数

public

ShootThemUp: Player/STUPlayerController.h

1ASTUPlayerController();

初始化组件

ShootThemUp: Player/STUPlayerController.cpp

1#include "Components/STURespawnComponent.h"
2
3ASTUPlayerController::ASTUPlayerController()
4{
5    STURespawnComponent = CreateDefaultSubobject<USTURespawnComponent>("STURespawnComponent");
6}    

查看

- 单位(s)
当前回合时长 30
回合最小活动时间 10
复活冷却 5
  • NPC死亡后可以复活
  • 死亡时, 回合剩余时间大于15s时, 可以复活
  • 死亡时, 回合剩余时间小于15s时, 在下一回合复活