造成伤害时判断阵营
2023年11月20日 2024年1月11日
Are Enemies?
说明
- 判断阵营的方法
PlayerState中的TeamID - 行为树中, NPC锁定攻击对象时, 排除队友
- 判断阵营的位置
- 方案一: 造成伤害前进行判断; 造成伤害的所有情形都要考虑到, 全部都要添加阵营判断
- 方案二: 游戏角色受到伤害时, 判断伤害来源阵营
要求伤害来源信息正确
Controller信息设置敌方, Actor信息用来存放武器
- 方案一: 造成伤害前进行判断; 造成伤害的所有情形都要考虑到, 全部都要添加阵营判断
- 游戏角色造成伤害的情形
- 步枪击中游戏角色
- 游戏角色在榴弹爆炸范围内
- 步枪击中游戏角色
添加判断函数
- 静态成员函数
- 参数的设定, 考虑到调用处容易给出
- 当且仅当二者阵营不同时返回true, 其他无效情况均返回false
public
ShootThemUp: STUUtils.h
1#include "Player/STUPlayerState.h" 2#include "GameFramework/Controller.h" 3 4bool static AreEnemies(AController *Controller1, AController *Controller2) 5{ 6 if (!Controller1 || !Controller2 || Controller1 == Controller2) return false; 7 8 const auto PlayerState1 = Cast<ASTUPlayerState>(Controller1->PlayerState); 9 const auto PlayerState2 = Cast<ASTUPlayerState>(Controller2->PlayerState); 10 11 return PlayerState1 && PlayerState2 && PlayerState1->GetTeamID() != PlayerState2->GetTeamID(); 12}
在感知组件中排除同阵营游戏角色
获取感知Actor的控制器
1const auto PercievePawn = Cast<APawn>(PercieveActor); 2PercievePawn && PercievePawn->Controller;
完整实现
ShootThemUp: Components/STUAIPerceptionComponent.cpp
1// GetClosestEnemy 2 3for (const auto PercieveActor : PercieveActors) 4{ 5 // ... 6 7 const auto PercievePawn = Cast<APawn>(PercieveActor); 8 const auto AreEnemies = PercievePawn && STUUtils::AreEnemies(Controller, PercievePawn->Controller); 9 10 if (HealthComponent && !HealthComponent->IsDead() && AreEnemies) 11 { 12 // ... 13 } 14}
受到伤害处判断阵营
修改步枪造成伤害传入的伤害源信息
- NPC无PlayerController
- 伤害源本就为武器
ShootThemUp: Weapon/STURifleWeapon.cpp
1// DamagedActor->TakeDamage(DamageAmount, FDamageEvent(), GetPlayerController(), this); 2 3const auto Pawn = Cast<APawn>(GetOwner()); 4const auto Controller = Pawn->Controller; 5 6DamagedActor->TakeDamage(DamageAmount, FDamageEvent(), Controller, this);
修改榴弹造成伤害时传入的伤害源信息
- Controller正确
- 伤害源本就为武器, 无修改
ShootThemUp: Weapon/STUProjectile.cpp
1UGameplayStatics::ApplyRadialDamage(GetWorld(), DamageAmount, GetActorLocation(), DamageRadius, UDamageType::StaticClass(), 2 {GetOwner()}, this, GetController(), DoFullDamage);
受伤时判断阵营
ShootThemUp: Components/STUHealthComponent.cpp
1#include "STUUtils.h" 2 3// OnTakeAnyDamage 4 5const auto Pawn = Cast<APawn>(GetOwner()); 6if (!Pawn) return; 7 8const auto AreEnemies = STUUtils::AreEnemies(Pawn->Controller, InstigatedBy); 9if (!AreEnemies) return;
查看
- 回合时长设置为120s
- 玩家数设为3
队友捕捉到2个游戏角色, 但只攻击敌人
在造成伤害处判断阵营
不推荐这种方法
步枪造成伤害
ShootThemUp: Weapon/STURifleWeapon.cpp
1#include "STUUtils.h" 2 3void ASTURifleWeapon::MakeDamage(const FHitResult &HitResult) 4{ 5 const auto HitActor = HitResult.GetActor(); 6 if (!HitActor) return; 7 8 const auto OwnerPawn = Cast<APawn>(GetOwner()); 9 const auto HitPawn = Cast<APawn>(HitActor); 10 11 bool AreEnemies = OwnerPawn && HitPawn && STUUtils::AreEnemies(OwnerPawn->Controller, HitPawn->Controller); 12 if (AreEnemies) 13 { 14 UE_LOG(LogTemp, Warning, TEXT("Shooting enemy")); 15 HitActor->TakeDamage(DamageAmount, FDamageEvent(), OwnerPawn->Controller, this); 16 } 17 else 18 { 19 UE_LOG(LogTemp, Warning, TEXT("Shooting cancel")); 20 } 21}
榴弹造成伤害
仅供参考
GameModeBase存放阵营信息
private
ShootThemUp: STUGameModeBase.h
1TArray<TArray<AActor *>> TeamMemberList;
初始化阵营信息
ShootThemUp: STUGameModeBase.cpp
1// 构造函数 2TeamMemberList.SetNum(2); 3 4// CreateTeamsInfo 5 6for (auto It = GetWorld()->GetControllerIterator(); It; ++It) 7{ 8 // ... 9 10 const auto Actor = Cast<AActor>(Controller->GetPawn()); 11 if (!Actor) continue; 12 13 // ... 14 15 SetPlayerColor(Controller); 16 TeamMemberList[TeamID - 1].Push(Actor); 17 18 // ... 19}
队友信息没放在PlayerState中有两个原因:
- 同阵营游戏角色保存的是相同信息, 可以使用TeamID分组; 这种拷贝比较浪费
- 当前复用控制器遍历整理阵营成员信息. 如果要存放在PlayerState中, 需要再遍历一次控制器, 拷贝队友信息
造成半径伤害时忽略队友
如果之前为STUGameModeBase类设置Public属性, 此处包含头文件路径时不用去到上级目录
ShootThemUp: Weapon/STUProjectile.cpp
1#include "../STUGameModeBase.h" 2 3// OnProjectileHit 4 5TArray<AActor *> IgnoreActors; 6const auto GameModeBase = Cast<ASTUGameModeBase>(UGameplayStatics::GetGameMode(this)); 7if (GameModeBase && GameModeBase->GetTeamMemberByActor(GetOwner(), IgnoreActors)) 8{ 9 UE_LOG(LogTemp, Warning, TEXT("Ignore nums: %i"), IgnoreActors.Num()); 10 UGameplayStatics::ApplyRadialDamage(GetWorld(), DamageAmount, GetActorLocation(), DamageRadius, UDamageType::StaticClass(), 11 IgnoreActors, this, GetController(), DoFullDamage); 12} 13else 14{ 15 UGameplayStatics::ApplyRadialDamage(GetWorld(), DamageAmount, GetActorLocation(), DamageRadius, UDamageType::StaticClass(), 16 {GetOwner()}, this, GetController(), DoFullDamage); 17}
通过队员获取阵营成员列表
public
ShootThemUp: STUGameModeBase.h
1bool GetTeamMemberByActor(AActor *Actor, TArray<AActor *> &TeamMembers) const;
ShootThemUp: STUGameModeBase.cpp
1bool ASTUGameModeBase::GetTeamMemberByActor(AActor *Actor, TArray<AActor *> &TeamMembers) const 2{ 3 const auto Pawn = Cast<APawn>(Actor); 4 if (!Pawn) return false; 5 6 const auto Controller = Pawn->Controller; 7 if (!Controller) return false; 8 9 const auto PlayerState = Cast<ASTUPlayerState>(Controller->PlayerState); 10 if (!PlayerState) return false; 11 12 const auto TeamID = PlayerState->GetTeamID(); 13 if (TeamID <= TeamMemberList.Num()) 14 { 15 TeamMembers = TeamMemberList[TeamID - 1]; 16 return true; 17 } 18 19 return false; 20}