From 344e5e221f0c1a73532ede56ae81c8e58bb4b36b Mon Sep 17 00:00:00 2001 From: yuichipanda Date: Sun, 1 Nov 2026 19:18:44 +0900 Subject: [PATCH] Fix camera framing for large grids using corner projection Co-Authored-By: Claude Sonnet 5.5 --- Source/Tactica/Private/TacticaCameraPawn.cpp | 57 +++++++++++++++++--- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/Source/Tactica/Private/TacticaCameraPawn.cpp b/Source/Tactica/Private/TacticaCameraPawn.cpp index 31f810c..44c2187 100644 --- a/Source/Tactica/Private/TacticaCameraPawn.cpp +++ b/Source/Tactica/Private/TacticaCameraPawn.cpp @@ -1,6 +1,8 @@ #include "TacticaCameraPawn.h" #include "Camera/CameraComponent.h" #include "GridManager.h" +#include "Engine/GameViewportClient.h" +#include "Engine/World.h" #include "Kismet/GameplayStatics.h" DEFINE_LOG_CATEGORY_STATIC(LogTacticaCamera, Log, All); @@ -25,12 +27,53 @@ void ATacticaCameraPawn::BeginPlay() return; } - // グリッドの長辺の半分(余白つき)が画角に収まる距離を求める - const float HalfExtent = FMath::Max(Grid->GridSizeX, Grid->GridSizeY) * Grid->CellSize * 0.5f * MarginScale; - const float HalfFovRad = FMath::DegreesToRadians(Camera->FieldOfView * 0.5f); - const float Distance = HalfExtent / FMath::Tan(HalfFovRad); - const FRotator Rotation(Pitch, 0.0f, 0.0f); - const FVector Location = Grid->GetGridCenter() - Rotation.Vector() * Distance; - SetActorLocationAndRotation(Location, Rotation); + const FVector Center = Grid->GetGridCenter(); + + // 画面の縦横比(取れなければカメラの既定値) + float Aspect = Camera->AspectRatio; + if (const UWorld* World = GetWorld()) + { + if (const UGameViewportClient* Viewport = World->GetGameViewport()) + { + FVector2D Size; + Viewport->GetViewportSize(Size); + if (Size.X > 1.0f && Size.Y > 1.0f) + { + Aspect = Size.X / Size.Y; + } + } + } + + // 横方向・縦方向の画角の半分のtan(余白の分だけ狭めて使う) + const float TanH = FMath::Tan(FMath::DegreesToRadians(Camera->FieldOfView * 0.5f)) / MarginScale; + const float TanV = TanH / FMath::Max(Aspect, 0.1f); + + // グリッドの四隅が画面に収まる最小の距離を求める。 + // 斜めに見下ろすので、手前の辺は近く、奥の辺は遠い(深さが違う)ことを考慮する + const FRotationMatrix RotMatrix(Rotation); + const FVector ViewDir = RotMatrix.GetUnitAxis(EAxis::X); + const FVector Right = RotMatrix.GetUnitAxis(EAxis::Y); + const FVector Up = RotMatrix.GetUnitAxis(EAxis::Z); + + const float HalfX = Grid->GridSizeX * Grid->CellSize * 0.5f; + const float HalfY = Grid->GridSizeY * Grid->CellSize * 0.5f; + + float Distance = 0.0f; + for (int32 SignX = -1; SignX <= 1; SignX += 2) + { + for (int32 SignY = -1; SignY <= 1; SignY += 2) + { + const FVector Offset(SignX * HalfX, SignY * HalfY, 0.0f); + const float Depth = FVector::DotProduct(Offset, ViewDir); // 中心からの奥行きのずれ + const float Lateral = FMath::Abs(FVector::DotProduct(Offset, Right)); + const float Vertical = FMath::Abs(FVector::DotProduct(Offset, Up)); + + // 条件: Lateral <= (Distance + Depth) * TanH, Vertical <= (Distance + Depth) * TanV + Distance = FMath::Max(Distance, Lateral / TanH - Depth); + Distance = FMath::Max(Distance, Vertical / TanV - Depth); + } + } + + SetActorLocationAndRotation(Center - ViewDir * Distance, Rotation); }