Added a lots of the file to write the pixel game but due to some problem ,i dicide to change sdl3 to sfml,a more modern lib

This commit is contained in:
2025-12-21 14:58:33 +08:00
parent 96b005e2ef
commit 86dce63e74
15 changed files with 443 additions and 51 deletions

View File

@@ -41,6 +41,7 @@ set(SOURCE_FILES
src/ui/managers/GameUIManager.cpp src/ui/managers/GameUIManager.cpp
src/ui/managers/MainMenuUIManager.cpp src/ui/managers/MainMenuUIManager.cpp
src/graphics/ui/UIRenderer.cpp src/graphics/ui/UIRenderer.cpp
src/graphics/font/BitmapFont.cpp
) )
@@ -54,6 +55,7 @@ target_link_libraries(${PROJECT_NAME}
PRIVATE PRIVATE
SDL3::SDL3 SDL3::SDL3
SDL3_ttf::SDL3_ttf SDL3_ttf::SDL3_ttf
SDL3_image::SDL3_image
) )
# ========== Windows: 复制 DLL ========== # ========== Windows: 复制 DLL ==========
@@ -82,6 +84,9 @@ if (WIN32)
COMMAND ${CMAKE_COMMAND} -E copy_if_different COMMAND ${CMAKE_COMMAND} -E copy_if_different
${STDCPP_DLL_PATH} ${STDCPP_DLL_PATH}
$<TARGET_FILE_DIR:${PROJECT_NAME}> $<TARGET_FILE_DIR:${PROJECT_NAME}>
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:SDL3_image::SDL3_image>
$<TARGET_FILE_DIR:${PROJECT_NAME}>
COMMENT "Copying MinGW runtime DLLs" COMMENT "Copying MinGW runtime DLLs"
) )
endif() endif()

View File

@@ -25,3 +25,14 @@ FetchContent_Declare(
) )
FetchContent_MakeAvailable(SDL3_ttf) FetchContent_MakeAvailable(SDL3_ttf)
# ===========================
# SDL3_image
# ===========================
FetchContent_Declare(
SDL3_image
GIT_REPOSITORY https://github.com/libsdl-org/SDL_image.git
GIT_TAG release-3.2.0
)
FetchContent_MakeAvailable(SDL3_image)

View File

