tengri/Source/TengriPlatformer/Domains/Movement/Config/TengriMovementConfig.h

241 lines
9.4 KiB
C++

// Request Games © All rights reserved
// Source/TengriPlatformer/Movement/Core/TengriMovementConfig.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataAsset.h"
#include "TengriMovementConfig.generated.h"
// ============================================================================
// SURFACE THRESHOLDS
// ============================================================================
/**
* Pre-calculated cosine thresholds for surface classification.
* Generated from angle degrees in UTengriMovementConfig.
*/
USTRUCT(BlueprintType)
struct TENGRIPLATFORMER_API FSurfaceThresholds
{
GENERATED_BODY()
/** Minimum Normal.Z for walkable floor (cos of max walkable angle) */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Thresholds")
float WalkableZ = 0.64f;
/** Minimum Normal.Z for steep slopes */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Thresholds")
float SteepSlopeZ = 0.08f;
/** Minimum Normal.Z for walls (below = ceiling/overhang) */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Thresholds")
float WallZ = -0.08f;
// === Classification Helpers ===
FORCEINLINE bool IsWalkable(const float NormalZ) const
{
return NormalZ >= WalkableZ;
}
FORCEINLINE bool IsSteepSlope(const float NormalZ) const
{
return NormalZ >= SteepSlopeZ && NormalZ < WalkableZ;
}
FORCEINLINE bool IsWall(const float NormalZ) const
{
return NormalZ >= WallZ && NormalZ < SteepSlopeZ;
}
FORCEINLINE bool IsOverhang(const float NormalZ) const
{
return NormalZ < WallZ;
}
};
// ============================================================================
// MOVEMENT CONFIG
// ============================================================================
/**
* Data asset containing all movement system parameters.
* Create instances in Content Browser for different character types.
*/
UCLASS(BlueprintType)
class TENGRIPLATFORMER_API UTengriMovementConfig : public UDataAsset
{
GENERATED_BODY()
public:
// ========================================================================
// PHYSICS
// ========================================================================
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Physics")
float MaxSpeed = 800.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Physics")
float Acceleration = 2048.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Physics")
float Friction = 8.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Physics")
float RotationSpeed = 360.0f;
/** Minimum speed (cm/s) required to rotate character toward movement */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Physics")
float MinSpeedForRotation = 10.0f;
// ========================================================================
// JUMP CONFIGURATION
// ========================================================================
/** Target height of the jump in cm (UE units) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Jump", meta = (ClampMin = "10.0"))
float MaxJumpHeight = 200.0f;
/** Minimum height for a short hop (when button is released early) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Jump", meta = (ClampMin = "1.0"))
float MinJumpHeight = 40.0f;
/** Time (seconds) to reach the peak of the jump. Defines "heaviness". */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Jump", meta = (ClampMin = "0.1", ClampMax = "2.0"))
float TimeToJumpApex = 0.5f;
// ========================================================================
// JUMP FEEL (TIMINGS)
// ========================================================================
/** Time (seconds) after falling off a ledge during which jump is still allowed */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Jump|Feel", meta = (ClampMin = "0.0"))
float CoyoteTime = 0.15f;
/** Time (seconds) to buffer a jump input before hitting the ground */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Jump|Feel", meta = (ClampMin = "0.0"))
float JumpBufferTime = 0.15f;
// ========================================================================
// AIR PHYSICS
// ========================================================================
/** Multiplier for acceleration when in air (0 = no control, 1 = full control) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Air Physics", meta = (ClampMin = "0.0", ClampMax = "1.0"))
float AirControl = 0.5f;
/** Friction applied while in air (usually 0 for platformers) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Air Physics")
float AirFriction = 0.0f;
// ========================================================================
// CALCULATED VALUES (READ ONLY)
// ========================================================================
/** Gravity magnitude calculated from Jump Height & Time */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Calculated")
float Gravity = 980.0f;
/** Initial Z velocity required to reach MaxJumpHeight */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Calculated")
float JumpVelocity = 0.0f;
/** Velocity cut-off for variable jump height */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Calculated")
float MinJumpVelocity = 0.0f;
// ========================================================================
// AIR PHYSICS
// ========================================================================
/** Multiplier for gravity when falling. Makes jump feel "heavy" and snappy. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Air Physics", meta = (ClampMin = "1.0"))
float FallingGravityScale = 1.5f;
/** Maximum falling speed (cm/s). Prevents infinite acceleration. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Air Physics", meta = (ClampMin = "0.0"))
float TerminalVelocity = 2000.0f;
/** Z velocity threshold to consider a landing "heavy" (e.g. for landing animation/shake) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Air Physics")
float HeavyLandVelocityThreshold = -1000.0f;
// ========================================================================
// SURFACE ANGLES
// ========================================================================
/** Maximum angle (degrees) that counts as walkable floor */
UPROPERTY(EditAnywhere, Category = "Surface Angles", meta = (ClampMin = "0", ClampMax = "89"))
float WalkableAngleDeg = 50.0f;
/** Maximum angle for steep slopes (limited movement) */
UPROPERTY(EditAnywhere, Category = "Surface Angles", meta = (ClampMin = "0", ClampMax = "89"))
float SteepSlopeAngleDeg = 85.0f;
/** Maximum angle for walls (above = ceiling) */
UPROPERTY(EditAnywhere, Category = "Surface Angles", meta = (ClampMin = "90", ClampMax = "180"))
float WallAngleDeg = 95.0f;
// ========================================================================
// COLLISION
// ========================================================================
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Collision")
int32 MaxSlideIterations = 3;
/** Maximum height of step that can be walked over */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Collision")
float MaxStepHeight = 45.0f;
// ========================================================================
// GROUND SNAPPING
// ========================================================================
/** Distance to search for ground when snapping */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ground Snapping")
float GroundSnapDistance = 20.0f;
/** Micro-offset above ground to prevent floor penetration */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ground Snapping")
float GroundSnapOffset = 0.15f;
// ========================================================================
// SLOPE PHYSICS
// ========================================================================
/** Velocity damping on steep slopes (0 = full stop, 1 = full slide) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Physics", meta = (ClampMin = "0", ClampMax = "1"))
float SteepSlopeSlideFactor = 0.0f;
// ========================================================================
// FIXED TIMESTEP
// ========================================================================
/** Physics update rate in Hz (default: 120) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Fixed Timestep",
meta = (ClampMin = "30", ClampMax = "240"))
float PhysicsTickRate = 120.0f;
/** Maximum accumulated time before clamping (prevents spiral of death) */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Fixed Timestep",
meta = (ClampMin = "0.05", ClampMax = "0.5"))
float MaxAccumulatedTime = 0.1f;
/** Enable interpolation between physics states */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Fixed Timestep")
bool bEnableInterpolation = true;
// ========================================================================
// API
// ========================================================================
/** Converts degree angles to cosine thresholds for runtime use */
FSurfaceThresholds GetThresholds() const;
#if WITH_EDITOR
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif
};