UE4 范围伤害RadiusDamage及碰撞检测通道ECollisionChanel

UE4的范围伤害函数为

/** Hurt locally authoritative actors within the radius. Will only hit components that block the Visibility channel.
...
 * @param DamagePreventionChannel - Damage will not be applied to victim if there is something between the origin and the victim which blocks traces on this channel
 ...
 */
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="Game|Damage", meta=(WorldContext="WorldContextObject", AutoCreateRefTerm="IgnoreActors"))
static bool ApplyRadialDamageWithFalloff(const UObject* WorldContextObject, float BaseDamage, float MinimumDamage, const FVector& Origin, float DamageInnerRadius, float DamageOuterRadius, float DamageFalloff, TSubclassOf DamageTypeClass, const TArray& IgnoreActors, AActor* DamageCauser = NULL, AController* InstigatedByController = NULL, ECollisionChannel DamagePreventionChannel = ECC_Visibility);

函数参数除伤害值和伤害范围外还有一个 DamagePreventionChannel,该值是碰撞通道枚举值ECC类型的,作用是检测伤害中心与Actor在该通道上是否有阻挡,有的话不造成伤害,该值默认是ECC_Visibility,意味着编辑器里所有勾选了Visiblity的TraceChanel的Actor均会阻挡伤害,可以改成ECC_MAX来取消掉阻挡检测
if (DamagePreventionChannel == ECC_MAX || ComponentIsDamageableFrom(Overlap.Component.Get(), Origin, DamageCauser, IgnoreActors, DamagePreventionChannel, Hit))
				{
					TArray& HitList = OverlapComponentMap.FindOrAdd(OverlapActor);
					HitList.Add(Hit);
				}

但是这里有一个点,就是这个通道是在检测完球体内的component后才进行过滤的,而这个检测是调用的physics的检测,

TArray Overlaps;
	UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject);
	World->OverlapMultiByObjectType(Overlaps, Origin, FQuat::Identity, FCollisionObjectQueryParams(FCollisionObjectQueryParams::InitType::AllDynamicObjects), FCollisionShape::MakeSphere(DamageOuterRadius), SphereParams); 

这个会检测到所有非worldstatic的component

UE4 范围伤害RadiusDamage及碰撞检测通道ECollisionChanel_第1张图片

如图,abc为伤害范围内Actor的component,引擎首先获取到这些component放到TArray Overlaps里,再通过在特定通道上的射线检测确定能否造成伤害,如图中a如果在特定通道上被阻挡将不会接受伤害。

如果想要某个特定component不接受RadiusDamage而其他component又不受范围内物体阻挡不修改引擎是没有办法实现的,一种简单粗暴的方法是给这个特定的component设置拿一个单独的碰撞类型到Overlaps后判断其碰撞类型为这个特定类型则不处理后续的伤害

if (Overlap.Component->GetCollisionObjectType()!=ECC_GameTraceChannel3)//to filter RadiusDamage ObjectType

这里ECC_GameTraceChannel3即使特定的碰撞类型,在C++里定义在EngineTypes.h里,注意ECC_EngineTraceChannel1与ECC_GameTraceChannel1的区别。

UENUM(BlueprintType)
enum ECollisionChannel
{

	ECC_WorldStatic UMETA(DisplayName="WorldStatic"),
	ECC_WorldDynamic UMETA(DisplayName="WorldDynamic"),
	ECC_Pawn UMETA(DisplayName="Pawn"),
	ECC_Visibility UMETA(DisplayName="Visibility" , TraceQuery="1"),
	ECC_Camera UMETA(DisplayName="Camera" , TraceQuery="1"),
	ECC_PhysicsBody UMETA(DisplayName="PhysicsBody"),
	ECC_Vehicle UMETA(DisplayName="Vehicle"),
	ECC_Destructible UMETA(DisplayName="Destructible"),

	/** Reserved for gizmo collision */
	ECC_EngineTraceChannel1 UMETA(Hidden),

	ECC_EngineTraceChannel2 UMETA(Hidden),
	...
	ECC_EngineTraceChannel6 UMETA(Hidden),

	ECC_GameTraceChannel1 UMETA(Hidden),
	ECC_GameTraceChannel2 UMETA(Hidden),
	ECC_GameTraceChannel3 UMETA(Hidden),
	...
	ECC_GameTraceChannel18 UMETA(Hidden),
	
	/** Add new serializeable channels above here (i.e. entries that exist in FCollisionResponseContainer) */
	/** Add only nonserialized/transient flags below */

	// NOTE!!!! THESE ARE BEING DEPRECATED BUT STILL THERE FOR BLUEPRINT. PLEASE DO NOT USE THEM IN CODE

	ECC_OverlapAll_Deprecated UMETA(Hidden),
	ECC_MAX,
};


在编辑器里定义在Project\Config\DefaultEngine.ini里

+DefaultChannelResponses=(Channel=ECC_GameTraceChannel3,Name="RadiusDamage",...

在编辑器里设置好默认值,默认对所有其他通道忽略,只有特定component的碰撞类型设置为这个"RadiusDamage"即可。

你可能感兴趣的:(UE4 范围伤害RadiusDamage及碰撞检测通道ECollisionChanel)