@@ -11,14 +11,14 @@ WindowManager::~WindowManager() {
} }
bool WindowManager::Initialize(GameConfig& config) { bool WindowManager::Initialize(GameConfig& config) {
m_width = config.windowWidth; m_logicalWidth = config.logicalWidth;
m_height = config.windowHeight; m_logicalHeight = config.logicalHeight;
// 创建窗口支持高DPI和横屏[3,4](@ref) // 创建窗口支持高DPI和横屏[3,4](@ref)
m_window = SDL_CreateWindow( m_window = SDL_CreateWindow(
"孢子棋", // 窗口标题,显示在标题栏上 "孢子棋", // 窗口标题,显示在标题栏上
m_width, // 窗口的逻辑宽度(例如 800用于统一布局不受屏幕 DPI 影响 m_logicalWidth, // 窗口的逻辑宽度(例如 800用于统一布局不受屏幕 DPI 影响
m_height, // 窗口的逻辑高度(例如 600 m_logicalHeight, // 窗口的逻辑高度(例如 600
SDL_WINDOW_HIGH_PIXEL_DENSITY | // 启用高像素密度支持HiDPI/Retina确保在高分屏上画面清晰 //SDL_WINDOW_HIGH_PIXEL_DENSITY | // 启用高像素密度支持HiDPI/Retina确保在高分屏上画面清晰
SDL_WINDOW_RESIZABLE // 允许用户调整窗口大小(可拉伸) SDL_WINDOW_RESIZABLE // 允许用户调整窗口大小(可拉伸)
); );
if (!m_window) { if (!m_window) {
@@ -34,14 +34,28 @@ bool WindowManager::Initialize(GameConfig& config) {
"创建渲染器失败: %s", SDL_GetError()); "创建渲染器失败: %s", SDL_GetError());
return false; return false;
} }
// 关键设置:启用像素模式 // 关键设置:启用像素模式
// 设置逻辑呈现模式,实现分辨率自适应[3](@ref) /* // 设置逻辑呈现模式,实现分辨率自适应[3](@ref)
SDL_SetRenderLogicalPresentation(m_renderer, SDL_SetRenderLogicalPresentation(m_renderer,
m_width, m_width,
m_height, m_height,
SDL_LOGICAL_PRESENTATION_LETTERBOX); SDL_LOGICAL_PRESENTATION_INTEGER_SCALE);
SDL_SetWindowSize(m_window, m_width, m_height); */
SDL_SetWindowSize(m_window, UI::StartWindowWidth, UI::StartWindowHeight);
// 创建逻辑画布
// RGBA8888: 32位色8位红绿蓝和透明度
// TARGET: 纹理可作为渲染目标
m_logicalTexture = SDL_CreateTexture(
m_renderer,
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
m_logicalWidth,
m_logicalHeight
);
return true; return true;
} }
@@ -51,13 +65,28 @@ void WindowManager::Shutdown() {
} }
void WindowManager::Clear() { void WindowManager::Clear() {
// 1. 设置渲染目标为逻辑纹理
SDL_SetRenderTarget(m_renderer, m_logicalTexture);
// 设置画笔颜色 // 设置画笔颜色
SDL_SetRenderDrawColor(m_renderer, 255, 255, 255, 255); SDL_SetRenderDrawColor(m_renderer, 255, 255, 255, 255);
// 使用画笔颜色填充整个屏幕 // 使用画笔颜色填充整个逻辑画布
SDL_RenderClear(m_renderer); SDL_RenderClear(m_renderer);
} }
void WindowManager::Present() { void WindowManager::Present() {
// 4. 切回默认渲染目标(窗口)
SDL_SetRenderTarget(m_renderer, nullptr);
SDL_RenderClear(m_renderer); // 清的是窗口(黑边
SDL_FRect dstRect;
calculateDstRect(dstRect);
SDL_RenderTexture (
m_renderer,
m_logicalTexture, // 源:你已经画好的逻辑画布
nullptr, // srcRect源区域nullptr = 整张)
&dstRect // dstRect贴到哪里 & 贴多大
);
SDL_RenderPresent(m_renderer); SDL_RenderPresent(m_renderer);
} }
@@ -78,3 +107,19 @@ bool WindowManager::setFullscreen(bool isFullscreen) {
return true; return true;
} }
void WindowManager::calculateDstRect(SDL_FRect& dstRect) {
// 获取窗口的实际尺寸(像素)
SDL_GetWindowSize(m_window, &m_windowWidth, &m_windowHeight);
// 计算缩放比例,整数缩放
int scaleX = m_windowWidth / m_logicalWidth;
int scaleY = m_windowHeight / m_logicalHeight;
int scale = (scaleX < scaleY) ? scaleX : scaleY;
// 计算目标矩形的尺寸
dstRect.w = static_cast<float>(m_logicalWidth * scale);
dstRect.h = static_cast<float>(m_logicalHeight * scale);
// 居中显示
dstRect.x = static_cast<float>((m_windowWidth - dstRect.w) / 2);
dstRect.y = static_cast<float>((m_windowHeight - dstRect.h) / 2);
}

View File

@@ -23,7 +23,13 @@ public:
private: private:
SDL_Window* m_window; SDL_Window* m_window;
SDL_Renderer* m_renderer; SDL_Renderer* m_renderer;
int m_width; int m_logicalWidth;
int m_height; int m_logicalHeight;
int m_windowWidth;
int m_windowHeight;
bool m_isFullscreen = false; bool m_isFullscreen = false;
SDL_Texture* m_logicalTexture = nullptr;
// 计算缩放后的目标矩形
void calculateDstRect(SDL_FRect& dstRect);
}; };

