From c0d9450d304dbb725a632ac428df18e8267a13b2 Mon Sep 17 00:00:00 2001 From: pixachux Date: Wed, 22 Jul 2026 18:55:07 +0200 Subject: [PATCH] Make top-down the default camera mode and bind camera toggle to C. Matches Fantasy Life style gameplay; first-person remains available as an optional mode. Co-authored-by: Cursor --- README.md | 4 +-- .../Private/VocationCharacter.cpp | 36 +++++++++++++++---- Source/VocationLife/Private/VocationHUD.cpp | 2 +- .../Private/VocationPlayerController.cpp | 4 +-- .../VocationLife/Public/VocationCharacter.h | 4 +-- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3b74a5d..1922524 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A life-simulation action RPG remake inspired by Fantasy Life, built in **Unreal ## Vision -- First-person gameplay (primary) with classic top-down camera toggle +- First-person gameplay with classic top-down camera as the default (toggle with C) - Mouse, keyboard, and gamepad support via Enhanced Input - Co-op multiplayer (listen server first, dedicated server hosting) - Optional hardware ray tracing and scalability presets @@ -31,7 +31,7 @@ A life-simulation action RPG remake inspired by Fantasy Life, built in **Unreal | Jump | Space | A / Cross | | Interact / Craft | E | X / Square | | Attack | LMB | RT | -| Toggle camera (FP / Top-Down) | V | Menu | +| Toggle camera (Top-Down / FP) | C | Menu | | Quick save | I | Y / Triangle | | Pause | Esc | Start | diff --git a/Source/VocationLife/Private/VocationCharacter.cpp b/Source/VocationLife/Private/VocationCharacter.cpp index dc3f7ca..dbd8cb4 100644 --- a/Source/VocationLife/Private/VocationCharacter.cpp +++ b/Source/VocationLife/Private/VocationCharacter.cpp @@ -32,6 +32,7 @@ AVocationCharacter::AVocationCharacter() FirstPersonCamera->SetupAttachment(GetCapsuleComponent()); FirstPersonCamera->SetRelativeLocation(FVector(0.f, 0.f, 64.f)); FirstPersonCamera->bUsePawnControlRotation = true; + FirstPersonCamera->SetActive(false); TopDownSpringArm = CreateDefaultSubobject(TEXT("TopDownSpringArm")); TopDownSpringArm->SetupAttachment(RootComponent); @@ -42,7 +43,7 @@ AVocationCharacter::AVocationCharacter() TopDownSpringArm->bInheritPitch = false; TopDownSpringArm->bInheritRoll = false; TopDownSpringArm->bInheritYaw = false; - TopDownSpringArm->SetActive(false); + TopDownSpringArm->SetActive(true); TopDownCamera = CreateDefaultSubobject(TEXT("TopDownCamera")); TopDownCamera->SetupAttachment(TopDownSpringArm, USpringArmComponent::SocketName); @@ -54,21 +55,25 @@ AVocationCharacter::AVocationCharacter() if (USkeletalMeshComponent* MeshComp = GetMesh()) { - MeshComp->SetOnlyOwnerSee(true); - MeshComp->SetupAttachment(FirstPersonCamera); - MeshComp->SetRelativeLocation(FVector(25.f, 0.f, -90.f)); + // Visible body for top-down default; FP mode reattaches in ApplyCameraModeVisuals. + MeshComp->SetOnlyOwnerSee(false); + MeshComp->SetOwnerNoSee(false); + MeshComp->SetupAttachment(GetCapsuleComponent()); + MeshComp->SetRelativeLocation(FVector(0.f, 0.f, -90.f)); + MeshComp->SetRelativeRotation(FRotator(0.f, -90.f, 0.f)); } if (UCharacterMovementComponent* Movement = GetCharacterMovement()) { - Movement->bOrientRotationToMovement = false; + Movement->bOrientRotationToMovement = true; Movement->RotationRate = FRotator(0.f, 540.f, 0.f); Movement->JumpZVelocity = 500.f; Movement->AirControl = 0.35f; Movement->MaxWalkSpeed = 500.f; } - bUseControllerRotationPitch = true; + // Top-down is the default camera mode (Fantasy Life style). + bUseControllerRotationPitch = false; bUseControllerRotationYaw = true; bUseControllerRotationRoll = false; } @@ -304,6 +309,25 @@ void AVocationCharacter::ApplyCameraModeVisuals() TopDownSpringArm->SetActive(!bFirstPerson); TopDownCamera->SetActive(!bFirstPerson); + if (USkeletalMeshComponent* MeshComp = GetMesh()) + { + if (bFirstPerson) + { + MeshComp->SetOnlyOwnerSee(true); + MeshComp->SetupAttachment(FirstPersonCamera); + MeshComp->SetRelativeLocation(FVector(25.f, 0.f, -90.f)); + MeshComp->SetRelativeRotation(FRotator::ZeroRotator); + } + else + { + MeshComp->SetOnlyOwnerSee(false); + MeshComp->SetOwnerNoSee(false); + MeshComp->SetupAttachment(GetCapsuleComponent()); + MeshComp->SetRelativeLocation(FVector(0.f, 0.f, -90.f)); + MeshComp->SetRelativeRotation(FRotator(0.f, -90.f, 0.f)); + } + } + bUseControllerRotationPitch = bFirstPerson; if (UCharacterMovementComponent* Movement = GetCharacterMovement()) { diff --git a/Source/VocationLife/Private/VocationHUD.cpp b/Source/VocationLife/Private/VocationHUD.cpp index bdbe03c..baee8f7 100644 --- a/Source/VocationLife/Private/VocationHUD.cpp +++ b/Source/VocationLife/Private/VocationHUD.cpp @@ -76,7 +76,7 @@ void AVocationHUD::DrawMainHUD() } else { - const FString Controls = TEXT("WASD Move | Mouse Look | V Camera | E Interact/Craft | LMB Attack | I Save | Esc Pause"); + const FString Controls = TEXT("WASD Move | Mouse Look | C Camera | E Interact/Craft | LMB Attack | I Save | Esc Pause"); Canvas->DrawColor = FColor(200, 200, 200); Canvas->DrawText(GEngine->GetSmallFont(), Controls, 40.f * Scale, Canvas->ClipY - 60.f * Scale, Scale, Scale); } diff --git a/Source/VocationLife/Private/VocationPlayerController.cpp b/Source/VocationLife/Private/VocationPlayerController.cpp index 11008c8..129f7c3 100644 --- a/Source/VocationLife/Private/VocationPlayerController.cpp +++ b/Source/VocationLife/Private/VocationPlayerController.cpp @@ -29,7 +29,7 @@ void AVocationPlayerController::BeginPlay() LocalPlayer->GetSubsystem()) { Subsystem->AddMappingContext(SharedMappingContext, SharedMappingPriority); - Subsystem->AddMappingContext(FirstPersonMappingContext, ModeMappingPriority); + Subsystem->AddMappingContext(TopDownMappingContext, ModeMappingPriority); } } @@ -175,7 +175,7 @@ void AVocationPlayerController::CreateRuntimeInputAssets() SharedMappingContext->MapKey(JumpAction, EKeys::SpaceBar); SharedMappingContext->MapKey(InteractAction, EKeys::E); SharedMappingContext->MapKey(AttackAction, EKeys::LeftMouseButton); - SharedMappingContext->MapKey(ToggleCameraAction, EKeys::V); + SharedMappingContext->MapKey(ToggleCameraAction, EKeys::C); SharedMappingContext->MapKey(InventoryAction, EKeys::I); SharedMappingContext->MapKey(PauseAction, EKeys::Escape); SharedMappingContext->MapKey(JumpAction, EKeys::Gamepad_FaceButton_Bottom); diff --git a/Source/VocationLife/Public/VocationCharacter.h b/Source/VocationLife/Public/VocationCharacter.h index 6d06a5c..8a028f9 100644 --- a/Source/VocationLife/Public/VocationCharacter.h +++ b/Source/VocationLife/Public/VocationCharacter.h @@ -110,10 +110,10 @@ protected: void UpdateInteractionPrompt(); UPROPERTY(ReplicatedUsing = OnRep_CameraMode, BlueprintReadOnly, Category = "VocationLife|Camera") - EVocationCameraMode CurrentCameraMode = EVocationCameraMode::FirstPerson; + EVocationCameraMode CurrentCameraMode = EVocationCameraMode::TopDown; UPROPERTY(ReplicatedUsing = OnRep_CameraMode) - EVocationCameraMode TargetCameraMode = EVocationCameraMode::FirstPerson; + EVocationCameraMode TargetCameraMode = EVocationCameraMode::TopDown; UPROPERTY() float CameraBlendAlpha = 1.f;