From 62b0f6dafd533d59de9de2f3215de74dcb4d72e9 Mon Sep 17 00:00:00 2001 From: Lenheart <947330670@qq.com> Date: Mon, 6 Apr 2026 23:17:26 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E6=B8=B2=E6=9F=93):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E8=99=9A=E6=8B=9F=E5=88=86=E8=BE=A8=E7=8E=87=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=B9=B6=E9=87=8D=E6=9E=84=E7=9B=B8=E6=9C=BA=E7=B3=BB=E7=BB=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现虚拟分辨率渲染系统,支持不同缩放模式 重构相机控制器以使用虚拟分辨率计算可见区域 移除硬编码的屏幕尺寸,改为动态获取 添加分辨率状态管理及相关工具函数 更新窗口和渲染器以处理分辨率变化 --- .../include/frostbite2D/core/application.h | 21 ++ Frostbite2D/include/frostbite2D/core/window.h | 214 ++---------- .../include/frostbite2D/graphics/camera.h | 2 + .../frostbite2D/graphics/render_resolution.h | 43 +++ .../include/frostbite2D/graphics/renderer.h | 71 ++-- .../src/frostbite2D/core/application.cpp | 31 +- Frostbite2D/src/frostbite2D/core/window.cpp | 188 +++++++--- .../src/frostbite2D/graphics/camera.cpp | 13 +- .../src/frostbite2D/graphics/renderer.cpp | 324 +++++++++++++++--- .../src/frostbite2D/scene/ui_scene.cpp | 3 + Game/include/camera/GameCameraController.h | 2 +- Game/include/map/GameMap.h | 4 +- Game/src/bootstrap/main.cpp | 18 +- Game/src/camera/GameCameraController.cpp | 8 +- Game/src/scene/GameMapTestScene.cpp | 9 +- Game/src/world/GameTown.cpp | 1 - 16 files changed, 631 insertions(+), 321 deletions(-) create mode 100644 Frostbite2D/include/frostbite2D/graphics/render_resolution.h diff --git a/Frostbite2D/include/frostbite2D/core/application.h b/Frostbite2D/include/frostbite2D/core/application.h index 708443a..84afb43 100644 --- a/Frostbite2D/include/frostbite2D/core/application.h +++ b/Frostbite2D/include/frostbite2D/core/application.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -37,6 +38,26 @@ struct AppConfig { */ PlatformType targetPlatform = PlatformType::Auto; + /** + * @brief 是否启用虚拟分辨率 + */ + bool useVirtualResolution = false; + + /** + * @brief 虚拟分辨率宽度 + */ + int virtualWidth = 0; + + /** + * @brief 虚拟分辨率高度 + */ + int virtualHeight = 0; + + /** + * @brief 虚拟分辨率缩放模式 + */ + ResolutionScaleMode resolutionMode = ResolutionScaleMode::Fit; + /** * @brief 创建默认配置 * @return 默认的应用配置实例 diff --git a/Frostbite2D/include/frostbite2D/core/window.h b/Frostbite2D/include/frostbite2D/core/window.h index 2d119f4..7c4b058 100644 --- a/Frostbite2D/include/frostbite2D/core/window.h +++ b/Frostbite2D/include/frostbite2D/core/window.h @@ -8,30 +8,22 @@ namespace frostbite2D { -/** - * \~chinese - * @brief 鼠标指针类型 - */ enum class CursorType { - Arrow, ///< 指针 - TextInput, ///< 文本 - Hand, ///< 手 - SizeAll, ///< 指向四个方向的箭头 - SizeWE, ///< 指向左右方向的箭头 - SizeNS, ///< 指向上下方向的箭头 - SizeNESW, ///< 指向左下到右上方向的箭头 - SizeNWSE, ///< 指向左上到右下方向的箭头 - No, ///< 禁止 + Arrow, + TextInput, + Hand, + SizeAll, + SizeWE, + SizeNS, + SizeNESW, + SizeNWSE, + No, }; -/** - * \~chinese - * @brief 分辨率 - */ struct Resolution { - uint32_t width = 0; ///< 分辨率宽度 - uint32_t height = 0; ///< 分辨率高度 - uint32_t refresh_rate = 0; ///< 刷新率 + uint32_t width = 0; + uint32_t height = 0; + uint32_t refresh_rate = 0; Resolution() = default; @@ -39,41 +31,33 @@ struct Resolution { : width(width), height(height), refresh_rate(refresh_rate) {} }; -/** - * \~chinese - * @brief 图标 - */ struct Icon { Icon() = default; Icon(std::string file_path) : file_path(file_path) {} - std::string file_path; ///< 文件路径 + std::string file_path; #if defined(_WIN32) - uint32_t resource_id = 0; ///< 资源ID,仅在windows上生效 + uint32_t resource_id = 0; Icon(uint32_t resource_id) : resource_id(resource_id) {} #endif }; -/** - * \~chinese - * @brief 窗口设置 - */ struct WindowConfig { - uint32_t width = 640; ///< 窗口宽度 - uint32_t height = 480; ///< 窗口高度 - std::string title = "frostbite2D Game"; ///< 窗口标题 - Icon icon; ///< 窗口图标 - bool resizable = false; ///< 窗口大小可调整 - bool fullscreen = false; ///< 窗口全屏 - bool borderless = false; ///< 无边框窗口 - bool decorated = true; ///< 窗口装饰 - int multisamples = 0; ///< 多重采样数 - bool centered = true; ///< 窗口是否居中 - bool vsync = true; ///< 是否启用垂直同步 - bool showCursor = true; ///< 是否显示光标 + uint32_t width = 640; + uint32_t height = 480; + std::string title = "frostbite2D Game"; + Icon icon; + bool resizable = false; + bool fullscreen = false; + bool borderless = false; + bool decorated = true; + int multisamples = 0; + bool centered = true; + bool vsync = true; + bool showCursor = true; }; class Window { @@ -81,179 +65,55 @@ public: Window() = default; ~Window() = default; - /** - * @brief 创建窗口 - * @param cfg 窗口配置 - * @return 创建是否成功 - */ - virtual bool create(const WindowConfig &cfg); - - /** - * @brief 销毁窗口 - */ + virtual bool create(const WindowConfig& cfg); virtual void destroy(); - - /** - * @brief 轮询事件 - */ virtual void poll(); - - /** - * @brief 交换缓冲区 - */ virtual void swap(); - - /** - * @brief 设置窗口关闭标志 - */ virtual void close(); - - /** - * @brief 设置窗口标题 - */ - virtual void setTitle(const std::string &title); - - /** - * @brief 设置窗口大小 - */ + virtual void setTitle(const std::string& title); virtual void setSize(int w, int h); - - /** - * @brief 设置窗口位置 - */ virtual void setPos(int x, int y); - - /** - * @brief 设置全屏模式 - */ virtual void setFullscreen(bool fs); - - /** - * @brief 设置垂直同步 - */ virtual void setVSync(bool vsync); - - /** - * @brief 设置窗口可见性 - */ virtual void setVisible(bool visible); - /** - * @brief 获取窗口宽度 - */ virtual int width() const; - - /** - * @brief 获取窗口高度 - */ virtual int height() const; - - /** - * @brief 获取窗口大小 - */ + virtual int drawableWidth() const; + virtual int drawableHeight() const; virtual Size size() const; - - /** - * @brief 获取窗口位置 - */ virtual Vec2 pos() const; - - /** - * @brief 是否全屏 - */ virtual bool fullscreen() const; - - /** - * @brief 是否启用垂直同步 - */ virtual bool vsync() const; - - /** - * @brief 窗口是否获得焦点 - */ virtual bool focused() const; - - /** - * @brief 窗口是否最小化 - */ virtual bool minimized() const; - - /** - * @brief 获取内容缩放X - */ virtual float scaleX() const; - - /** - * @brief 获取内容缩放Y - */ virtual float scaleY() const; - - /** - * @brief 设置光标形状 - */ + virtual bool refreshMetrics(bool emitResize = false); virtual void setCursor(CursorType cursor); - - /** - * @brief 显示/隐藏光标 - */ virtual void showCursor(bool show); - - /** - * @brief 锁定/解锁光标 - */ virtual void lockCursor(bool lock); - /** - * @brief 窗口大小改变回调 - */ using ResizeCb = std::function; - - /** - * @brief 窗口关闭回调 - */ using CloseCb = std::function; - - /** - * @brief 窗口焦点改变回调 - */ using FocusCb = std::function; - /** - * @brief 设置大小改变回调 - */ virtual void onResize(ResizeCb cb); - - /** - * @brief 设置关闭回调 - */ virtual void onClose(CloseCb cb); - - /** - * @brief 设置焦点改变回调 - */ virtual void onFocus(FocusCb cb); + virtual void* native() const; - /** - * @brief 获取原生窗口句柄 - */ - virtual void *native() const; - - /** - * @brief 获取 SDL 窗口句柄 - */ - SDL_Window *sdlWindow() const { return sdlWindow_; } - - /** - * @brief 获取 OpenGL 上下文 - */ + SDL_Window* sdlWindow() const { return sdlWindow_; } SDL_GLContext glContext() const { return glContext_; } private: - SDL_Window *sdlWindow_ = nullptr; + SDL_Window* sdlWindow_ = nullptr; SDL_GLContext glContext_ = nullptr; int width_ = 1280; int height_ = 720; + int drawableWidth_ = 1280; + int drawableHeight_ = 720; bool fullscreen_ = false; bool vsync_ = true; bool focused_ = true; @@ -269,4 +129,4 @@ private: FocusCb focusCb_; }; -} // namespace frostbite2D \ No newline at end of file +} // namespace frostbite2D diff --git a/Frostbite2D/include/frostbite2D/graphics/camera.h b/Frostbite2D/include/frostbite2D/graphics/camera.h index 15a1b7e..8f0a7fd 100644 --- a/Frostbite2D/include/frostbite2D/graphics/camera.h +++ b/Frostbite2D/include/frostbite2D/graphics/camera.h @@ -17,6 +17,8 @@ public: float getZoom() const { return zoom_; } int getViewportWidth() const { return viewportWidth_; } int getViewportHeight() const { return viewportHeight_; } + float getVisibleWidth() const; + float getVisibleHeight() const; void lookAt(const Vec2& target); void move(const Vec2& delta); diff --git a/Frostbite2D/include/frostbite2D/graphics/render_resolution.h b/Frostbite2D/include/frostbite2D/graphics/render_resolution.h new file mode 100644 index 0000000..75055fd --- /dev/null +++ b/Frostbite2D/include/frostbite2D/graphics/render_resolution.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +namespace frostbite2D { + +enum class ResolutionScaleMode { + Disabled, + Fit, + FitHeight, +}; + +struct RenderResolutionState { + int windowWidth = 1280; + int windowHeight = 720; + + int drawableWidth = 1280; + int drawableHeight = 720; + + int windowViewportX = 0; + int windowViewportY = 0; + int windowViewportWidth = 1280; + int windowViewportHeight = 720; + + int viewportX = 0; + int viewportY = 0; + int viewportWidth = 1280; + int viewportHeight = 720; + + float contentScaleX = 1.0f; + float contentScaleY = 1.0f; + float scaleX = 1.0f; + float scaleY = 1.0f; + + Rect getWindowViewportRect() const { + return Rect(static_cast(windowViewportX), + static_cast(windowViewportY), + static_cast(windowViewportWidth), + static_cast(windowViewportHeight)); + } +}; + +} // namespace frostbite2D diff --git a/Frostbite2D/include/frostbite2D/graphics/renderer.h b/Frostbite2D/include/frostbite2D/graphics/renderer.h index 75f40ba..a13e6b7 100644 --- a/Frostbite2D/include/frostbite2D/graphics/renderer.h +++ b/Frostbite2D/include/frostbite2D/graphics/renderer.h @@ -1,11 +1,12 @@ #pragma once -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include #include namespace frostbite2D { @@ -13,55 +14,71 @@ namespace frostbite2D { class Renderer { public: static Renderer& get(); - + bool init(); void shutdown(); - + void beginFrame(); void endFrame(); void flush(); - + void setViewport(int x, int y, int width, int height); + void setWindowSize(int width, int height, float contentScaleX = 1.0f, + float contentScaleY = 1.0f); + void setVirtualResolutionEnabled(bool enabled); + void setVirtualResolution(int width, int height); + void setResolutionScaleMode(ResolutionScaleMode mode); void setClearColor(float r, float g, float b, float a = 1.0f); void setClearColor(const Color& color); void clear(uint32_t flags); - + void setCamera(Camera* camera); Camera* getCamera() { return camera_; } - - void drawQuad(const Vec2& pos, const Size& size, float cr = 1.0f, float cg = 1.0f, - float cb = 1.0f, float ca = 1.0f); + int getVirtualWidth() const; + int getVirtualHeight() const; + Rect getViewportRect() const; + const RenderResolutionState& getResolutionState() const { + return resolutionState_; + } + Vec2 screenToVirtual(const Vec2& screenPos) const; + Vec2 virtualToScreen(const Vec2& virtualPos) const; + + void drawQuad(const Vec2& pos, const Size& size, float cr = 1.0f, + float cg = 1.0f, float cb = 1.0f, float ca = 1.0f); void drawQuad(const Vec2& pos, const Size& size, Ptr texture); void drawQuad(const Rect& rect, const Color& color); - + void drawSprite(const Vec2& pos, const Size& size, Ptr texture); - void drawSprite(const Vec2& pos, const Rect& srcRect, const Vec2& texSize, - Ptr texture, const Color& color = Color(1, 1, 1, 1)); + void drawSprite(const Vec2& pos, const Rect& srcRect, const Vec2& texSize, + Ptr texture, + const Color& color = Color(1, 1, 1, 1)); void setupBlendMode(BlendMode mode); - + ShaderManager& getShaderManager() { return shaderManager_; } Batch& getBatch() { return batch_; } - + private: Renderer(); - // ~Renderer() 在 shutdown() 中手动调用销毁 - + void updateUniforms(); - + void recalculateResolutionState(); + void syncCameraViewport(); + ShaderManager shaderManager_; Batch batch_; Camera* camera_ = nullptr; - + uint32_t clearColor_[4] = {0, 0, 0, 255}; - int viewportX_ = 0; - int viewportY_ = 0; - int viewportWidth_ = 1280; - int viewportHeight_ = 720; - + bool useVirtualResolution_ = false; + int virtualWidth_ = 1280; + int virtualHeight_ = 720; + ResolutionScaleMode resolutionMode_ = ResolutionScaleMode::Fit; + RenderResolutionState resolutionState_; + bool initialized_ = false; - + Renderer(const Renderer&) = delete; Renderer& operator=(const Renderer&) = delete; }; -} +} // namespace frostbite2D diff --git a/Frostbite2D/src/frostbite2D/core/application.cpp b/Frostbite2D/src/frostbite2D/core/application.cpp index 423ed1c..ec9b0b2 100644 --- a/Frostbite2D/src/frostbite2D/core/application.cpp +++ b/Frostbite2D/src/frostbite2D/core/application.cpp @@ -180,9 +180,13 @@ bool Application::initCoreModules() { } window_->onResize([this](int width, int height) { - renderer_->setViewport(0, 0, width, height); - camera_->setViewport(width, height); - SDL_Log("Window resized to %dx%d", width, height); + if (!renderer_ || !window_) { + return; + } + + renderer_->setWindowSize(width, height, window_->scaleX(), window_->scaleY()); + SDL_Log("Window resized to %dx%d (drawable %dx%d)", width, height, + window_->drawableWidth(), window_->drawableHeight()); }); // 初始化渲染器 @@ -197,13 +201,19 @@ bool Application::initCoreModules() { // 设置窗口清除颜色和视口 renderer_->setClearColor(0.0f, 0.0f, 0.0f); - renderer_->setViewport(0, 0, config_.windowConfig.width, config_.windowConfig.height); + renderer_->setVirtualResolutionEnabled(config_.useVirtualResolution); + renderer_->setResolutionScaleMode(config_.resolutionMode); + if (config_.virtualWidth > 0 && config_.virtualHeight > 0) { + renderer_->setVirtualResolution(config_.virtualWidth, config_.virtualHeight); + } + renderer_->setWindowSize(window_->width(), window_->height(), window_->scaleX(), + window_->scaleY()); // 创建并设置相机 { ScopedStartupTrace stageTrace("Camera setup"); camera_ = new Camera(); - camera_->setViewport(config_.windowConfig.width, config_.windowConfig.height); + camera_->setViewport(renderer_->getVirtualWidth(), renderer_->getVirtualHeight()); camera_->setFlipY(true); // 启用 Y 轴翻转,(0,0) 在左上角 renderer_->setCamera(camera_); } @@ -282,6 +292,17 @@ void Application::mainLoop() { break; } + if (sdlEvent.type == SDL_WINDOWEVENT && window_) { + switch (sdlEvent.window.event) { + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_SIZE_CHANGED: + window_->refreshMetrics(true); + break; + default: + break; + } + } + auto event = convertSDLEvent(sdlEvent); if (event) { dispatchEvent(*event); diff --git a/Frostbite2D/src/frostbite2D/core/window.cpp b/Frostbite2D/src/frostbite2D/core/window.cpp index 1bfc9e6..06d777a 100644 --- a/Frostbite2D/src/frostbite2D/core/window.cpp +++ b/Frostbite2D/src/frostbite2D/core/window.cpp @@ -4,13 +4,11 @@ #include #include - namespace frostbite2D { -bool Window::create(const WindowConfig &cfg) { - +bool Window::create(const WindowConfig& cfg) { Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; - + #ifndef __SWITCH__ if (cfg.fullscreen) { flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; @@ -28,7 +26,6 @@ bool Window::create(const WindowConfig &cfg) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); @@ -38,17 +35,11 @@ bool Window::create(const WindowConfig &cfg) { SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, cfg.multisamples); } - int x = SDL_WINDOWPOS_CENTERED; - int y = SDL_WINDOWPOS_CENTERED; - if (!cfg.centered) { - x = SDL_WINDOWPOS_UNDEFINED; - y = SDL_WINDOWPOS_UNDEFINED; - } - - // 创建窗口 - sdlWindow_ = - SDL_CreateWindow(cfg.title.c_str(), x, y, cfg.width, cfg.height, flags); + int x = cfg.centered ? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED; + int y = cfg.centered ? SDL_WINDOWPOS_CENTERED : SDL_WINDOWPOS_UNDEFINED; + sdlWindow_ = SDL_CreateWindow(cfg.title.c_str(), x, y, cfg.width, cfg.height, + flags); if (!sdlWindow_) { SDL_Log("Failed to create window: %s", SDL_GetError()); return false; @@ -72,23 +63,12 @@ bool Window::create(const WindowConfig &cfg) { } SDL_GL_SetSwapInterval(cfg.vsync ? 1 : 0); + refreshMetrics(false); - // 获取实际的可绘制大小(考虑高 DPI 和 Switch 等平台) - int drawableWidth, drawableHeight; - SDL_GL_GetDrawableSize(sdlWindow_, &drawableWidth, &drawableHeight); - width_ = drawableWidth; - height_ = drawableHeight; - - // 计算缩放比例 - int windowWidth, windowHeight; - SDL_GetWindowSize(sdlWindow_, &windowWidth, &windowHeight); - if (windowWidth > 0 && windowHeight > 0) { - scaleX_ = static_cast(drawableWidth) / static_cast(windowWidth); - scaleY_ = static_cast(drawableHeight) / static_cast(windowHeight); - } - fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; vsync_ = cfg.vsync; + cursorVisible_ = cfg.showCursor; + showCursor(cfg.showCursor); #ifndef __SWITCH__ if (!cfg.icon.file_path.empty()) { @@ -113,9 +93,11 @@ bool Window::create(const WindowConfig &cfg) { } void Window::destroy() { - if (sdlWindow_) { + if (glContext_) { SDL_GL_DeleteContext(glContext_); glContext_ = nullptr; + } + if (sdlWindow_) { SDL_DestroyWindow(sdlWindow_); sdlWindow_ = nullptr; } @@ -129,16 +111,32 @@ void Window::swap() { } } -void Window::close() { shouldClose_ = true; } +void Window::close() { + shouldClose_ = true; + if (closeCb_) { + closeCb_(); + } +} -void Window::setTitle(const std::string &title) {} +void Window::setTitle(const std::string& title) { + if (sdlWindow_) { + SDL_SetWindowTitle(sdlWindow_, title.c_str()); + } +} void Window::setSize(int w, int h) { if (sdlWindow_) { SDL_SetWindowSize(sdlWindow_, w, h); + refreshMetrics(true); + return; } + width_ = w; height_ = h; + drawableWidth_ = w; + drawableHeight_ = h; + scaleX_ = 1.0f; + scaleY_ = 1.0f; if (resizeCb_) { resizeCb_(w, h); } @@ -150,23 +148,54 @@ void Window::setPos(int x, int y) { } } -void Window::setFullscreen(bool fs) { fullscreen_ = fs; } +void Window::setFullscreen(bool fs) { + fullscreen_ = fs; + if (!sdlWindow_) { + return; + } -void Window::setVSync(bool vsync) { vsync_ = vsync; } +#ifndef __SWITCH__ + Uint32 flags = fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0; + SDL_SetWindowFullscreen(sdlWindow_, flags); + refreshMetrics(true); +#endif +} -void Window::setVisible(bool visible) {} +void Window::setVSync(bool vsync) { + vsync_ = vsync; + if (glContext_) { + SDL_GL_SetSwapInterval(vsync ? 1 : 0); + } +} + +void Window::setVisible(bool visible) { + if (!sdlWindow_) { + return; + } + + if (visible) { + SDL_ShowWindow(sdlWindow_); + } else { + SDL_HideWindow(sdlWindow_); + } +} int Window::width() const { return width_; } int Window::height() const { return height_; } +int Window::drawableWidth() const { return drawableWidth_; } + +int Window::drawableHeight() const { return drawableHeight_; } + Size Window::size() const { return Size{static_cast(width_), static_cast(height_)}; } Vec2 Window::pos() const { if (sdlWindow_) { - int x, y; + int x = 0; + int y = 0; SDL_GetWindowPosition(sdlWindow_, &x, &y); return Vec2{static_cast(x), static_cast(y)}; } @@ -185,11 +214,90 @@ float Window::scaleX() const { return scaleX_; } float Window::scaleY() const { return scaleY_; } -void Window::setCursor(CursorType cursor) {} +bool Window::refreshMetrics(bool emitResize) { + if (!sdlWindow_) { + return false; + } -void Window::showCursor(bool show) { cursorVisible_ = show; } + int prevWidth = width_; + int prevHeight = height_; + int prevDrawableWidth = drawableWidth_; + int prevDrawableHeight = drawableHeight_; -void Window::lockCursor(bool lock) { cursorLocked_ = lock; } + SDL_GetWindowSize(sdlWindow_, &width_, &height_); + SDL_GL_GetDrawableSize(sdlWindow_, &drawableWidth_, &drawableHeight_); + + if (width_ > 0 && height_ > 0) { + scaleX_ = static_cast(drawableWidth_) / static_cast(width_); + scaleY_ = static_cast(drawableHeight_) / static_cast(height_); + } else { + scaleX_ = 1.0f; + scaleY_ = 1.0f; + } + + Uint32 windowFlags = SDL_GetWindowFlags(sdlWindow_); + focused_ = (windowFlags & SDL_WINDOW_INPUT_FOCUS) != 0; + minimized_ = (windowFlags & SDL_WINDOW_MINIMIZED) != 0; + fullscreen_ = (windowFlags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0 || + (windowFlags & SDL_WINDOW_FULLSCREEN) != 0; + + bool changed = prevWidth != width_ || prevHeight != height_ || + prevDrawableWidth != drawableWidth_ || + prevDrawableHeight != drawableHeight_; + if (emitResize && changed && resizeCb_) { + resizeCb_(width_, height_); + } + + return true; +} + +void Window::setCursor(CursorType cursor) { + SDL_SystemCursor systemCursor = SDL_SYSTEM_CURSOR_ARROW; + switch (cursor) { + case CursorType::Arrow: + systemCursor = SDL_SYSTEM_CURSOR_ARROW; + break; + case CursorType::TextInput: + systemCursor = SDL_SYSTEM_CURSOR_IBEAM; + break; + case CursorType::Hand: + systemCursor = SDL_SYSTEM_CURSOR_HAND; + break; + case CursorType::SizeAll: + systemCursor = SDL_SYSTEM_CURSOR_SIZEALL; + break; + case CursorType::SizeWE: + systemCursor = SDL_SYSTEM_CURSOR_SIZEWE; + break; + case CursorType::SizeNS: + systemCursor = SDL_SYSTEM_CURSOR_SIZENS; + break; + case CursorType::SizeNESW: + systemCursor = SDL_SYSTEM_CURSOR_SIZENESW; + break; + case CursorType::SizeNWSE: + systemCursor = SDL_SYSTEM_CURSOR_SIZENWSE; + break; + case CursorType::No: + systemCursor = SDL_SYSTEM_CURSOR_ARROW; + break; + } + + SDL_Cursor* sdlCursor = SDL_CreateSystemCursor(systemCursor); + if (sdlCursor) { + SDL_SetCursor(sdlCursor); + } +} + +void Window::showCursor(bool show) { + cursorVisible_ = show; + SDL_ShowCursor(show ? SDL_ENABLE : SDL_DISABLE); +} + +void Window::lockCursor(bool lock) { + cursorLocked_ = lock; + SDL_SetRelativeMouseMode(lock ? SDL_TRUE : SDL_FALSE); +} void Window::onResize(ResizeCb cb) { resizeCb_ = cb; } @@ -197,6 +305,6 @@ void Window::onClose(CloseCb cb) { closeCb_ = cb; } void Window::onFocus(FocusCb cb) { focusCb_ = cb; } -void *Window::native() const { return nullptr; } +void* Window::native() const { return nullptr; } } // namespace frostbite2D diff --git a/Frostbite2D/src/frostbite2D/graphics/camera.cpp b/Frostbite2D/src/frostbite2D/graphics/camera.cpp index 3b2c454..309e535 100644 --- a/Frostbite2D/src/frostbite2D/graphics/camera.cpp +++ b/Frostbite2D/src/frostbite2D/graphics/camera.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace frostbite2D { @@ -14,6 +15,16 @@ void Camera::setViewport(int width, int height) { viewportHeight_ = height; } +float Camera::getVisibleWidth() const { + float safeZoom = std::max(zoom_, 0.01f); + return static_cast(viewportWidth_) / safeZoom; +} + +float Camera::getVisibleHeight() const { + float safeZoom = std::max(zoom_, 0.01f); + return static_cast(viewportHeight_) / safeZoom; +} + void Camera::lookAt(const Vec2 &target) { position_ = target; } void Camera::move(const Vec2 &delta) { position_ = position_ + delta; } @@ -54,4 +65,4 @@ glm::mat4 Camera::getProjectionMatrix() const { return glm::ortho(left, right, bottom, top, -1.0f, 1.0f); } -} // namespace frostbite2D \ No newline at end of file +} // namespace frostbite2D diff --git a/Frostbite2D/src/frostbite2D/graphics/renderer.cpp b/Frostbite2D/src/frostbite2D/graphics/renderer.cpp index 93bb23e..ee43336 100644 --- a/Frostbite2D/src/frostbite2D/graphics/renderer.cpp +++ b/Frostbite2D/src/frostbite2D/graphics/renderer.cpp @@ -1,11 +1,23 @@ #include "SDL_log.h" #include +#include +#include #include #include #include namespace frostbite2D { +namespace { + +constexpr float kMinContentScale = 0.01f; + +int roundToInt(float value) { + return static_cast(std::lround(value)); +} + +} // namespace + Renderer& Renderer::get() { static Renderer instance; return instance; @@ -13,29 +25,29 @@ Renderer& Renderer::get() { Renderer::Renderer() = default; -// 移除析构函数中的自动销毁,改为在 Application::shutdown() 中手动调用 - bool Renderer::init() { if (initialized_) { return true; } - + if (!batch_.init()) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize batch system"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to initialize batch system"); return false; } - //初始化着色器管理器 if (!shaderManager_.init("assets/shaders")) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize shader manager"); + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, + "Failed to initialize shader manager"); return false; } - + glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - + SDL_Log("Renderer initialized"); initialized_ = true; + recalculateResolutionState(); return true; } @@ -46,11 +58,12 @@ void Renderer::shutdown() { } void Renderer::beginFrame() { - glViewport(viewportX_, viewportY_, viewportWidth_, viewportHeight_); - glClearColor(clearColor_[0] / 255.0f, clearColor_[1] / 255.0f, - clearColor_[2] / 255.0f, clearColor_[3] / 255.0f); + glViewport(resolutionState_.viewportX, resolutionState_.viewportY, + resolutionState_.viewportWidth, resolutionState_.viewportHeight); + glClearColor(clearColor_[0] / 255.0f, clearColor_[1] / 255.0f, + clearColor_[2] / 255.0f, clearColor_[3] / 255.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + updateUniforms(); batch_.begin(); } @@ -64,14 +77,66 @@ void Renderer::flush() { } void Renderer::setViewport(int x, int y, int width, int height) { - viewportX_ = x; - viewportY_ = y; - viewportWidth_ = width; - viewportHeight_ = height; - - if (camera_) { - camera_->setViewport(width, height); - } + resolutionState_.viewportX = x; + resolutionState_.viewportY = y; + resolutionState_.viewportWidth = std::max(width, 1); + resolutionState_.viewportHeight = std::max(height, 1); + + float safeScaleX = std::max(resolutionState_.contentScaleX, kMinContentScale); + float safeScaleY = std::max(resolutionState_.contentScaleY, kMinContentScale); + + resolutionState_.windowViewportX = roundToInt( + static_cast(resolutionState_.viewportX) / safeScaleX); + resolutionState_.windowViewportY = roundToInt( + static_cast(resolutionState_.viewportY) / safeScaleY); + resolutionState_.windowViewportWidth = roundToInt( + static_cast(resolutionState_.viewportWidth) / safeScaleX); + resolutionState_.windowViewportHeight = roundToInt( + static_cast(resolutionState_.viewportHeight) / safeScaleY); + + int logicalWidth = std::max(getVirtualWidth(), 1); + int logicalHeight = std::max(getVirtualHeight(), 1); + resolutionState_.scaleX = + static_cast(resolutionState_.windowViewportWidth) / + static_cast(logicalWidth); + resolutionState_.scaleY = + static_cast(resolutionState_.windowViewportHeight) / + static_cast(logicalHeight); + + syncCameraViewport(); +} + +void Renderer::setWindowSize(int width, int height, float contentScaleX, + float contentScaleY) { + resolutionState_.windowWidth = std::max(width, 1); + resolutionState_.windowHeight = std::max(height, 1); + resolutionState_.contentScaleX = std::max(contentScaleX, kMinContentScale); + resolutionState_.contentScaleY = std::max(contentScaleY, kMinContentScale); + resolutionState_.drawableWidth = std::max( + roundToInt(static_cast(resolutionState_.windowWidth) * + resolutionState_.contentScaleX), + 1); + resolutionState_.drawableHeight = std::max( + roundToInt(static_cast(resolutionState_.windowHeight) * + resolutionState_.contentScaleY), + 1); + recalculateResolutionState(); +} + +void Renderer::setVirtualResolutionEnabled(bool enabled) { + useVirtualResolution_ = enabled; + recalculateResolutionState(); +} + +void Renderer::setVirtualResolution(int width, int height) { + virtualWidth_ = std::max(width, 1); + virtualHeight_ = std::max(height, 1); + recalculateResolutionState(); +} + +void Renderer::setResolutionScaleMode(ResolutionScaleMode mode) { + resolutionMode_ = mode; + recalculateResolutionState(); } void Renderer::setClearColor(float r, float g, float b, float a) { @@ -98,15 +163,169 @@ void Renderer::setCamera(Camera* camera) { } camera_ = camera; - if (camera) { - camera_->setViewport(viewportWidth_, viewportHeight_); - } + syncCameraViewport(); if (initialized_) { updateUniforms(); } } +int Renderer::getVirtualWidth() const { + if (useVirtualResolution_) { + return std::max(virtualWidth_, 1); + } + return std::max(resolutionState_.windowWidth, 1); +} + +int Renderer::getVirtualHeight() const { + if (useVirtualResolution_) { + return std::max(virtualHeight_, 1); + } + return std::max(resolutionState_.windowHeight, 1); +} + +Rect Renderer::getViewportRect() const { + return resolutionState_.getWindowViewportRect(); +} + +Vec2 Renderer::screenToVirtual(const Vec2& screenPos) const { + Rect viewport = getViewportRect(); + if (viewport.width() <= 0.0f || viewport.height() <= 0.0f) { + return screenPos; + } + + float localX = screenPos.x - viewport.left(); + float localY = screenPos.y - viewport.top(); + return Vec2(localX * static_cast(getVirtualWidth()) / viewport.width(), + localY * static_cast(getVirtualHeight()) / + viewport.height()); +} + +Vec2 Renderer::virtualToScreen(const Vec2& virtualPos) const { + Rect viewport = getViewportRect(); + float logicalWidth = static_cast(std::max(getVirtualWidth(), 1)); + float logicalHeight = static_cast(std::max(getVirtualHeight(), 1)); + + return Vec2(viewport.left() + virtualPos.x * viewport.width() / logicalWidth, + viewport.top() + virtualPos.y * viewport.height() / + logicalHeight); +} + +void Renderer::recalculateResolutionState() { + resolutionState_.windowWidth = std::max(resolutionState_.windowWidth, 1); + resolutionState_.windowHeight = std::max(resolutionState_.windowHeight, 1); + resolutionState_.contentScaleX = + std::max(resolutionState_.contentScaleX, kMinContentScale); + resolutionState_.contentScaleY = + std::max(resolutionState_.contentScaleY, kMinContentScale); + resolutionState_.drawableWidth = std::max( + roundToInt(static_cast(resolutionState_.windowWidth) * + resolutionState_.contentScaleX), + 1); + resolutionState_.drawableHeight = std::max( + roundToInt(static_cast(resolutionState_.windowHeight) * + resolutionState_.contentScaleY), + 1); + + int windowViewportX = 0; + int windowViewportY = 0; + int windowViewportWidth = resolutionState_.windowWidth; + int windowViewportHeight = resolutionState_.windowHeight; + + if (useVirtualResolution_) { + float widthScale = static_cast(resolutionState_.windowWidth) / + static_cast(std::max(virtualWidth_, 1)); + float heightScale = static_cast(resolutionState_.windowHeight) / + static_cast(std::max(virtualHeight_, 1)); + + switch (resolutionMode_) { + case ResolutionScaleMode::Disabled: + resolutionState_.scaleX = widthScale; + resolutionState_.scaleY = heightScale; + break; + case ResolutionScaleMode::FitHeight: { + float uniformScale = heightScale; + float fittedWidth = static_cast(virtualWidth_) * uniformScale; + if (fittedWidth > static_cast(resolutionState_.windowWidth)) { + uniformScale = std::min(widthScale, heightScale); + } + + windowViewportWidth = std::clamp( + roundToInt(static_cast(virtualWidth_) * uniformScale), 1, + resolutionState_.windowWidth); + windowViewportHeight = std::clamp( + roundToInt(static_cast(virtualHeight_) * uniformScale), 1, + resolutionState_.windowHeight); + windowViewportX = + (resolutionState_.windowWidth - windowViewportWidth) / 2; + windowViewportY = + (resolutionState_.windowHeight - windowViewportHeight) / 2; + resolutionState_.scaleX = + static_cast(windowViewportWidth) / + static_cast(std::max(virtualWidth_, 1)); + resolutionState_.scaleY = + static_cast(windowViewportHeight) / + static_cast(std::max(virtualHeight_, 1)); + break; + } + case ResolutionScaleMode::Fit: + default: { + float uniformScale = std::min(widthScale, heightScale); + windowViewportWidth = std::clamp( + roundToInt(static_cast(virtualWidth_) * uniformScale), 1, + resolutionState_.windowWidth); + windowViewportHeight = std::clamp( + roundToInt(static_cast(virtualHeight_) * uniformScale), 1, + resolutionState_.windowHeight); + windowViewportX = + (resolutionState_.windowWidth - windowViewportWidth) / 2; + windowViewportY = + (resolutionState_.windowHeight - windowViewportHeight) / 2; + resolutionState_.scaleX = + static_cast(windowViewportWidth) / + static_cast(std::max(virtualWidth_, 1)); + resolutionState_.scaleY = + static_cast(windowViewportHeight) / + static_cast(std::max(virtualHeight_, 1)); + break; + } + } + } else { + resolutionState_.scaleX = 1.0f; + resolutionState_.scaleY = 1.0f; + } + + resolutionState_.windowViewportX = windowViewportX; + resolutionState_.windowViewportY = windowViewportY; + resolutionState_.windowViewportWidth = windowViewportWidth; + resolutionState_.windowViewportHeight = windowViewportHeight; + resolutionState_.viewportX = roundToInt( + static_cast(windowViewportX) * resolutionState_.contentScaleX); + resolutionState_.viewportY = roundToInt( + static_cast(windowViewportY) * resolutionState_.contentScaleY); + resolutionState_.viewportWidth = std::max( + roundToInt(static_cast(windowViewportWidth) * + resolutionState_.contentScaleX), + 1); + resolutionState_.viewportHeight = std::max( + roundToInt(static_cast(windowViewportHeight) * + resolutionState_.contentScaleY), + 1); + + syncCameraViewport(); + if (initialized_) { + updateUniforms(); + } +} + +void Renderer::syncCameraViewport() { + if (!camera_) { + return; + } + + camera_->setViewport(getVirtualWidth(), getVirtualHeight()); +} + void Renderer::setupBlendMode(BlendMode mode) { switch (mode) { case BlendMode::None: @@ -116,38 +335,37 @@ void Renderer::setupBlendMode(BlendMode mode) { case BlendMode::Normal: glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, - GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); break; case BlendMode::Additive: glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, - GL_ONE, GL_ONE); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ONE, GL_ONE); break; case BlendMode::Screen: glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, - GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_COLOR, GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); break; case BlendMode::Premultiplied: glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, - GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); break; case BlendMode::Subtractive: glEnable(GL_BLEND); - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, - GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); break; case BlendMode::Multiply: glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); - glBlendFuncSeparate(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA, - GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + glBlendFuncSeparate(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); break; } } @@ -160,7 +378,7 @@ void Renderer::updateUniforms() { spriteShader->setMat4("u_view", camera_->getViewMatrix()); spriteShader->setMat4("u_projection", camera_->getProjectionMatrix()); } - + auto* coloredShader = shaderManager_.getShader("colored_quad"); if (coloredShader) { coloredShader->use(); @@ -177,57 +395,57 @@ void Renderer::updateUniforms() { } } -void Renderer::drawQuad(const Vec2& pos, const Size& size, float cr, float cg, - float cb, float ca) { +void Renderer::drawQuad(const Vec2& pos, const Size& size, float cr, float cg, + float cb, float ca) { Rect rect(pos.x, pos.y, size.width, size.height); Quad quad = Quad::create(rect, cr, cg, cb, ca); Transform2D transform = Transform2D::identity(); - + auto* shader = shaderManager_.getShader("colored_quad"); if (shader) { shader->use(); } - + batch_.submitQuad(quad, transform, nullptr, shader, BlendMode::Normal); } void Renderer::drawQuad(const Vec2& pos, const Size& size, Ptr texture) { Rect rect(pos.x, pos.y, size.width, size.height); Quad quad = Quad::createTextured(rect, Rect(0, 0, size.width, size.height), - Vec2(size.width, size.height)); + Vec2(size.width, size.height)); Transform2D transform = Transform2D::identity(); - + auto* shader = shaderManager_.getShader("sprite"); if (shader) { shader->use(); } - + batch_.submitQuad(quad, transform, texture, shader, BlendMode::Normal); } void Renderer::drawQuad(const Rect& rect, const Color& color) { - drawQuad(Vec2(rect.left(), rect.top()), - Size(rect.width(), rect.height()), - color.r, color.g, color.b, color.a); + drawQuad(Vec2(rect.left(), rect.top()), Size(rect.width(), rect.height()), + color.r, color.g, color.b, color.a); } void Renderer::drawSprite(const Vec2& pos, const Size& size, Ptr texture) { drawQuad(pos, size, texture); } -void Renderer::drawSprite(const Vec2& pos, const Rect& srcRect, const Vec2& texSize, - Ptr texture, const Color& color) { +void Renderer::drawSprite(const Vec2& pos, const Rect& srcRect, + const Vec2& texSize, Ptr texture, + const Color& color) { Rect destRect(pos.x, pos.y, srcRect.width(), srcRect.height()); - Quad quad = Quad::createTextured(destRect, srcRect, texSize, - color.r, color.g, color.b, color.a); + Quad quad = Quad::createTextured(destRect, srcRect, texSize, color.r, color.g, + color.b, color.a); Transform2D transform = Transform2D::identity(); - + auto* shader = shaderManager_.getShader("sprite"); if (shader) { shader->use(); } - + batch_.submitQuad(quad, transform, texture, shader, BlendMode::Normal); } -} +} // namespace frostbite2D diff --git a/Frostbite2D/src/frostbite2D/scene/ui_scene.cpp b/Frostbite2D/src/frostbite2D/scene/ui_scene.cpp index 1a3660a..907adf4 100644 --- a/Frostbite2D/src/frostbite2D/scene/ui_scene.cpp +++ b/Frostbite2D/src/frostbite2D/scene/ui_scene.cpp @@ -1,8 +1,11 @@ +#include #include namespace frostbite2D { UIScene::UIScene() { + Renderer& renderer = Renderer::get(); + camera_.setViewport(renderer.getVirtualWidth(), renderer.getVirtualHeight()); camera_.setFlipY(true); camera_.setZoom(1.0f); camera_.setPosition(Vec2::Zero()); diff --git a/Game/include/camera/GameCameraController.h b/Game/include/camera/GameCameraController.h index 22c17f9..a937f43 100644 --- a/Game/include/camera/GameCameraController.h +++ b/Game/include/camera/GameCameraController.h @@ -45,7 +45,7 @@ private: bool debugEnabled_ = false; bool initialized_ = false; - float zoom_ = 1.2f; + float zoom_ = 1.0f; float debugMoveSpeed_ = 800.0f; }; diff --git a/Game/include/map/GameMap.h b/Game/include/map/GameMap.h index 8bcf485..bfe414d 100644 --- a/Game/include/map/GameMap.h +++ b/Game/include/map/GameMap.h @@ -90,9 +90,9 @@ private: int backgroundRepeatWidth_ = 0; /// 地图配置里的整体 Y 偏移;既影响层位置,也影响地板校准。 int mapOffsetY_ = 0; - bool debugMode_ = true; + bool debugMode_ = false; /// 硬编码调试开关:关闭后忽略可行走区域检测,允许角色自由移动。 - bool movableAreaCheckEnabled_ = false; + bool movableAreaCheckEnabled_ = true; /// 当前地图正在播放的背景音乐。 Ptr currentMusic_; }; diff --git a/Game/src/bootstrap/main.cpp b/Game/src/bootstrap/main.cpp index f5eba43..6e114f5 100644 --- a/Game/src/bootstrap/main.cpp +++ b/Game/src/bootstrap/main.cpp @@ -34,9 +34,18 @@ int main(int argc, char **argv) { AppConfig config = AppConfig::createDefault(); config.appName = "Frostbite2D Test App"; config.appVersion = "1.0.0"; +#ifdef SWITCH config.windowConfig.width = 1280; config.windowConfig.height = 720; +#else + config.windowConfig.width = 1066; + config.windowConfig.height = 600; +#endif config.windowConfig.title = "Frostbite2D - Async Init Demo"; + config.useVirtualResolution = true; + config.virtualWidth = 1066; + config.virtualHeight = 600; + config.resolutionMode = ResolutionScaleMode::FitHeight; Application &app = Application::get(); { @@ -76,19 +85,20 @@ int main(int argc, char **argv) { auto LoadingScene = MakePtr(); SceneManager::get().PushScene(LoadingScene); - auto Background = Sprite::createFromFile("assets/ImagePacks2/Loading0.jpg"); - Background->SetSize(1280, 720); + auto Background = + Sprite::createFromFile("assets/ImagePacks2/Loading0.png"); + Background->SetSize(1066, 600); LoadingScene->AddChild(Background); auto BackgroundBar = Sprite::createFromFile("assets/ImagePacks2/Loading1.png"); - BackgroundBar->SetPosition(0, 686); + BackgroundBar->SetPosition(0 - 107, 566); LoadingScene->AddChild(BackgroundBar); auto LoadCircleSp = Sprite::createFromFile("assets/ImagePacks2/Loading2.png"); LoadCircleSp->SetAnchor(Vec2(0.5f, 0.5f)); - LoadCircleSp->SetPosition(1280 / 2.0f, 686 - 60); + LoadCircleSp->SetPosition(1066 / 2.0f, 566 - 60); LoadCircleSp->SetBlendMode(BlendMode::Additive); LoadCircleSp->AddUpdateListener([](Actor &self, float dt) { auto rotation = self.GetRotation(); diff --git a/Game/src/camera/GameCameraController.cpp b/Game/src/camera/GameCameraController.cpp index 5d4c585..9fcdbd2 100644 --- a/Game/src/camera/GameCameraController.cpp +++ b/Game/src/camera/GameCameraController.cpp @@ -10,8 +10,6 @@ namespace frostbite2D { namespace { -constexpr float kScreenWidth = 1280.0f; -constexpr float kScreenHeight = 720.0f; constexpr int kDebugStickDeadzone = 8000; float normalizeControllerAxis(int16 value) { @@ -180,10 +178,10 @@ void GameCameraController::applyFocus() const { return; } - float halfWidth = kScreenWidth * 0.5f / zoom_; - float halfHeight = kScreenHeight * 0.5f / zoom_; - Vec2 cameraPos(focus_.x - halfWidth, focus_.y - halfHeight); camera->setZoom(zoom_); + float halfWidth = camera->getVisibleWidth() * 0.5f; + float halfHeight = camera->getVisibleHeight() * 0.5f; + Vec2 cameraPos(focus_.x - halfWidth, focus_.y - halfHeight); camera->setPosition(cameraPos); map_->ApplyCameraFocus(focus_); } diff --git a/Game/src/scene/GameMapTestScene.cpp b/Game/src/scene/GameMapTestScene.cpp index c65e40f..4abf018 100644 --- a/Game/src/scene/GameMapTestScene.cpp +++ b/Game/src/scene/GameMapTestScene.cpp @@ -43,14 +43,14 @@ void GameMapTestScene::onEnter() { { ScopedStartupTrace stageTrace("GameMapTestScene character construction"); - character_ = MakePtr(); - if (!character_->Construction(0)) { - SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + character_ = MakePtr(); + if (!character_->Construction(0)) { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "GameMapTestScene: failed to construct default character"); character_.Reset(); } else { Vec2 spawnPos = - map_->ClampCameraFocus(map_->GetDefaultCameraFocus(), 1.2f); + map_->ClampCameraFocus(map_->GetDefaultCameraFocus(), 1.0f); character_->SetCharacterPosition(spawnPos); character_->EnableEventReceive(); character_->SetEventPriority(-100); @@ -59,7 +59,6 @@ void GameMapTestScene::onEnter() { } cameraController_.SetMap(map_.Get()); - // cameraController_.SetZoom(1.2f); cameraController_.SetTarget(character_.Get()); cameraController_.SetDebugEnabled(false); if (character_) { diff --git a/Game/src/world/GameTown.cpp b/Game/src/world/GameTown.cpp index 301ff67..e4d8afb 100644 --- a/Game/src/world/GameTown.cpp +++ b/Game/src/world/GameTown.cpp @@ -117,7 +117,6 @@ void GameTown::AddCharacter(RefPtr actor, int areaIndex) { AddChild(mapIt->map); cameraController_.SetMap(mapIt->map.Get()); - cameraController_.SetZoom(1.2f); cameraController_.SetTarget(actor.Get()); cameraController_.SnapToDefaultFocus();