View File

@@ -0,0 +1,208 @@
#include "BitmapFont.h"
#include <SDL3_image/SDL_image.h>
#include <fstream>
#include <filesystem>
#include <cstdio>
#include <cstring>
static bool startsWith(const std::string& s, const char* prefix) {
return s.size() >= std::strlen(prefix) &&
s.compare(0, std::strlen(prefix), prefix) == 0;
}
////////////////////////////////////////////////////////////
// 构造 / 析构
////////////////////////////////////////////////////////////
BitmapFont::BitmapFont() = default;
BitmapFont::~BitmapFont() {
for (SDL_Texture* tex : m_pages) {
SDL_DestroyTexture(tex);
}
m_pages.clear();
}
////////////////////////////////////////////////////////////
// 加载 .fnt
////////////////////////////////////////////////////////////
bool BitmapFont::load(const std::string& fntPath, SDL_Renderer* renderer) {
m_renderer = renderer;
std::ifstream file(fntPath);
if (!file.is_open()) {
SDL_Log("BitmapFont: 无法打开 %s", fntPath.c_str());
return false;
}
// .fnt 所在目录(用于加载 .tga
std::string baseDir =
std::filesystem::path(fntPath).parent_path().string();
std::string line;
while (std::getline(file, line)) {
// common 行:行高
if (startsWith(line, "common ")) {
sscanf(line.c_str(),
"common lineHeight=%d",
&m_lineHeight
);
}
// page 行:加载贴图
else if (startsWith(line, "page ")) {
int id = 0;
char filename[256]{};
sscanf(line.c_str(),
"page id=%d file=\"%255[^\"]\"",
&id, filename
);
if ((int)m_pages.size() <= id) {
m_pages.resize(id + 1, nullptr);
}
std::string texPath = baseDir + "/" + filename;
SDL_Surface* surf = IMG_Load(texPath.c_str());
if (!surf) {
SDL_Log("BitmapFont: 无法加载贴图 %s", texPath.c_str());
return false;
}
SDL_Texture* tex =
SDL_CreateTextureFromSurface(renderer, surf);
SDL_DestroySurface(surf);
// 像素风关键:最近邻
SDL_SetTextureScaleMode(tex, SDL_SCALEMODE_NEAREST);
m_pages[id] = tex;
}
// char 行:字形数据
else if (startsWith(line, "char ")) {
uint32_t id = 0;
BitmapGlyph g{};
sscanf(line.c_str(),
"char id=%u x=%d y=%d width=%d height=%d "
"xoffset=%d yoffset=%d xadvance=%d page=%d",
&id,
&g.x, &g.y,
&g.w, &g.h,
&g.xOffset, &g.yOffset,
&g.xAdvance,
&g.page
);
m_glyphs[id] = g;
}
}
return true;
}
////////////////////////////////////////////////////////////
// 绘制文本
////////////////////////////////////////////////////////////
void BitmapFont::drawText(const std::string& text, int x, int y) const {
int cursorX = x;
int cursorY = y;
for (uint32_t cp : utf8ToCodepoints(text)) {
// 换行
if (cp == '\n') {
cursorX = x;
cursorY += m_lineHeight;
continue;
}
auto it = m_glyphs.find(cp);
if (it == m_glyphs.end()) {
continue;
}
const BitmapGlyph& g = it->second;
SDL_FRect src{
(float)g.x,
(float)g.y,
(float)g.w,
(float)g.h
};
SDL_FRect dst{
(float)(cursorX + g.xOffset),
(float)(cursorY + g.yOffset),
(float)g.w,
(float)g.h
};
SDL_RenderTexture(
m_renderer,
m_pages[g.page],
&src,
&dst
);
cursorX += g.xAdvance;
}
}
////////////////////////////////////////////////////////////
// 行高
////////////////////////////////////////////////////////////
int BitmapFont::getLineHeight() const {
return m_lineHeight;
}
////////////////////////////////////////////////////////////
// UTF-8 → Unicode codepoint最小但够用
////////////////////////////////////////////////////////////
std::vector<uint32_t>
BitmapFont::utf8ToCodepoints(const std::string& text) {
std::vector<uint32_t> result;
for (size_t i = 0; i < text.size();) {
uint8_t c = (uint8_t)text[i];
if (c < 0x80) {
result.push_back(c);
i += 1;
}
else if ((c >> 5) == 0x6) {
uint32_t cp =
((text[i] & 0x1F) << 6) |
(text[i + 1] & 0x3F);
result.push_back(cp);
i += 2;
}
else if ((c >> 4) == 0xE) {
uint32_t cp =
((text[i] & 0x0F) << 12) |
((text[i + 1] & 0x3F) << 6) |
(text[i + 2] & 0x3F);
result.push_back(cp);
i += 3;
}
else if ((c >> 3) == 0x1E) {
uint32_t cp =
((text[i] & 0x07) << 18) |
((text[i + 1] & 0x3F) << 12) |
((text[i + 2] & 0x3F) << 6) |
(text[i + 3] & 0x3F);
result.push_back(cp);
i += 4;
}
else {
// 非法 UTF-8跳过
i += 1;
}
}
return result;
}

View File

@@ -0,0 +1,70 @@
#pragma once
/*
BitmapFont.h
--------------------------------
Bitmap FontBMFont / AngelCode渲染器
- 支持 .fnt文本格式
- 支持多 page多张 .tga
- 支持 UTF-8 / 中文
- SDL3 / 像素风NEAREST
用法示例:
BitmapFont font;
font.load("assets/fonts/sanhan.fnt", renderer);
font.drawText("你好,像素世界", 10, 10);
*/
#include <SDL3/SDL.h>
#include <string>
#include <unordered_map>
#include <vector>
////////////////////////////////////////////////////////////
// 单个字形(对应 .fnt 中的 char 行)
////////////////////////////////////////////////////////////
struct BitmapGlyph {
int x = 0; // 在贴图中的 x
int y = 0; // 在贴图中的 y
int w = 0; // 字形宽度
int h = 0; // 字形高度
int xOffset = 0; // 绘制时 x 偏移
int yOffset = 0; // 绘制时 y 偏移
int xAdvance = 0;// 光标前进量
int page = 0; // 所属贴图页
};
////////////////////////////////////////////////////////////
// BitmapFont 类
////////////////////////////////////////////////////////////
class BitmapFont {
public:
BitmapFont();
~BitmapFont();
// 加载 .fnt 文件
bool load(const std::string& fntPath, SDL_Renderer* renderer);
// 绘制文本UTF-8
void drawText(const std::string& text, int x, int y) const;
// 获取行高(用于换行 / UI 布局)
int getLineHeight() const;
private:
// UTF-8 → Unicode codepoint
static std::vector<uint32_t> utf8ToCodepoints(const std::string& text);
private:
SDL_Renderer* m_renderer = nullptr;
int m_lineHeight = 0;
// Unicode → Glyph
std::unordered_map<uint32_t, BitmapGlyph> m_glyphs;
// 所有 page 对应的纹理
std::vector<SDL_Texture*> m_pages;
};

View File

