增加缩放功能和运行截图

This commit is contained in:
2026-06-03 17:57:14 +08:00
parent ed284833fe
commit ed7bb908cb
10 changed files with 157 additions and 26 deletions
+1
View File
@@ -39,3 +39,4 @@ Thumbs.db
*.uid
.godot/
.import/
.codegraph/
+11
View File
@@ -60,8 +60,19 @@ target_link_libraries(mana_core PUBLIC PkgConfig::PUGIXML)
target_compile_options(mana_core PRIVATE -Wall -Wextra -Wpedantic)
add_executable(mana_pet_world
src/app/LogicalViewport.cpp
src/app/main.cpp
src/battle/BattleScene.cpp
)
target_link_libraries(mana_pet_world PRIVATE mana_core PkgConfig::RAYLIB)
target_compile_options(mana_pet_world PRIVATE -Wall -Wextra -Wpedantic)
enable_testing()
add_executable(logical_viewport_test
tests/app/LogicalViewportTest.cpp
src/app/LogicalViewport.cpp
)
target_include_directories(logical_viewport_test PRIVATE src/app)
target_compile_options(logical_viewport_test PRIVATE -Wall -Wextra -Wpedantic)
add_test(NAME logical_viewport_test COMMAND logical_viewport_test)
+42
View File
@@ -0,0 +1,42 @@
#include "LogicalViewport.h"
namespace mana::app {
LogicalViewport ComputeLogicalViewport(int windowWidth, int windowHeight)
{
const float safeWindowWidth = static_cast<float>(std::max(1, windowWidth));
const float safeWindowHeight = static_cast<float>(std::max(1, windowHeight));
const float scale = std::min(
safeWindowWidth / static_cast<float>(kLogicalScreenWidth),
safeWindowHeight / static_cast<float>(kLogicalScreenHeight));
const float width = static_cast<float>(kLogicalScreenWidth) * scale;
const float height = static_cast<float>(kLogicalScreenHeight) * scale;
return {
(safeWindowWidth - width) * 0.5f,
(safeWindowHeight - height) * 0.5f,
width,
height,
scale,
};
}
LogicalPoint WindowToLogicalPoint(float windowX, float windowY, const LogicalViewport& viewport)
{
const float safeScale = std::max(0.0001f, viewport.scale);
return {
(windowX - viewport.x) / safeScale,
(windowY - viewport.y) / safeScale,
};
}
WindowRect LogicalRectToWindowRect(LogicalRect rect, const LogicalViewport& viewport)
{
return {
viewport.x + rect.x * viewport.scale,
viewport.y + rect.y * viewport.scale,
rect.width * viewport.scale,
rect.height * viewport.scale,
};
}
} // namespace mana::app
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <algorithm>
namespace mana::app {
constexpr int kLogicalScreenWidth = 1280;
constexpr int kLogicalScreenHeight = 720;
constexpr int kMinimumWindowWidth = 640;
constexpr int kMinimumWindowHeight = 360;
struct LogicalViewport {
float x = 0.0f;
float y = 0.0f;
float width = static_cast<float>(kLogicalScreenWidth);
float height = static_cast<float>(kLogicalScreenHeight);
float scale = 1.0f;
};
struct LogicalPoint {
float x = 0.0f;
float y = 0.0f;
};
struct LogicalRect {
float x = 0.0f;
float y = 0.0f;
float width = 0.0f;
float height = 0.0f;
};
struct WindowRect {
float x = 0.0f;
float y = 0.0f;
float width = 0.0f;
float height = 0.0f;
};
LogicalViewport ComputeLogicalViewport(int windowWidth, int windowHeight);
LogicalPoint WindowToLogicalPoint(float windowX, float windowY, const LogicalViewport& viewport);
WindowRect LogicalRectToWindowRect(LogicalRect rect, const LogicalViewport& viewport);
} // namespace mana::app
+59 -22
View File
@@ -7,6 +7,7 @@
#include "InteractableVisual.h"
#include "InventoryUiModel.h"
#include "ItemIconCatalog.h"
#include "LogicalViewport.h"
#include "MapAtmosphere.h"
#include "MinimapAsset.h"
#include "MusicAssets.h"
@@ -50,6 +51,20 @@
namespace {
using mana::app::kLogicalScreenHeight;
using mana::app::kLogicalScreenWidth;
using mana::app::kMinimumWindowHeight;
using mana::app::kMinimumWindowWidth;
Camera2D LogicalUiCamera(const mana::app::LogicalViewport& viewport)
{
Camera2D camera{};
camera.offset = {viewport.x, viewport.y};
camera.target = {0.0f, 0.0f};
camera.zoom = viewport.scale;
return camera;
}
struct TextureEntry {
Texture2D texture{};
bool loaded = false;
@@ -2960,22 +2975,25 @@ void DrawTexturedProgressBar(Runtime& rt, Rectangle bounds, float ratio, Color t
}
}
void DrawMiniMap(Runtime& rt, Font font)
void DrawMiniMap(Runtime& rt, Font font, const mana::app::LogicalViewport& logicalViewport)
{
(void)font;
const Rectangle panel{8.0f, 8.0f, 160.0f, 96.0f};
const Rectangle viewport{panel.x + 5.0f, panel.y + 5.0f, panel.width - 10.0f, panel.height - 10.0f};
const Rectangle mapViewport{panel.x + 5.0f, panel.y + 5.0f, panel.width - 10.0f, panel.height - 10.0f};
DrawMinimapPanel(rt, panel);
const float mapWidth = static_cast<float>(std::max(1, rt.map.width * rt.map.tileWidth));
const float mapHeight = static_cast<float>(std::max(1, rt.map.height * rt.map.tileHeight));
const mana::app::WindowRect scissor = mana::app::LogicalRectToWindowRect(
{mapViewport.x, mapViewport.y, mapViewport.width, mapViewport.height},
logicalViewport);
BeginScissorMode(
static_cast<int>(viewport.x),
static_cast<int>(viewport.y),
static_cast<int>(viewport.width),
static_cast<int>(viewport.height));
static_cast<int>(std::floor(scissor.x)),
static_cast<int>(std::floor(scissor.y)),
static_cast<int>(std::ceil(scissor.width)),
static_cast<int>(std::ceil(scissor.height)));
if (!rt.minimapPath.empty() && std::filesystem::exists(rt.minimapPath)) {
Texture2D& minimap = LoadTextureCached(rt, rt.minimapPath);
@@ -2989,14 +3007,14 @@ void DrawMiniMap(Runtime& rt, Font font)
playerRatio.x * textureW - 5.0f,
playerRatio.y * textureH - 5.0f,
};
const float sourceW = std::min(viewport.width, textureW);
const float sourceH = std::min(viewport.height, textureH);
const float scrollX = std::clamp(minimapPlayerPos.x - viewport.width * 0.5f, 0.0f, std::max(0.0f, textureW - sourceW));
const float scrollY = std::clamp(minimapPlayerPos.y - viewport.height * 0.5f, 0.0f, std::max(0.0f, textureH - sourceH));
const float sourceW = std::min(mapViewport.width, textureW);
const float sourceH = std::min(mapViewport.height, textureH);
const float scrollX = std::clamp(minimapPlayerPos.x - mapViewport.width * 0.5f, 0.0f, std::max(0.0f, textureW - sourceW));
const float scrollY = std::clamp(minimapPlayerPos.y - mapViewport.height * 0.5f, 0.0f, std::max(0.0f, textureH - sourceH));
const Rectangle sourceRect{scrollX, scrollY, sourceW, sourceH};
const Rectangle mapRect{
viewport.x,
viewport.y,
mapViewport.x,
mapViewport.y,
sourceW,
sourceH,
};
@@ -3008,8 +3026,8 @@ void DrawMiniMap(Runtime& rt, Font font)
0.0f,
WHITE);
const Vector2 playerPoint{
viewport.x + minimapPlayerPos.x - scrollX + 5.0f,
viewport.y + minimapPlayerPos.y - scrollY + 5.0f,
mapViewport.x + minimapPlayerPos.x - scrollX + 5.0f,
mapViewport.y + minimapPlayerPos.y - scrollY + 5.0f,
};
if (const std::optional<Vector2> target = CurrentQuestTargetPosition(rt)) {
const Vector2 targetRatio{
@@ -3017,10 +3035,10 @@ void DrawMiniMap(Runtime& rt, Font font)
std::clamp(target->y / mapHeight, 0.0f, 1.0f),
};
const Vector2 targetPoint{
viewport.x + targetRatio.x * textureW - scrollX,
viewport.y + targetRatio.y * textureH - scrollY,
mapViewport.x + targetRatio.x * textureW - scrollX,
mapViewport.y + targetRatio.y * textureH - scrollY,
};
if (CheckCollisionPointRec(targetPoint, viewport)) {
if (CheckCollisionPointRec(targetPoint, mapViewport)) {
DrawCircleV(targetPoint, 6.0f, Color{139, 214, 146, 235});
DrawCircleLines(static_cast<int>(targetPoint.x), static_cast<int>(targetPoint.y), 10.0f, Color{255, 255, 221, 255});
DrawCircleLines(static_cast<int>(targetPoint.x), static_cast<int>(targetPoint.y), 15.0f, Color{139, 214, 146, 170});
@@ -3295,10 +3313,10 @@ void DrawDebugCoordinates(Runtime& rt, Font font)
DrawTextCn(font, CompactSlotLabel(warpLine, 58).c_str(), {panel.x + 14.0f, panel.y + 102.0f}, 14.0f, Color{205, 208, 190, 245});
}
void DrawUi(Runtime& rt, Font font)
void DrawUi(Runtime& rt, Font font, const mana::app::LogicalViewport& logicalViewport)
{
if (rt.minimapVisible) {
DrawMiniMap(rt, font);
DrawMiniMap(rt, font, logicalViewport);
}
const Rectangle tracker{846.0f, 18.0f, 416.0f, 86.0f};
DrawRectangleRounded(tracker, 0.05f, 6, Color{244, 231, 186, 222});
@@ -7024,7 +7042,9 @@ int main(int argc, char** argv)
PrewarmMapEntityState(rt, IndoorAliasMapName());
RefreshProgress(rt);
InitWindow(1280, 720, "玛纳宠物世界");
SetConfigFlags(FLAG_WINDOW_RESIZABLE);
InitWindow(kLogicalScreenWidth, kLogicalScreenHeight, "玛纳宠物世界");
SetWindowMinSize(kMinimumWindowWidth, kMinimumWindowHeight);
SetExitKey(0);
rt.graphicsReady = true;
InitAudioDevice();
@@ -7035,12 +7055,20 @@ int main(int argc, char** argv)
PrewarmRuntimeGraphics(rt);
Camera2D camera{};
camera.offset = {640.0f, 360.0f};
camera.offset = {static_cast<float>(kLogicalScreenWidth) * 0.5f, static_cast<float>(kLogicalScreenHeight) * 0.5f};
camera.zoom = 1.55f;
rt.observerCamera = rt.player;
rt.observerZoom = camera.zoom;
while (!WindowShouldClose()) {
const mana::app::LogicalViewport viewport = mana::app::ComputeLogicalViewport(GetScreenWidth(), GetScreenHeight());
SetMouseOffset(
static_cast<int>(std::round(-viewport.x)),
static_cast<int>(std::round(-viewport.y)));
SetMouseScale(
static_cast<float>(kLogicalScreenWidth) / std::max(1.0f, viewport.width),
static_cast<float>(kLogicalScreenHeight) / std::max(1.0f, viewport.height));
const Camera2D uiCamera = LogicalUiCamera(viewport);
const float dt = GetFrameTime();
if (rt.currentMusicLoaded) {
UpdateMusicStream(rt.currentMusic);
@@ -7088,17 +7116,24 @@ int main(int argc, char** argv)
ProcessTexturePrewarmQueue(rt, 2, 0.0015);
camera.target = rt.mode == Mode::Observer ? rt.observerCamera : rt.player;
camera.offset = {static_cast<float>(GetScreenWidth()) * 0.5f, static_cast<float>(GetScreenHeight()) * 0.5f};
camera.zoom = rt.mode == Mode::Observer ? rt.observerZoom : 1.55f;
BeginDrawing();
ClearBackground(BLACK);
if (rt.mode == Mode::TitleMenu) {
BeginMode2D(uiCamera);
DrawTitleMenu(rt, font);
EndMode2D();
} else if (rt.mode == Mode::TitleHelp) {
BeginMode2D(uiCamera);
DrawTitleHelp(rt, font);
EndMode2D();
} else if (rt.mode == Mode::Battle) {
BeginMode2D(uiCamera);
DrawBattle(rt, font);
EndMode2D();
} else {
BeginMode2D(camera);
struct VisibleMapDraw {
@@ -7269,7 +7304,8 @@ int main(int argc, char** argv)
EndMode2D();
DrawMapAtmosphere(rt);
DrawUi(rt, font);
BeginMode2D(uiCamera);
DrawUi(rt, font, viewport);
if (rt.nearbyWarp && rt.mode == Mode::Explore) {
DrawInteractionPrompt(rt, font, "进入", rt.warpPrompt);
} else if (rt.nearbyNpc && rt.mode == Mode::Explore) {
@@ -7301,6 +7337,7 @@ int main(int argc, char** argv)
DrawPanel(rt, 470, 610, 340, 54);
DrawTextCn(font, "观察模式", {590, 626}, 22.0f, RAYWHITE);
}
EndMode2D();
}
DrawWakeBlinkOverlay(rt);
+1 -4
View File
@@ -648,10 +648,7 @@ BattleUiCommand ReadBattleUiCommand(BattleMenuMode& mode, int& selectedIndex, in
};
const auto logicalMousePosition = []() {
const Vector2 mouse = GetMousePosition();
const float screenW = static_cast<float>(std::max(1, GetScreenWidth()));
const float screenH = static_cast<float>(std::max(1, GetScreenHeight()));
return Vector2{mouse.x * 1280.0f / screenW, mouse.y * 720.0f / screenH};
return GetMousePosition();
};
const auto panelCellAt = [](Rectangle panel, Vector2 point) {
Binary file not shown.

After

Width:  |  Height:  |  Size: 648 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB