The ground measurement was the slowest part of every iteration: the game ran until the shell's timeout because nothing told it to stop. -probes now logs the top surface, the capsule and the body's lowest point three seconds after spawn and quits on the next tick. A run went from minutes to 13.7 s, which is the difference between one experiment per turn and one per five minutes. Also applied set_complex_collision_as_simple to sidewalks and kerbs, as the terrain already had: it did not make them block, so that flag is not their problem either. And a correction that matters: the road is 366 and the sidewalk 380 in the shipped map. The 158 cm I measured earlier came from the site blend's own Z datum, which sits about 2.2 m below the map's because the terrain was added after that blend was written. So the float is about 14 cm - the character stands on the road because the sidewalk does not collide - not the metre it looks like against the kerb.
244 lines
8.4 KiB
C++
244 lines
8.4 KiB
C++
// First-person player character for the 0.1.0 walkable Hollywood block.
|
|
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "GameFramework/Character.h"
|
|
#include "InputActionValue.h"
|
|
#include "GigLineCharacter.generated.h"
|
|
|
|
class UAnimSequence;
|
|
class UCameraComponent;
|
|
class UInputAction;
|
|
class UInputMappingContext;
|
|
class USpringArmComponent;
|
|
|
|
|
|
/**
|
|
* Walking first-person character.
|
|
*
|
|
* Movement is C++ and network-agnostic in the shapes it uses (Enhanced Input ->
|
|
* AddMovementInput), so a Blueprint subclass can retune values without touching
|
|
* code. Defaults are human-scale: 1.75 m capsule, 1.6 m eye height, 4 m/s walk.
|
|
*/
|
|
UCLASS()
|
|
class GIGLINE_API AGigLineCharacter : public ACharacter
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
AGigLineCharacter();
|
|
|
|
virtual void BeginPlay() override;
|
|
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
|
|
virtual void Tick(float DeltaSeconds) override;
|
|
|
|
protected:
|
|
/** Loads the Enhanced Input assets from /Game/Input; called from BeginPlay. */
|
|
void LoadInputAssets();
|
|
|
|
/** Teleports back to the map's PlayerStart and clears velocity. */
|
|
void ResetToStart();
|
|
void TogglePause();
|
|
|
|
public:
|
|
/** True while the third-person rig is the active view (for the debug overlay). */
|
|
bool IsThirdPerson() const { return bThirdPerson; }
|
|
|
|
/** Review harness: hold or release forward input from the screenshot actor. */
|
|
void SetReviewWalk(bool bEnable);
|
|
|
|
/** Review harness: put the pawn back where it spawned, after a walking capture. */
|
|
void ReturnToStartForReview();
|
|
|
|
protected:
|
|
/** Swaps between the first-person and third-person rigs (V). */
|
|
void ToggleCamera();
|
|
|
|
/**
|
|
* Plays the idle or walk clip on the visible body.
|
|
*
|
|
* Called from the movement tick rather than from input: an animation state
|
|
* driven by speed is correct whether the player walked, was pushed, or fell.
|
|
* Only switches when the clip changes, because PlayAnimation restarts a clip
|
|
* and calling it every frame would freeze the cycle at its first key.
|
|
*/
|
|
void UpdateBodyAnimation();
|
|
|
|
/** Velocity above which the walk clip plays, in cm/s (0.1 m/s tolerance). */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Animation")
|
|
float WalkAnimationThreshold = 10.0f;
|
|
|
|
/**
|
|
* TEMP QA: scripted walk / reset / pause verification.
|
|
*
|
|
* Enabled only by the `-qaselftest` command-line switch, so it never runs in
|
|
* normal play. It exists because those three behaviours were listed as
|
|
* "needs a human at the keyboard" and a repeatable headless check beats
|
|
* waiting for one.
|
|
*/
|
|
void StartQASelfTest();
|
|
|
|
/** Set while the self-test is driving forward input. */
|
|
bool bQATestWalking = false;
|
|
|
|
/** Repeating timer that captures StartLocation on first ground contact. */
|
|
FTimerHandle SettleHandle;
|
|
|
|
/** Where the player started, so reset returns there rather than the origin. */
|
|
UPROPERTY()
|
|
FVector StartLocation = FVector::ZeroVector;
|
|
|
|
UPROPERTY()
|
|
FRotator StartRotation = FRotator::ZeroRotator;
|
|
|
|
bool bPaused = false;
|
|
|
|
/** Moves along the control yaw by the given forward/strafe amounts. */
|
|
void ApplyMove(float Forward, float Strafe);
|
|
|
|
/** Handles input actions to movement; assigned in C++ so the project runs with no assets. */
|
|
/** Forward/back and strafe are separate 1D actions, summed into one move. */
|
|
void MoveForward(const FInputActionValue& Value);
|
|
void MoveStrafe(const FInputActionValue& Value);
|
|
void MoveBack(const FInputActionValue& Value);
|
|
void MoveLeft(const FInputActionValue& Value);
|
|
void Look(const FInputActionValue& Value);
|
|
void StartJump();
|
|
void StopJump();
|
|
|
|
/** Mapping context for the gamepad and keyboard. */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputMappingContext> MappingContext;
|
|
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> MoveAction;
|
|
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> MoveBackAction;
|
|
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> StrafeAction;
|
|
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> StrafeLeftAction;
|
|
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> LookAction;
|
|
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> JumpAction;
|
|
|
|
/** Respawn at the start point (R). */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> ResetAction;
|
|
|
|
/** Toggle the pause menu (Escape). */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> PauseAction;
|
|
|
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
|
|
TObjectPtr<UCameraComponent> FirstPersonCamera;
|
|
|
|
/**
|
|
* Third-person boom. Collision testing is on, which is what stops the camera
|
|
* from ending up inside a wall: the arm shortens until the camera is clear
|
|
* instead of clipping through geometry.
|
|
*/
|
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
|
|
TObjectPtr<USpringArmComponent> ThirdPersonArm;
|
|
|
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Camera")
|
|
TObjectPtr<UCameraComponent> ThirdPersonCamera;
|
|
|
|
/** Boom length in cm: far enough to see the body, close enough to read the street. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera")
|
|
float ThirdPersonBoomLength = 340.0f;
|
|
|
|
/**
|
|
* Hair, as its own skeletal mesh following the body's pose.
|
|
*
|
|
* A second component rather than geometry joined into the body: Unreal collapses
|
|
* the second material slot on a skeletal-mesh import, so joined hair rendered with
|
|
* the skin material. The character-artist skill calls for hair cards to be their
|
|
* own mesh for the same reason it calls for swappable parts to be separate.
|
|
*/
|
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Body")
|
|
TObjectPtr<USkeletalMeshComponent> HairMesh;
|
|
|
|
/**
|
|
* Garments, each its own skeletal mesh on a leader pose component.
|
|
*
|
|
* The character-artist skill keeps clothing separate so a piece can be swapped or
|
|
* re-materialled on its own; it also sidesteps the material-slot collapse that
|
|
* makes joined multi-material meshes arrive with one slot.
|
|
*/
|
|
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Body")
|
|
TArray<TObjectPtr<USkeletalMeshComponent>> Clothing;
|
|
|
|
UPROPERTY()
|
|
TObjectPtr<UAnimSequence> IdleAnimation;
|
|
|
|
UPROPERTY()
|
|
TObjectPtr<UAnimSequence> WalkAnimation;
|
|
|
|
/** True while the third-person rig is the active view. */
|
|
UPROPERTY(BlueprintReadOnly, Category = "Camera")
|
|
bool bThirdPerson = false;
|
|
|
|
/** Clip currently playing on the body, so UpdateBodyAnimation can diff it. */
|
|
UPROPERTY()
|
|
TObjectPtr<UAnimSequence> PlayingAnimation;
|
|
|
|
/** True while `-walk` holds forward input for the screenshot run. */
|
|
bool bWalkForever = false;
|
|
|
|
/** Applies the `-walk` forward input when the flag is set and the pawn is grounded. */
|
|
void WalkForever();
|
|
|
|
/** Debug-overlay action (F3). */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> ToggleDebugAction;
|
|
|
|
/** Current boom length and camera position of the third-person rig. */
|
|
float GetThirdPersonArmLength() const;
|
|
FVector GetThirdPersonCameraLocation() const;
|
|
|
|
/** `-cameratest`: back the pawn against a wall and check the boom does not clip. */
|
|
void UpdateCameraCollisionTest(float DeltaSeconds);
|
|
|
|
UPROPERTY()
|
|
TObjectPtr<class AStaticMeshActor> CameraTestWall;
|
|
|
|
/** `-probes`: log the ground measurements, then quit. */
|
|
bool bProbeAndQuit = false;
|
|
|
|
/** Seconds until the foot-contact probe runs; 0 disables it. */
|
|
float FootProbeDelay = 0.f;
|
|
void LogFootProbes();
|
|
|
|
FVector LastWallNormal = FVector::ZeroVector;
|
|
bool bCameraTest = false;
|
|
bool CameraTestPlaced = false;
|
|
float CameraTestElapsed = 0.0f;
|
|
|
|
/** Flips the gigline.Debug console variable that the HUD reads. */
|
|
void ToggleDebugOverlay();
|
|
|
|
/** Toggle-camera action (V). */
|
|
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Input")
|
|
TObjectPtr<UInputAction> ToggleCameraAction;
|
|
|
|
/** Degrees per second per unit of mouse input; defaults to Unreal's usual 45. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera")
|
|
float LookSensitivity = 45.0f;
|
|
|
|
/** Invert the pitch axis, for players who prefer it. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Camera")
|
|
bool bInvertLookY = false;
|
|
|
|
/** Walk speed in metres per second; converted to Unreal units on first use. */
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
|
|
float WalkSpeedMetresPerSecond = 4.0f;
|
|
};
|