@@ -5,7 +5,8 @@ TextRenderer::TextRenderer(SDL_Renderer* renderer, FontManager* fontManager) :
m_fontManager(fontManager), m_fontManager(fontManager),
m_renderer(renderer) m_renderer(renderer)
{ {
//m_bitmapFont = std::make_unique<BitmapFont>();
//m_bitmapFont->load("assets/fonts/sanhan.fnt", renderer);
} }
TextRenderer::~TextRenderer() { TextRenderer::~TextRenderer() {
@@ -62,6 +63,8 @@ void TextRenderer::renderText(const std::string& text, TextStyle style, int x, i
static_cast<float>(cached.width), static_cast<float>(cached.width),
static_cast<float>(cached.height) }; static_cast<float>(cached.height) };
SDL_RenderTexture(m_renderer, cached.texture, NULL, &dest); SDL_RenderTexture(m_renderer, cached.texture, NULL, &dest);
//m_bitmapFont->drawText(text, x, y);
} }
TextRenderer::CachedText TextRenderer::createAndCacheTexture(const std::string& text, TextStyle style) { TextRenderer::CachedText TextRenderer::createAndCacheTexture(const std::string& text, TextStyle style) {
@@ -91,6 +94,7 @@ TextRenderer::CachedText TextRenderer::createAndCacheTexture(const std::string&
SDL_Log("错误:无法创建纹理\n"); SDL_Log("错误:无法创建纹理\n");
return result; return result;
} }
// 设置纹理缩放模式为最近邻
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST); SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);
// 保存结果 // 保存结果
result.texture = texture; result.texture = texture;

View File

@@ -16,7 +16,8 @@
#include <SDL3_ttf/SDL_ttf.h> #include <SDL3_ttf/SDL_ttf.h>
#include "Textstyle.h" #include "Textstyle.h"
#include "FontManager.h" #include "FontManager.h"
#include "BitmapFont.h"
#include <memory>
/** /**
* @class TextRenderer * @class TextRenderer
* @brief 文本渲染器 * @brief 文本渲染器
@@ -163,5 +164,5 @@ private:
* @see CachedText, m_cache * @see CachedText, m_cache
*/ */
CachedText createAndCacheTexture(const std::string& text, TextStyle style); CachedText createAndCacheTexture(const std::string& text, TextStyle style);
//std::unique_ptr<BitmapFont> m_bitmapFont;
}; };

View File

