470 lines
14 KiB
C++
470 lines
14 KiB
C++
// 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
|
||
};
|