diff --git a/Tetris.sln b/Tetris.sln new file mode 100644 index 0000000..eb62b96 --- /dev/null +++ b/Tetris.sln @@ -0,0 +1,30 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 18 +VisualStudioVersion = 18.0.0.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tetris", "Tetris.vcxproj", "{A6B8E95B-7C95-46C2-A3E2-48F342D1F20B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A6B8E95B-7C95-46C2-A3E2-48F342D1F20B}.Debug|Win32.ActiveCfg = Debug|Win32 + {A6B8E95B-7C95-46C2-A3E2-48F342D1F20B}.Debug|Win32.Build.0 = Debug|Win32 + {A6B8E95B-7C95-46C2-A3E2-48F342D1F20B}.Debug|x64.ActiveCfg = Debug|x64 + {A6B8E95B-7C95-46C2-A3E2-48F342D1F20B}.Debug|x64.Build.0 = Debug|x64 + {A6B8E95B-7C95-46C2-A3E2-48F342D1F20B}.Release|Win32.ActiveCfg = Release|Win32 + {A6B8E95B-7C95-46C2-A3E2-48F342D1F20B}.Release|Win32.Build.0 = Release|Win32 + {A6B8E95B-7C95-46C2-A3E2-48F342D1F20B}.Release|x64.ActiveCfg = Release|x64 + {A6B8E95B-7C95-46C2-A3E2-48F342D1F20B}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2A6B54D6-B945-4445-8A94-9B38E625493E} + EndGlobalSection +EndGlobal diff --git a/Tetris.vcxproj b/Tetris.vcxproj new file mode 100644 index 0000000..c8a43d1 --- /dev/null +++ b/Tetris.vcxproj @@ -0,0 +1,204 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + 18.0 + Win32Proj + {A6B8E95B-7C95-46C2-A3E2-48F342D1F20B} + Tetris + 10.0 + + + + Application + true + v145 + Unicode + + + Application + true + v145 + Unicode + + + Application + false + v145 + true + Unicode + + + Application + false + v145 + true + Unicode + + + + + + + + + + + + + + + + + + + $(ProjectDir).vscode-build\vs2026\$(Platform)\$(Configuration)\ + $(ProjectDir).vscode-build\vs2026\obj\$(Platform)\$(Configuration)\ + Tetris + + + + Level3 + true + UNICODE;_UNICODE;_WINDOWS;%(PreprocessorDefinitions) + true + stdcpp17 + $(ProjectDir)src\include;%(AdditionalIncludeDirectories) + NotUsing + /utf-8 %(AdditionalOptions) + Disabled + ProgramDatabase + + + Windows + true + winmm.lib;gdiplus.lib;gdi32.lib;user32.lib;shell32.lib;%(AdditionalDependencies) + + + $(ProjectDir)src\include;$(ProjectDir)assets\icons;%(AdditionalIncludeDirectories) + UNICODE;_UNICODE;%(PreprocessorDefinitions) + + + + + Level3 + true + UNICODE;_UNICODE;_WINDOWS;%(PreprocessorDefinitions) + true + stdcpp17 + $(ProjectDir)src\include;%(AdditionalIncludeDirectories) + NotUsing + /utf-8 %(AdditionalOptions) + Disabled + ProgramDatabase + + + Windows + true + winmm.lib;gdiplus.lib;gdi32.lib;user32.lib;shell32.lib;%(AdditionalDependencies) + + + $(ProjectDir)src\include;$(ProjectDir)assets\icons;%(AdditionalIncludeDirectories) + UNICODE;_UNICODE;%(PreprocessorDefinitions) + + + + + Level3 + true + true + true + UNICODE;_UNICODE;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + true + stdcpp17 + $(ProjectDir)src\include;%(AdditionalIncludeDirectories) + NotUsing + /utf-8 %(AdditionalOptions) + + + Windows + true + true + true + winmm.lib;gdiplus.lib;gdi32.lib;user32.lib;shell32.lib;%(AdditionalDependencies) + + + $(ProjectDir)src\include;$(ProjectDir)assets\icons;%(AdditionalIncludeDirectories) + UNICODE;_UNICODE;%(PreprocessorDefinitions) + + + + + Level3 + true + true + true + UNICODE;_UNICODE;_WINDOWS;NDEBUG;%(PreprocessorDefinitions) + true + stdcpp17 + $(ProjectDir)src\include;%(AdditionalIncludeDirectories) + NotUsing + /utf-8 %(AdditionalOptions) + + + Windows + true + true + true + winmm.lib;gdiplus.lib;gdi32.lib;user32.lib;shell32.lib;%(AdditionalDependencies) + + + $(ProjectDir)src\include;$(ProjectDir)assets\icons;%(AdditionalIncludeDirectories) + UNICODE;_UNICODE;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tetris.vcxproj.filters b/Tetris.vcxproj.filters new file mode 100644 index 0000000..18eadc5 --- /dev/null +++ b/Tetris.vcxproj.filters @@ -0,0 +1,65 @@ + + + + + {0E9F8A8A-4B33-47F4-8409-BBD2E632BD02} + cpp;c;cc;cxx + + + {4040C716-0A25-434E-8225-3FB91E96C9C2} + + + {A0E8AA27-81E0-4B07-8436-84237CBFC4A8} + + + {D9E2B29D-32A7-4A92-9824-64B07CE76CEF} + + + {86ED6590-B71E-4555-A5ED-131EAB571D32} + + + {E19CF9D7-1762-45A0-AE35-9806E551112D} + + + {28A22C80-54CC-44AF-9925-926D1EE5BAE9} + + + {F7961514-73CF-48BD-A777-525FB4964E26} + h;hpp;hxx + + + {2BF6F47B-88D9-47B6-971A-54309126F736} + rc;ico;bmp;png;jpg;jpeg + + + + Source Files + Source Files + Source Files + Source Files + Source Files\app + Source Files\app + Source Files\app + Source Files\app + Source Files\common + Source Files\extensions + Source Files\logic + Source Files\logic + Source Files\render + Source Files\render + Source Files\rogue + + + Header Files + Header Files + Header Files + Header Files + Header Files + Header Files + Header Files + Header Files + + + Resource Files + + diff --git a/VS2026_RUN_GUIDE.md b/VS2026_RUN_GUIDE.md index 219cb00..f06467a 100644 --- a/VS2026_RUN_GUIDE.md +++ b/VS2026_RUN_GUIDE.md @@ -1,198 +1,191 @@ -# 在 Visual Studio 2026 中运行本项目 +# 只使用 Visual Studio 2026 运行本项目 -本文说明如何在 Visual Studio 2026 中打开、构建和运行本项目。 -本文档编写时的日期为 2026-05-08,Visual Studio 2026 已发布;Microsoft Learn 的发布历史显示 2026 年 4 月 28 日稳定通道版本为 18.5.2。 +本文说明如何只依赖 Visual Studio 2026 自带的 C++ 工具链运行本项目,不额外安装 MinGW、GCC 或其他第三方编译器。 -## 1. 项目构建方式说明 +本文档编写日期为 2026-05-08。Microsoft Learn 的发布历史显示,Visual Studio 2026 在 2026-04-28 的稳定通道版本为 18.5.2。 -本项目是一个基于 C++、Win32 API、GDI/GDI+ 和 MinGW-w64 的俄罗斯方块程序。 +## 1. 结论 -项目当前没有 Visual Studio `.sln` 或 `.vcxproj` 工程文件,推荐继续使用项目根目录已有脚本构建: +可以只用 Visual Studio 2026。 -```powershell -.\build-mingw.ps1 -``` +需要安装 Visual Studio 2026 的 `Desktop development with C++` 工作负载。该工作负载会提供本项目需要的主要工具: -构建并运行: +- `cl.exe`:Microsoft C/C++ 编译器 +- `link.exe`:Microsoft 链接器 +- `rc.exe`:Windows 资源编译器 +- Windows SDK:提供 Win32 API、GDI、GDI+ 等头文件和库 -```powershell -.\build-mingw.ps1 -Run -``` - -生成的程序位于: - -```text -.vscode-build\mingw\Tetris.exe -``` - -因为运行时需要读取 `assets/` 目录中的图片、音频和视频资源,建议从项目根目录启动程序,避免资源路径失效。 +本项目当前没有 `.sln` 或 `.vcxproj` 工程文件,因此推荐在 Visual Studio 2026 中打开文件夹,然后在 `Developer PowerShell for VS 2026` 中执行构建命令。 ## 2. 安装 Visual Studio 2026 -1. 打开 Visual Studio 2026 下载页面或 Visual Studio Installer。 +1. 打开 Visual Studio Installer。 2. 安装 Visual Studio 2026 Community、Professional 或 Enterprise 均可。 -3. 在安装器中选择 `Desktop development with C++` 工作负载。 -4. 保留默认的 Windows SDK 和 C++ 工具组件。 +3. 在工作负载页面选择 `Desktop development with C++`。 +4. 保留默认勾选的 MSVC 工具集和 Windows SDK。 5. 完成安装后启动 Visual Studio 2026。 -说明:Microsoft Learn 的 Visual Studio 安装文档建议通过工作负载选择所需功能;C++ 桌面开发应选择 C++ 桌面开发相关工作负载。Visual Studio 2026 系统要求页面说明其支持 Windows 11、Windows Server 2025/2022/2019 等 64 位系统。 +不要额外安装 MinGW。本文后续命令只使用 Visual Studio 2026 自带工具。 -## 3. 安装或确认 MinGW-w64 - -本项目的构建脚本调用的是 `g++.exe` 和 `windres.exe`,因此只安装 Visual Studio 2026 还不够,还需要 MinGW-w64。 - -推荐满足以下任一条件: - -1. `g++.exe` 和 `windres.exe` 已加入系统 `PATH`。 -2. MinGW-w64 安装在: - -```text -C:\mingw64\bin\ -``` - -可在 PowerShell 中检查: - -```powershell -g++ --version -windres --version -``` - -如果提示找不到命令,需要安装 MinGW-w64,或把 MinGW-w64 的 `bin` 目录加入系统环境变量 `PATH`。 - -## 4. 在 Visual Studio 2026 中打开项目 +## 3. 打开项目文件夹 1. 启动 Visual Studio 2026。 -2. 在开始窗口选择 `Open a local folder`,或在菜单中选择 `File -> Open -> Folder...`。 +2. 在开始窗口选择 `Open a local folder`。 3. 选择项目根目录: ```text D:\VSC_program\Tereis ``` -4. 等待 Visual Studio 扫描文件。 -5. 在 Solution Explorer 中查看 `src`、`assets`、`build-mingw.ps1` 等文件。 +4. 打开后可以在 Solution Explorer 中看到: -Microsoft Learn 说明,Visual Studio 的 `Open Folder` 模式适合打开没有专用工程文件的代码库;对于无法被 IDE 自动识别的构建系统,可以通过自定义任务配置构建命令。 +```text +src +assets +build-mingw.ps1 +build-vs2026.ps1 +VS2026_RUN_GUIDE.md +``` -## 5. 在 Visual Studio 终端中构建和运行 +说明:`build-mingw.ps1` 是旧的 MinGW 构建脚本。只使用 VS2026 时不需要运行它。 +`build-vs2026.ps1` 是本项目提供的 VS2026 专用构建脚本。 -这是最简单、最推荐的方式。 +## 4. 打开 VS2026 开发者终端 -1. 在 Visual Studio 2026 中打开菜单 `View -> Terminal`。 -2. 确认终端当前目录是项目根目录。如果不是,执行: +普通 PowerShell 通常找不到 `cl.exe` 和 `rc.exe`。要使用 VS2026 自带编译器,应打开开发者终端: + +1. 在 Visual Studio 2026 顶部菜单选择 `Tools -> Command Line -> Developer PowerShell`。 +2. 进入项目根目录: ```powershell cd D:\VSC_program\Tereis ``` -3. 只构建: +3. 检查工具是否可用: ```powershell -.\build-mingw.ps1 +cl +rc ``` -4. 构建并启动游戏: +如果能看到 Microsoft C/C++ Compiler 和 Microsoft Windows Resource Compiler 的版本信息,说明 VS2026 C++ 工具链可用。 + +## 5. 使用 VS2026 工具链构建 + +在 `Developer PowerShell for VS 2026` 中执行: ```powershell -.\build-mingw.ps1 -Run +.\build-vs2026.ps1 ``` -如果 PowerShell 阻止脚本运行,可临时使用: +构建并运行: ```powershell -powershell -NoProfile -ExecutionPolicy Bypass -File .\build-mingw.ps1 -Run +.\build-vs2026.ps1 -Run ``` -## 6. 可选:在 Visual Studio 中配置 Open Folder 构建任务 +生成结果: -如果希望在 Visual Studio 的 Open Folder 模式中通过任务执行构建,可以添加 `tasks.vs.json`。Microsoft Learn 说明,`tasks.vs.json` 用于定义自定义构建命令,`launch.vs.json` 用于定义调试启动配置。 - -可在 Visual Studio 中右键项目文件夹,选择 `Configure Tasks`,然后参考以下内容配置: - -```json -{ - "version": "0.2.1", - "tasks": [ - { - "taskName": "Build Tetris with MinGW", - "appliesTo": "/", - "type": "launch", - "command": "powershell.exe", - "args": [ - "-NoProfile", - "-ExecutionPolicy", - "Bypass", - "-File", - "${workspaceRoot}\\build-mingw.ps1" - ], - "workingDirectory": "${workspaceRoot}" - }, - { - "taskName": "Build and Run Tetris with MinGW", - "appliesTo": "/", - "type": "launch", - "command": "powershell.exe", - "args": [ - "-NoProfile", - "-ExecutionPolicy", - "Bypass", - "-File", - "${workspaceRoot}\\build-mingw.ps1", - "-Run" - ], - "workingDirectory": "${workspaceRoot}" - } - ] -} +```text +.vscode-build\vs2026\Tetris.exe ``` -注意:Visual Studio 可能把该文件放在隐藏的 `.vs` 目录中。该目录通常是本机配置,不一定需要提交到仓库。 +该脚本会递归编译 `src\source` 下所有 `.cpp` 文件,包括 `render`、`app`、`logic`、`rogue`、`common`、`extensions` 等目录,避免手动建 VS 工程时漏加源文件。 + +如果需要手动理解脚本做了什么,核心命令如下。 + +先创建输出目录: + +```powershell +New-Item -ItemType Directory -Force -Path .\.vscode-build\vs2026 +``` + +编译资源文件: + +```powershell +rc /nologo /i .\src\include /i .\assets\icons /fo .\.vscode-build\vs2026\Tetris.res .\src\resources\Tetris.rc +``` + +编译并链接 C++ 源码: + +```powershell +$sources = Get-ChildItem .\src\source -Recurse -Filter *.cpp | ForEach-Object { $_.FullName } +cl /nologo /utf-8 /std:c++17 /EHsc /Zi /Od /DUNICODE /D_UNICODE /D_WINDOWS /I .\src\include $sources .\.vscode-build\vs2026\Tetris.res /Fe:.\.vscode-build\vs2026\Tetris.exe /link /SUBSYSTEM:WINDOWS winmm.lib gdiplus.lib gdi32.lib user32.lib shell32.lib +``` + +## 6. 运行程序 + +运行时建议从项目根目录启动,因为程序会读取 `assets/` 目录中的图片、音频和视频资源。 + +```powershell +Start-Process .\.vscode-build\vs2026\Tetris.exe -WorkingDirectory . +``` + +如果直接双击 exe,可能因为工作目录不对导致背景图、音乐或视频加载失败。 ## 7. 常见问题 -### 找不到 `g++.exe` +### 找不到 `cl.exe` -原因:未安装 MinGW-w64,或 MinGW-w64 的 `bin` 目录没有加入 `PATH`。 +原因:没有在 VS2026 开发者终端中运行命令,或安装 VS2026 时没有选择 `Desktop development with C++`。 + +处理: + +1. 打开 `Tools -> Command Line -> Developer PowerShell`。 +2. 如果仍然找不到 `cl.exe`,打开 Visual Studio Installer,修改安装,勾选 `Desktop development with C++`。 + +### 找不到 `rc.exe` + +原因:Windows SDK 没有安装,或没有进入 VS2026 开发者终端。 + +处理:打开 Visual Studio Installer,确认 C++ 桌面开发工作负载中的 Windows SDK 已安装。 + +### 资源文件编译失败,提示找不到图标 + +原因:`Tetris.rc` 中引用了图标文件,资源编译命令必须包含图标目录。 + +处理:确认资源编译命令中包含: + +```powershell +/i .\assets\icons +``` + +### 程序运行后没有图片、音乐或视频 + +原因:程序没有从项目根目录启动,导致 `assets/` 相对路径无法读取。 处理: ```powershell -g++ --version +Start-Process .\.vscode-build\vs2026\Tetris.exe -WorkingDirectory . ``` -如果命令失败,请安装 MinGW-w64,或把 `C:\mingw64\bin` 加入系统 `PATH`。 +### 程序能运行、有音乐,但窗口黑屏 -### 找不到 `windres.exe` +原因通常是手动创建 Visual Studio 工程时没有把所有源文件加入编译,尤其是漏掉了这些目录: -原因:资源编译器不可用。项目需要它编译 `src\resources\Tetris.rc` 中的图标、菜单和字符串资源。 +```text +src\source\app +src\source\common +src\source\extensions +src\source\logic +src\source\render +src\source\rogue +``` -处理:确认 MinGW-w64 安装完整,并检查: +处理:不要运行手动残缺工程生成的 exe,改用 VS2026 开发者终端运行项目脚本: ```powershell -windres --version +.\build-vs2026.ps1 -Run ``` -### 程序启动后没有图片、音乐或视频 +如果一定要手动建 VS 工程,必须把 `src\source` 下所有 `.cpp` 文件递归加入项目,并把工作目录设置为项目根目录 `D:\VSC_program\Tereis`。 -原因:程序没有从项目根目录启动,导致相对路径下的 `assets/` 资源无法读取。 +### 直接按 F5 不能运行 -处理:在项目根目录执行: +原因:本项目当前没有 Visual Studio `.sln` 或 `.vcxproj` 工程文件,VS2026 不知道应该如何构建和启动。 -```powershell -.\build-mingw.ps1 -Run -``` - -或手动启动: - -```powershell -Start-Process .\.vscode-build\mingw\Tetris.exe -WorkingDirectory . -``` - -### 直接按 F5 没有运行 - -原因:本项目当前不是 Visual Studio `.sln` / `.vcxproj` 工程,Visual Studio 不一定知道应使用 `build-mingw.ps1` 构建。 - -处理:优先使用 Visual Studio 终端运行构建脚本;如果需要 IDE 菜单任务,可按第 6 节配置 `tasks.vs.json`。 +处理:使用本文的 `Developer PowerShell for VS 2026` 构建方式。后续如果需要 F5 调试体验,可以再创建 Visual Studio C++ 工程文件。 ## 8. 参考资料 @@ -200,4 +193,5 @@ Start-Process .\.vscode-build\mingw\Tetris.exe -WorkingDirectory . - Visual Studio 2026 Release History: - Visual Studio 2026 System Requirements: - Install Visual Studio: -- Create build and debug tasks for Open Folder development: +- Use the Microsoft C++ toolset from the command line: +- MSVC compiler command-line syntax: diff --git a/build-vs2026.ps1 b/build-vs2026.ps1 new file mode 100644 index 0000000..6304280 --- /dev/null +++ b/build-vs2026.ps1 @@ -0,0 +1,75 @@ +param( + [switch]$Run +) + +$ErrorActionPreference = "Stop" + +$Root = Split-Path -Parent $MyInvocation.MyCommand.Path +$ProjectDir = Join-Path $Root "src" +$IncludeDir = Join-Path $ProjectDir "include" +$SourceDir = Join-Path $ProjectDir "source" +$ResourceDir = Join-Path $ProjectDir "resources" +$AssetIconDir = Join-Path $Root "assets\icons" +$BuildDir = Join-Path $Root ".vscode-build\vs2026" +$ExePath = Join-Path $BuildDir "Tetris.exe" +$ResPath = Join-Path $BuildDir "Tetris.res" +$RcPath = Join-Path $ResourceDir "Tetris.rc" + +if (-not (Get-Command cl.exe -ErrorAction SilentlyContinue)) { + throw "cl.exe not found. Open Visual Studio 2026: Tools -> Command Line -> Developer PowerShell, then run this script again." +} + +if (-not (Get-Command rc.exe -ErrorAction SilentlyContinue)) { + throw "rc.exe not found. Install the Windows SDK from the Visual Studio Installer C++ desktop workload." +} + +New-Item -ItemType Directory -Force -Path $BuildDir | Out-Null + +$Sources = Get-ChildItem -Path $SourceDir -Recurse -Filter "*.cpp" | + Sort-Object FullName | + Select-Object -ExpandProperty FullName + +if ($Sources.Count -lt 10) { + throw "Too few source files found under src\source. The render, app, logic, rogue, common, and extension modules must all be compiled." +} + +& rc.exe ` + /nologo ` + /i $IncludeDir ` + /i $AssetIconDir ` + /fo $ResPath ` + $RcPath + +if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE +} + +& cl.exe ` + /nologo ` + /utf-8 ` + /std:c++17 ` + /EHsc ` + /Zi ` + /Od ` + /DUNICODE ` + /D_UNICODE ` + /D_WINDOWS ` + /I $IncludeDir ` + $Sources ` + $ResPath ` + /Fe:$ExePath ` + /link ` + /SUBSYSTEM:WINDOWS ` + winmm.lib ` + gdiplus.lib ` + gdi32.lib ` + user32.lib ` + shell32.lib + +if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE +} + +if ($Run) { + Start-Process -FilePath $ExePath -WorkingDirectory $Root +} diff --git a/src/include/resource.h b/src/include/resource.h index b7697c8..f4d76aa 100644 --- a/src/include/resource.h +++ b/src/include/resource.h @@ -2,18 +2,15 @@ /** * @file resource.h - * @brief 定义菜单、图标、对话框和命令等 Windows 资源编号。 + * @brief Defines Windows resource IDs for menus, icons, dialogs, commands, and strings. */ //{{NO_DEPENDENCIES}} -// Microsoft Visual C++ 生成的包含文件。 -// 供 Tetris.rc 使用 -// +// Microsoft Visual C++ generated include file. +// Used by Tetris.rc. -// 字符串资源:窗口标题等文本由 Win32 启动流程按编号读取。 #define IDS_APP_TITLE 103 -// 图标、对话框、菜单和命令编号需要与 Tetris.rc 中的资源定义保持一致。 #define IDR_MAINFRAME 128 #define IDD_TETRIS_DIALOG 102 #define IDD_ABOUTBOX 103 @@ -26,13 +23,11 @@ #define IDC_MYICON 2 #ifndef IDC_STATIC -// 静态文本控件使用 -1,表示运行时不需要通过控件 ID 单独访问。 #define IDC_STATIC -1 #endif #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -// 以下编号由资源编辑器维护,手工改动容易导致新增资源编号冲突。 #define _APS_NO_MFC 130 #define _APS_NEXT_RESOURCE_VALUE 129 #define _APS_NEXT_COMMAND_VALUE 32771 diff --git a/src/resources/Tetris.rc b/src/resources/Tetris.rc index 3512254..2f92bf4 100644 Binary files a/src/resources/Tetris.rc and b/src/resources/Tetris.rc differ