@@ -99,14 +99,14 @@ void UIRenderer::renderText(const Type& data) {
auto [textW, textH] = m_textRenderer->getTextSize(m_text, m_textStyle); auto [textW, textH] = m_textRenderer->getTextSize(m_text, m_textStyle);
// 如果组件的宽高为 0则使用文本尺寸填充相当于自动调整控件大小 // 如果组件的宽高为 0则使用文本尺寸填充相当于自动调整控件大小
float boxW = m_rect.w; int boxW = m_rect.w;
float boxH = m_rect.h; int boxH = m_rect.h;
if (boxW <= 0.0f) boxW = static_cast<float>(textW); if (boxW <= 0) boxW = textW;
if (boxH <= 0.0f) boxH = static_cast<float>(textH); if (boxH <= 0) boxH = textH;
// 计算文本左上角坐标以实现居中 // 计算文本左上角坐标以实现居中
int textX = static_cast<int>(m_rect.x + (boxW - textW) / 2.0f); int textX = m_rect.x + (boxW - textW) / 2;
int textY = static_cast<int>(m_rect.y + (boxH - textH) / 2.0f); int textY = m_rect.y + (boxH - textH) / 2;
// 渲染文本TextRenderer 的 x,y 为左上角) // 渲染文本TextRenderer 的 x,y 为左上角)
m_textRenderer->renderText(m_text, m_textStyle, textX, textY); m_textRenderer->renderText(m_text, m_textStyle, textX, textY);

View File

@@ -34,9 +34,13 @@ public:
* @brief 设置组件位置 * @brief 设置组件位置
* @param x X坐标屏幕像素 * @param x X坐标屏幕像素
* @param y Y坐标屏幕像素 * @param y Y坐标屏幕像素
* @param w 宽度(屏幕像素)
* @param h 高度(屏幕像素)
*/ */
virtual void setPosition(int x, int y) { virtual void setRect(int x, int y, int w, int h) {
m_rect.w = static_cast<float>(w);
m_rect.h = static_cast<float>(h);
m_rect.x = static_cast<float>(x); m_rect.x = static_cast<float>(x);
m_rect.y = static_cast<float>(y); m_rect.y = static_cast<float>(y);
} }

View File

@@ -1,24 +1,25 @@
#include "Button.h" #include "Button.h"
#include "graphics/font/TextRenderer.h" //#include "graphics/font/TextRenderer.h"
Button::Button() Button::Button()
{ {
} }
Button::Button(TextRenderer* textRenderer) : m_textRenderer(textRenderer) {
}
Button::Button( Button::Button(
const std::string& text, const std::string& text,
TextStyle style, TextStyle style,
int x, int x,
int y, int y,
TextRenderer* textRenderer, int w,
int h,
//TextRenderer* textRenderer,
SDL_Color backgroundColor, SDL_Color backgroundColor,
int borderThickness, int borderThickness,
SDL_Color borderColor SDL_Color borderColor
) : m_textRenderer(textRenderer) ) //: m_textRenderer(textRenderer)
{ {
m_rect.x = static_cast<float>(x); m_rect.x = static_cast<float>(x);
m_rect.y = static_cast<float>(y); m_rect.y = static_cast<float>(y);
@@ -29,12 +30,14 @@ Button::Button(
m_buttonData.borderColor = borderColor; m_buttonData.borderColor = borderColor;
// 如果提供了 TextRenderer则立即测量文本并更新控件尺寸 // 如果提供了 TextRenderer则立即测量文本并更新控件尺寸
if (m_textRenderer) { /*if (m_textRenderer) {
auto [w, h] = m_textRenderer->getTextSize(text, style); auto [w, h] = m_textRenderer->getTextSize(text, style);
m_rect.w = static_cast<float>(w); m_rect.w = static_cast<float>(w);
m_rect.h = static_cast<float>(h); m_rect.h = static_cast<float>(h);
m_buttonData.rect = m_rect; m_buttonData.rect = m_rect;
} }*/
m_rect.w = static_cast<float>(w);
m_rect.h = static_cast<float>(h);
} }
@@ -43,24 +46,24 @@ void Button::setText(const std::string& text, TextStyle style) {
m_buttonData.textstytle = style; m_buttonData.textstytle = style;
// 如果提供了 TextRenderer则立即测量文本并更新控件尺寸 // 如果提供了 TextRenderer则立即测量文本并更新控件尺寸
if (m_textRenderer) { /*if (m_textRenderer) {
auto [w, h] = m_textRenderer->getTextSize(text, style); auto [w, h] = m_textRenderer->getTextSize(text, style);
m_rect.w = static_cast<float>(w); m_rect.w = static_cast<float>(w);
m_rect.h = static_cast<float>(h); m_rect.h = static_cast<float>(h);
m_buttonData.rect = m_rect; m_buttonData.rect = m_rect;
} }*/
} }
void Button::setText(const std::string& text) { void Button::setText(const std::string& text) {
m_buttonData.text = text; m_buttonData.text = text;
// 如果提供了 TextRenderer则立即测量文本并更新控件尺寸 // 如果提供了 TextRenderer则立即测量文本并更新控件尺寸
if (m_textRenderer) { /*if (m_textRenderer) {
auto [w, h] = m_textRenderer->getTextSize(text, m_buttonData.textstytle); auto [w, h] = m_textRenderer->getTextSize(text, m_buttonData.textstytle);
m_rect.w = static_cast<float>(w); m_rect.w = static_cast<float>(w);
m_rect.h = static_cast<float>(h); m_rect.h = static_cast<float>(h);
m_buttonData.rect = m_rect; m_buttonData.rect = m_rect;
} }*/
} }
void Button::setBackgroundColor(SDL_Color normal) { void Button::setBackgroundColor(SDL_Color normal) {

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "ui/base/UIRenderData.h" #include "ui/base/UIRenderData.h"
#include "ui/base/UIComponent.h" #include "ui/base/UIComponent.h"
#include "utils/Config.h"
#include <memory> #include <memory>
// 前向声明,避免在头文件包含过多实现细节 // 前向声明,避免在头文件包含过多实现细节
@@ -10,15 +11,15 @@ class Button : public UIComponent{
public: public:
// 默认构造(不进行自动测量) // 默认构造(不进行自动测量)
Button(); Button();
// 可以传入 TextRenderer 指针以便在 setText 时立即计算文字尺寸并更新 rect
explicit Button(TextRenderer* textRenderer);
explicit Button( explicit Button(
const std::string& text, const std::string& text,
TextStyle style = {"SourceHanSansSC-Regular.otf", 48, {0, 0, 0, 255}}, TextStyle style = {"SourceHanSansSC-Regular.otf", 48, {0, 0, 0, 255}},
int x = 0, int x = 0,
int y = 0, int y = 0,
TextRenderer* textRenderer = nullptr, int w = UI::ButtonSize,
int h = UI::ButtonSize,
//TextRenderer* textRenderer = nullptr,
SDL_Color backgroundColor = {200, 200, 200, 255}, SDL_Color backgroundColor = {200, 200, 200, 255},
int borderThickness = 0, int borderThickness = 0,
SDL_Color borderColor = {0, 0, 0, 255} SDL_Color borderColor = {0, 0, 0, 255}
@@ -78,7 +79,7 @@ private:
std::function<void()> m_callback; std::function<void()> m_callback;
ButtonData m_buttonData; ButtonData m_buttonData;
// 用于在 setText 时测量文本尺寸(非拥有) // 用于在 setText 时测量文本尺寸(非拥有)
TextRenderer* m_textRenderer = nullptr; //TextRenderer* m_textRenderer = nullptr;
}; };

View File

@@ -126,10 +126,10 @@ void GameUIManager::updateGameState(GameState state) {
void GameUIManager::setupUIComponents() { void GameUIManager::setupUIComponents() {
// 这里可以添加更多的UI组件初始化逻辑 // 这里可以添加更多的UI组件初始化逻辑
auto button = std::make_unique<Button>(m_textRenderer); auto button = std::make_unique<Button>();
button->setBackgroundColor({255, 100, 0, 255}); button->setBackgroundColor({255, 100, 0, 255});
button->setBorder(2, {0, 0, 0, 255}); button->setBorder(2, {0, 0, 0, 255});
button->setPosition(20, 20); button->setRect(20, 20, 200, 100);
button->setEnabled(true); button->setEnabled(true);
button->setVisible(true); button->setVisible(true);
button->setText("Please Choose", {"SourceHanSansSC-Regular.otf", 48, {0, 0, 0, 255}}); button->setText("Please Choose", {"SourceHanSansSC-Regular.otf", 48, {0, 0, 0, 255}});
@@ -137,18 +137,16 @@ void GameUIManager::setupUIComponents() {
m_buttons.emplace(button->getNameHash(), std::move(button)); m_buttons.emplace(button->getNameHash(), std::move(button));
auto label = std::make_unique<Label>(); auto label = std::make_unique<Label>();
label->setPosition(1200, 20); label->setRect(1200, 20, 200, 50);
label->setText("0 0", {"SourceHanSansSC-Regular.otf", 48, {0, 0, 0, 255}}); label->setText("0 0", {"SourceHanSansSC-Regular.otf", 48, {0, 0, 0, 255}});
label->setName("MousePositionLabel"); label->setName("MousePositionLabel");
m_labels.emplace(label->getNameHash(), std::move(label)); m_labels.emplace(label->getNameHash(), std::move(label));
auto restartButton = std::make_unique<Button>( auto restartButton = std::make_unique<Button>(
"Restart", "Restart",
(TextStyle){"SourceHanSansSC-Regular.otf", 48, {0, 0, 0, 255}}, (TextStyle){"unifont.otf", 48, {0, 0, 0, 255}},
700, 700,
500, 500
m_textRenderer,
(SDL_Color){100, 255, 100, 255}
); );
restartButton->setCallback([this](){ restartButton->setCallback([this](){

View File

@@ -13,19 +13,26 @@ MainMenuUIManager::~MainMenuUIManager() {
} }
void MainMenuUIManager::init() { void MainMenuUIManager::init() {
auto button = std::make_unique<Button>(m_textRenderer); auto button = std::make_unique<Button>();
button->setBackgroundColor({0, 150, 255, 255}); button->setBackgroundColor({0, 150, 255, 255});
button->setBorder(2, {0, 0, 0, 255}); button->setBorder(2, {0, 0, 0, 255});
button->setPosition(650, 430);
button->setRect(0, 0, UI::ButtonSize * 4, UI::ButtonSize * 2);
button->setName("StartButton"); button->setName("StartButton");
button->setText("Start Game", {"SourceHanSansSC-Regular.otf", 64, {255, 255, 255, 255}});
button->setText("Start Game", {"SourceHanSansSC-Regular.otf", UI::UI_NORMAL_FONT_SIZE, {255, 255, 255, 255}});
button->setCallback([this](){ button->setCallback([this](){
SDL_Log("Start Game button clicked!"); SDL_Log("Start Game button clicked!");
m_eventCallback("GameScene"); m_eventCallback("GameScene");
}); });
m_buttons.emplace(button->getNameHash(), std::move(button)); m_buttons.emplace(button->getNameHash(), std::move(button));
auto label = std::make_unique<Label>(); auto label = std::make_unique<Label>();
label->setPosition(1200, 20); label->setRect(1200, 20, 200, 50);
label->setText("0 0", {"SourceHanSansSC-Regular.otf", 48, {0, 0, 0, 255}}); label->setText("0 0", {"SourceHanSansSC-Regular.otf", 48, {0, 0, 0, 255}});
label->setName("MousePositionLabel"); label->setName("MousePositionLabel");
m_labels.emplace(label->getNameHash(), std::move(label)); m_labels.emplace(label->getNameHash(), std::move(label));

View File

@@ -3,11 +3,22 @@
// 统一管理配置 // 统一管理配置
struct GameConfig { struct GameConfig {
int windowWidth = 1600; /*
int windowHeight = 900; tileSize: 16x16 每个格子的逻辑大小(像素)
屏幕 = 20 × 11 tiles = 320x176 逻辑分辨率
*/
int logicalWidth = 320;
int logicalHeight = 180;
std::string windowTitle = "孢子棋"; std::string windowTitle = "孢子棋";
bool vsync = true; bool vsync = true;
int uiScale = 2; int scale = 2;
/*
1280x720 scale 4
1920x1080 scale 6
2560x1440 scale 8
3840x2160 scale 12
*/
} ; } ;
// 获取棋盘渲染区域信息(用于坐标转换) // 获取棋盘渲染区域信息(用于坐标转换)
@@ -16,3 +27,21 @@ struct BoardArea {
int cellSize; // 每格像素大小 int cellSize; // 每格像素大小
int rows, cols; // 行列数 int rows, cols; // 行列数
}; };
// ui 相关常量
namespace UI
{
constexpr int TopBarHeight = 16;
constexpr int HotbarHeight = 32;
constexpr int ButtonSize = 16;
constexpr int SlotSize = 16;
constexpr int PanelPadding = 4;
constexpr int FontHeight = 8;
constexpr int StartWindowWidth = 320 * 4; // 初始窗口宽度(像素)
constexpr int StartWindowHeight = 180 * 4; // 初始窗口高度(像素)
// 字体大小(逻辑像素)
constexpr int DIALOG_FONT_SIZE = 14;
constexpr int UI_SMALL_FONT_SIZE = 8;
constexpr int UI_NORMAL_FONT_SIZE = 12;
constexpr int UI_LARGE_FONT_SIZE = 16;
}