Files
PHY/Plugins/GCS/Source/GenericCombatSystem/Public/Collision/GCS_TraceStructLibrary.h
2026-03-03 01:23:02 +08:00

470 lines
14 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Copyright 2025 https://yuewu.dev/en All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "CollisionShape.h"
#include "CollisionQueryParams.h"
#include "Collision/GCS_TraceEnumLibrary.h"
#include "Engine/DataTable.h"
#include "StructUtils/InstancedStruct.h"
#include "UObject/Object.h"
#include "GCS_TraceStructLibrary.generated.h"
class UTargetingPreset;
class UGCS_TraceSystemComponent;
USTRUCT(BlueprintType)
struct FGCS_TraceSweepSetting
{
GENERATED_BODY()
/**
* The type of sweep to perform for collision detection.
* 执行碰撞检测的扫描类型。
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "GCS")
EGCS_TraceSweepType SweepType = EGCS_TraceSweepType::ByChannel;
/**
* The collision channel to use for channel-based sweeping.
* 用于基于通道扫描的碰撞通道。
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "GCS",
meta = (EditCondition = "SweepType == EGCS_TraceSweepType::ByChannel", EditConditionHides))
TEnumAsByte<ECollisionChannel> TraceChannel = ECC_Visibility;
/**
* The object types to use for object-based sweeping.
* 用于基于对象扫描的对象类型。
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "GCS",
meta = (EditCondition = "SweepType == EGCS_TraceSweepType::ByObject", EditConditionHides))
TArray<TEnumAsByte<ECollisionChannel>> ObjectTypes;
/**
* The collision profile name to use for profile-based sweeping.
* 用于基于配置扫描的碰撞配置名称。
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "GCS",
meta = (EditCondition = "SweepType == EGCS_TraceSweepType::ByProfile", EditConditionHides))
FName ProfileName = NAME_None;
/**
* Whether to trace against complex collision.
* 是否对复杂碰撞进行追踪。
*/
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "GCS")
bool bTraceComplex = false;
};
/**
* Build collision shape by static parameters
* 通过静态参数构建碰撞形状。
* 在SourceComponent空间内的静态形状。
*/
USTRUCT(meta = (Hidden, DisplayName = "Collision Shape"))
struct GENERICCOMBATSYSTEM_API FGCS_CollisionShape
{
GENERATED_BODY()
virtual ~FGCS_CollisionShape() = default;
virtual bool InitializeShape(const UPrimitiveComponent* SourceComponent);
virtual FTransform GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const;
virtual FCollisionShape GetDynamicCollisionShape(const UPrimitiveComponent* SourceComponent, const float& Time) const;
};
/**
* Build collision shape by static parameters
* 通过静态参数构建碰撞形状。
* 在SourceComponent空间内的静态形状。
*/
USTRUCT(meta = (DisplayName = "Collision Shape (Static)"))
struct GENERICCOMBATSYSTEM_API FGCS_CollisionShape_Static : public FGCS_CollisionShape
{
GENERATED_BODY()
/**
* The type of collision shape to use.
* 要使用的碰撞形状类型。
*/
UPROPERTY(EditAnywhere, Category = "GCS")
EGCS_CollisionShapeType ShapeType = EGCS_CollisionShapeType::Sphere;
/**
* The orientation/rotation of the collision shape.
* 碰撞形状的方向/旋转。
*/
UPROPERTY(EditAnywhere, Category = "GCS",
meta = (EditCondition = "ShapeType != EGCS_CollisionShapeType::Sphere", EditConditionHides))
FRotator Orientation = FRotator::ZeroRotator;
/**
* The position offset of the collision shape.
* 碰撞形状的位置偏移。
*/
UPROPERTY(EditAnywhere, Category = "GCS")
FVector Offset = FVector::ZeroVector;
/**
* The radius of the sphere or capsule.
* 球体或胶囊体的半径。
*/
UPROPERTY(EditAnywhere, Category = "GCS",
meta = (EditCondition = "ShapeType != EGCS_CollisionShapeType::Box", EditConditionHides))
float Radius = 10.f;
/**
* The half height of the capsule.
* 胶囊体的半高。
*/
UPROPERTY(EditAnywhere, Category = "GCS",
meta = (EditCondition = "ShapeType == EGCS_CollisionShapeType::Capsule", EditConditionHides))
float HalfHeight = 10.f;
/**
* The half size of the box.
* 盒子的半尺寸。
*/
UPROPERTY(EditAnywhere, Category = "GCS",
meta = (EditCondition = "ShapeType == EGCS_CollisionShapeType::Box", EditConditionHides))
FVector HalfSize = FVector(10.f, 10.f, 10.f);
virtual bool InitializeShape(const UPrimitiveComponent* SourceComponent) override;
virtual FTransform GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const override;
virtual FCollisionShape GetDynamicCollisionShape(const UPrimitiveComponent* SourceComponent, const float& Time) const override;
};
/**
* Build dynamic collision shape by binding to shape component(Box/Sphere/Capsule).
* 通过绑定Shape组件(Box/Sphere/Capsule)构建动态碰撞形状。
* 在SourceComponent空间内的与SourceComponent进行匹配的形状。
*/
USTRUCT(meta = (DisplayName = "Collision Shape (Shape Based)"))
struct GENERICCOMBATSYSTEM_API FGCS_CollisionShape_ShapeBased : public FGCS_CollisionShape
{
GENERATED_BODY()
/**
* The type of collision shape to use.
* 要使用的碰撞形状类型。
*/
UPROPERTY(EditAnywhere, Category = "GCS")
EGCS_CollisionShapeType ShapeType = EGCS_CollisionShapeType::Sphere;
/**
* The orientation/rotation of the collision shape.
* 碰撞形状的方向/旋转。
*/
UPROPERTY(EditAnywhere, Category = "GCS",
meta = (EditCondition = "ShapeType != EGCS_CollisionShapeType::Sphere", EditConditionHides))
FRotator Orientation = FRotator::ZeroRotator;
UPROPERTY(EditAnywhere, Category = "GCS")
FVector Offset = FVector::ZeroVector;
UPROPERTY()
float Radius = 10.f;
UPROPERTY()
float HalfHeight = 10.f;
UPROPERTY()
FVector HalfSize = FVector(10.f, 10.f, 10.f);
virtual bool InitializeShape(const UPrimitiveComponent* SourceComponent) override;
virtual FTransform GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const override;
virtual FCollisionShape GetDynamicCollisionShape(const UPrimitiveComponent* SourceComponent, const float& Time) const override;
};
/**
* 在SourceComponent空间内跟随SourceComponent的某Socket/Bone运动的形状。
*/
USTRUCT(meta = (DisplayName = "Collision Shape (Attached)"))
struct GENERICCOMBATSYSTEM_API FGCS_CollisionShape_Attached : public FGCS_CollisionShape_Static
{
GENERATED_BODY()
/**
* Name of the socket or bone the shape will be attached to.
* 形状将附加到的插槽或骨骼的名称。
*/
UPROPERTY(EditAnywhere, Category="GCS")
FName SocketOrBoneName;
virtual bool InitializeShape(const UPrimitiveComponent* SourceComponent) override;
virtual FTransform GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const override;
};
/**
* Build dynamic capsule collision shape by mesh's sockets.
* 通过网格的指定Sockets构建动态碰撞形状。
*/
USTRUCT(meta = (DisplayName = "Collision Shape (Socket Based)"))
struct GENERICCOMBATSYSTEM_API FGCS_CollisionShape_SocketBased : public FGCS_CollisionShape
{
GENERATED_BODY()
/**
* The name of the starting socket on the mesh.
* 网格上起始插槽的名称。
*/
UPROPERTY(EditAnywhere, Category = "GCS")
FName MeshSocketStart = TEXT("TrailStart");
/**
* The name of the ending socket on the mesh.
* 网格上结束插槽的名称。
*/
UPROPERTY(EditAnywhere, Category = "GCS")
FName MeshSocketEnd = TEXT("TrailEnd");
/**
* Additional length offset for the socket-based shape.
* 基于插槽的形状的额外长度偏移。
*/
UPROPERTY(EditAnywhere, Category = "GCS")
float MeshSocketLengthOffset = 0;
/**
* The radius of the capsule.
* 胶囊体的半径。
*/
UPROPERTY(EditAnywhere, Category = "GCS")
float Radius = 10.f;
/**
* The orientation/rotation of the collision shape.
* 碰撞形状的方向/旋转。
*/
UPROPERTY()
FRotator Orientation = FRotator::ZeroRotator;
/**
* The position offset of the collision shape.
* 碰撞形状的位置偏移。
*/
UPROPERTY()
FVector Offset = FVector::ZeroVector;
/**
* The half height of the capsule.
* 胶囊体的半高。
*/
UPROPERTY()
float HalfHeight = 10.f;
virtual FTransform GetTransform(const UPrimitiveComponent* SourceComponent, const float& Time) const override;
virtual bool InitializeShape(const UPrimitiveComponent* SourceComponent) override;
virtual FCollisionShape GetDynamicCollisionShape(const UPrimitiveComponent* SourceComponent, const float& Time) const override;
};
/**
* Structure for defining collision trace instances.
* 定义碰撞检测实例的结构。
*/
USTRUCT(BlueprintType)
struct GENERICCOMBATSYSTEM_API FGCS_TraceDefinition : public FTableRowBase
{
GENERATED_BODY()
FGCS_TraceDefinition();
/**
* Tag used as Trace identifier.
* 此Trace的Tag标识。
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trace Settings", meta=(Categories="GGF.Combat.Trace"))
FGameplayTag TraceTag;
/**
* Defines the shape used for detecting hit results.
* 定义用于获取命中结果的形状。
*/
UPROPERTY(EditAnywhere, Category = "Trace Settings", meta=(ExcludeBaseStruct, BaseStruct = "/Script/GenericCombatSystem.GCS_CollisionShape"))
FInstancedStruct CollisionShape{FInstancedStruct::Make(FGCS_CollisionShape_Static())};
/**
* Settings for the sweep operation.
* 扫描操作的设置。
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trace Settings")
FGCS_TraceSweepSetting SweepSetting;
/**
* The type of tick policy to use for this trace.
* 此Trace使用的tick策略类型。
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trace Settings")
EGCS_TraceTickType TraceTickType{EGCS_TraceTickType::FixedFrameRate};
/**
* The fixed frame rate for ticking when using FixedFrameRate policy.
* 使用固定帧率策略时的固定帧率。
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trace Settings",
meta = (EditCondition = "TraceTickType == EGCS_TraceTickType::FixedFrameRate", EditConditionHides))
int32 FixedTickFrameRate = 30;
/**
* The distance threshold for ticking when using DistanceBased policy.
* 使用基于距离策略时的距离阈值。
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trace Settings",
meta = (EditCondition = "TraceTickType == EGCS_TraceTickType::DistanceBased", EditConditionHides))
int32 DistanceTickThreshold = 30;
/**
* The angle threshold for ticking when using DistanceBased policy (in degrees).
* 使用基于距离策略时的角度阈值(度)。
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Trace Settings",
meta = (EditCondition = "TraceTickType == EGCS_TraceTickType::DistanceBased", EditConditionHides))
float AngleTickThreshold = 15.0f; // Degrees
bool IsValidDefinition() const;
FString ToString() const;
};
/**
* Simple struct used for trace query.
*/
USTRUCT(BlueprintType)
struct GENERICCOMBATSYSTEM_API FGCS_TraceHandle
{
GENERATED_BODY()
/**
* The gameplay tag identifying this trace.
* 标识此Trace的游戏标签。
*/
UPROPERTY(BlueprintReadOnly, Category = "GCS")
FGameplayTag TraceTag;
/**
* The unique GUID for this trace instance.
* 此Trace实例的唯一GUID。
*/
UPROPERTY(BlueprintReadOnly, Category = "GCS")
FGuid Guid;
/**
* The source object that created this trace.
* 创建此Trace的源对象。
*/
UPROPERTY(BlueprintReadOnly, Category = "GCS")
TWeakObjectPtr<UObject> SourceObject;
bool IsValidHandle() const;
// Equality operator
friend bool operator==(const FGCS_TraceHandle& A, const FGCS_TraceHandle& B)
{
return A.TraceTag == B.TraceTag &&
A.Guid == B.Guid &&
A.SourceObject == B.SourceObject;
}
// Inequality operator
friend bool operator!=(const FGCS_TraceHandle& A, const FGCS_TraceHandle& B)
{
return !(A == B);
}
// Hash function for TMap/TSet
friend uint32 GetTypeHash(const FGCS_TraceHandle& Handle)
{
uint32 Hash = GetTypeHash(Handle.TraceTag);
Hash = HashCombine(Hash, GetTypeHash(Handle.Guid));
Hash = HashCombine(Hash, GetTypeHash(Handle.SourceObject));
return Hash;
}
FString ToDebugString() const
{
FString TagName = TraceTag.ToString();
if (TraceTag.IsValid())
{
TArray<FString> TagNames;
TraceTag.ToString().ParseIntoArray(TagNames,TEXT("."));
if (TagNames.Num() > 0)
{
TagName = TagNames.Last();
}
}
return FString::Printf(TEXT("%s;%s"), *TagName, SourceObject.IsValid() ? *GetNameSafe(SourceObject.Get()) : TEXT("None"));
}
};
// 补帧数据.
struct FGCS_TraceSubTick
{
FTransform StartTransform;
FTransform EndTransform;
FTransform AverageTransform;
};
USTRUCT(BlueprintType)
struct FGCS_TraceState
{
GENERATED_BODY()
void ChangeExecutionState(bool bNewTraceState, bool bStopImmediate = true);
void UpdatePreviousTransform(const FTransform& Transform);
// Get the world space transform of this trace.
FTransform GetCurrentTransform() const;
// Begin Runtime references
UPROPERTY()
UWorld* World{nullptr};
UPROPERTY()
TObjectPtr<UPrimitiveComponent> SourceComponent{nullptr};
UPROPERTY()
TObjectPtr<UGCS_TraceSystemComponent> OwningSystem{nullptr};
// End Runtime references
// Begin Static Data
FGCS_TraceSweepSetting SweepSetting;
// End Static Data
// Begin runtime data
FGCS_TraceHandle Handle;
bool IsPendingRemoval = false;
// The modified dynamic shape.
FInstancedStruct Shape;
TArray<FTransform, TFixedAllocator<2>> TransformsOverTime;
EGCS_TraceExecutionState ExecutionState = EGCS_TraceExecutionState::Stopped;
FCollisionShape CollisionShapeOverTime;
TArray<FGCS_TraceSubTick> SubTicks;
EGCS_TraceTickType TickPolicy;
float TickInterval = 1 / 30;
float AngleThreshold = 15.0f; // Degrees
bool bShouldTickThisFrame = false;
float TimeSinceLastTick = 0;
// how long this state active?
//
float TimeSinceActive = 0;
int32 TotalTickNumDuringExecution = 0;
TArray<TObjectPtr<AActor>> HitActors;
FCollisionQueryParams CollisionParams;
FCollisionResponseParams ResponseParams;
FCollisionObjectQueryParams ObjectQueryParams;
// End runtime data
};