划分阵营
2023年11月19日 2024年1月11日
Player State
说明
本节会为游戏角色划分阵营, 通过游戏角色模型材质的颜色标记
关于文章结构:
- 之前都是由小及大, 即使课程里先给出框架, 也会从叶子的实现一点点与分支处接轨
这在讲解中是没有问题的, 但在实际开发中, 叶子实现完测试, 仍旧需要构建框架. 对细枝末节的把握, 也不会总是那么准确 - 本节会尝试从大的框架, 延伸到枝叶的实现
创建C++类: STUPlayerState
可以在 Common Classess
中找到
- | |
---|---|
基类 | PlayerState |
路径 | Player |
名称 | STUPlayerState |
属性 | Public |
每个游戏角色都拥有一个PlayerState, 其存在和Controller一样, 贯穿整个游戏
游戏角色死亡被销毁时, PlayerState依然存在. 因此, PlayerState是用来存储和游戏角色并非直接相关的各种数据的不二选择
通常是一些统计数据: 游戏角色死亡次数, 击杀敌人数目, 游戏角色名称, 阵营标识等
添加数据成员
- | |
---|---|
TeamID | 阵营标识 |
TeamColor | 阵营颜色 |
private
ShootThemUp: Player/STUPlayerState.h
1int32 TeamID; 2FLinearColor TeamColor;
添加接口
TeamID和TeamColor的Get和Set接口
public
ShootThemUp: Player/STUPlayerState.h
1void SetTeamID(int32 ID) { TeamID = ID; } 2void SetTeamColor(const FLinearColor &Color) { TeamColor = Color; } 3 4int32 GetTeamID() const { return TeamID; } 5FLinearColor GetTeamColor() const { return TeamColor; }
补充游戏规则
- | |
---|---|
TeamColors | 阵营颜色列表, 使用TeamID匹配 |
DefaultTeamColor | 阵营默认颜色. 未设置TeamColors时使用 |
ShootThemUp: STUCoreTypes.h
1// FGameData 2 3UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) 4FLinearColor DefaultTeamColor = FLinearColor::Red; 5 6UPROPERTY(EditDefaultsOnly, BlueprintReadWrite) 7TArray<FLinearColor> TeamColors;
关卡中搭建框架
STUGameModeBase
- | |
---|---|
CreateTeamsInfo | 游戏开始时调用, 为游戏角色分组 |
DetermineColorByTeamID | 通过TeamID查询颜色 |
SetPlayerColor | 通过Controller设置游戏角色阵营颜色 |
private
ShootThemUp: STUGameModeBase.h
1void CreateTeamsInfo(); 2FLinearColor DetermineColorByTeamID(int32 TeamID) const; 3void SetPlayerColor(AController *Controller);
设置PlayerState类型
ShootThemUp: STUGameModeBase.cpp
1#include "Player/STUPlayerState.h" 2 3// 构造函数 4PlayerStateClass = ASTUPlayerState::StaticClass();
在StartPlay中为游戏角色分组
ShootThemUp: STUGameModeBase.cpp
1// StartPlay 2 3SpawnBots(); 4CreateTeamsInfo();
实现分组逻辑
- 可以通过Controller获取PlayerState: 迭代Controller, 设置PlayerState
- 控制器个数对应游戏角色个数, 分组时, 轮流为每个组增加队员; 当前两个组, 所以会容易些
- 设置颜色后, 需要应用颜色: 调用SetPlayerColor
ShootThemUp: STUGameModeBase.cpp
1void ASTUGameModeBase::CreateTeamsInfo() 2{ 3 if (!GetWorld()) return; 4 int32 TeamID = 1; 5 for (auto It = GetWorld()->GetControllerIterator(); It; ++It) 6 { 7 const auto Controller = It->Get(); 8 if (!Controller) continue; 9 10 const auto PlayerState = Cast<ASTUPlayerState>(Controller->PlayerState); 11 if (!PlayerState) continue; 12 13 PlayerState->SetTeamID(TeamID); 14 PlayerState->SetTeamColor(DetermineColorByTeamID(TeamID)); 15 SetPlayerColor(Controller); 16 17 TeamID = TeamID == 1 ? 2 : 1; 18 } 19}
根据TeamID获取阵营颜色
阵营编号类型为 int32
, 当然存在为负数的情况. 至于要不要检测, 调用处TeamID是合法的, 没有别的情况暂不检查
ShootThemUp: STUGameModeBase.cpp
1FLinearColor ASTUGameModeBase::DetermineColorByTeamID(int32 TeamID) const 2{ 3 if (TeamID - 1 < GameData.TeamColors.Num()) 4 { 5 return GameData.TeamColors[TeamID - 1]; 6 } 7 UE_LOG(LogSTUGameModeBase, Warning, TEXT("No color for team id %i, set to default: %s"), TeamID, *GameData.DefaultTeamColor.ToString()); 8 9 return GameData.DefaultTeamColor; 10}
通过控制器修改游戏角色颜色
- 初始化时需要设置
- 重建游戏角色时, 需要再次设置
ShootThemUp: STUGameModeBase.cpp
1// ResetOnePlayer 2 3RestartPlayer(Controller); 4SetPlayerColor(Controller);
- CreateTeamsInfo中调用SetPlayerColor, 可以传入颜色; 而由ResetOnePlayer调用时, 无法传入颜色
当然, 我们可以在ResetOnePlayer获取PlayerState, 再传入颜色, 可这和代码可读性矛盾
因此, 我们选择在SetPlayerColor中获取PlayerState. 这其实不会影响性能, 因为CreateTeamsInfo只调用一次 - 之后再在STUBaseCharacter中实现SetPlayerColor逻辑
ShootThemUp: STUGameModeBase.cpp
1void ASTUGameModeBase::SetPlayerColor(AController *Controller) 2{ 3 if (!Controller) return; 4 5 const auto Character = Cast<ASTUBaseCharacter>(Controller->GetPawn()); 6 if (!Character) return; 7 8 const auto PlayerState = Cast<ASTUPlayerState>(Controller->PlayerState); 9 if (!PlayerState) return; 10 11 Character->SetPlayerColor(PlayerState->GetTeamColor()); 12}
查看游戏角色材质
HeroTPP
打开方式: 双击打开 BP_STUAICharacter
, 双击 Mesh > Materials > Element 0 > HeroTPP
左侧下方 Paint Color
属性, 对应材质上的橘色: 该颜色将与阵营相关联
实现修改游戏角色材质颜色逻辑
public
ShootThemUp: Player/STUBaseCharacter.h
1void SetPlayerColor(const FLinearColor &Color);
添加属性: 材质参数名称
protected
ShootThemUp: Player/STUBaseCharacter.h
1UPROPERTY(EditDefaultsOnly) 2FName MaterialColorName = "PaintColor";
实现
ShootThemUp: Player/STUBaseCharacter.cpp
1#include "Materials/MaterialInstanceDynamic.h" 2 3void ASTUBaseCharacter::SetPlayerColor(const FLinearColor &Color) 4{ 5 const auto MaterialInst = GetMesh()->CreateAndSetMaterialInstanceDynamic(0); 6 if (!MaterialInst) return; 7 8 MaterialInst->SetVectorParameterValue(MaterialColorName, Color); 9}
查看
-
使用阵营默认颜色, 有告警
-
设置阵营颜色数组和玩家总数4
-
两个元素: 绿色和蓝色
- Hex Linear 绿色 3AE90000 蓝色 001BD600 -
玩家总数
- Players Num 4
-