增加缩放功能和运行截图
This commit is contained in:
@@ -39,3 +39,4 @@ Thumbs.db
|
||||
*.uid
|
||||
.godot/
|
||||
.import/
|
||||
.codegraph/
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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 |
Reference in New Issue
Block a user