// Source/TengriPlatformer/Movement/TengriMovementComponent.h #pragma once #include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "TengriPlatformer/Movement/Core/TengriMovementConfig.h" #include "TengriMovementComponent.generated.h" class UCapsuleComponent; /** * Custom movement component for deterministic 3D platformer physics. * Handles acceleration, friction, gravity, collision, and ground snapping. */ UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) class TENGRIPLATFORMER_API UTengriMovementComponent : public UActorComponent { GENERATED_BODY() public: UTengriMovementComponent(); protected: virtual void BeginPlay() override; public: virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; // ======================================================================== // BLUEPRINT API // ======================================================================== /** * Sets the movement input vector. Call every frame from PlayerController. * @param NewInput - Raw input (will be clamped to 1.0 and Z zeroed) */ UFUNCTION(BlueprintCallable, Category = "Tengri Movement") void SetInputVector(FVector NewInput); // ======================================================================== // CONFIGURATION // ======================================================================== /** Movement parameters data asset */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tengri Movement") TObjectPtr MovementConfig; // ======================================================================== // RUNTIME STATE // ======================================================================== /** Current velocity in cm/s */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tengri Movement|State") FVector Velocity; /** True when character is on walkable ground */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tengri Movement|State") bool bIsGrounded = false; /** Cached surface thresholds (cosines) for performance */ UPROPERTY(VisibleAnywhere, Category = "Tengri Movement|Debug") FSurfaceThresholds CachedThresholds; private: // ======================================================================== // INTERNAL STATE // ======================================================================== UPROPERTY() TObjectPtr OwnerCapsule; /** Normalized input vector (Z always 0) */ FVector InputVector = FVector::ZeroVector; // ======================================================================== // INITIALIZATION // ======================================================================== void InitializeSystem(); // ======================================================================== // MOVEMENT PHASES // ======================================================================== /** Phase 1: Apply acceleration toward input direction or friction to stop */ void ApplyAccelerationAndFriction(float DeltaTime); /** Phase 2: Rotate character to face movement direction */ void ApplyRotation(float DeltaTime) const; /** Phase 3: Apply gravity when airborne */ void ApplyGravity(float DeltaTime); /** Phase 4: Resolve movement with collision */ FVector ResolveMovementWithCollision(float DeltaTime); /** Phase 5: Snap to ground to prevent slope jitter */ bool PerformGroundSnapping(FVector& InOutLocation, FHitResult& OutSnapHit) const; /** Phase 6: Update grounded state based on collision results */ void UpdateGroundedState(bool bMoveBlocked, float HitNormalZ, bool bJustSnapped); };