> 技术文档 > 使用Imgui和SDL2做的一个弹球小游戏-Bounze

使用Imgui和SDL2做的一个弹球小游戏-Bounze


使用Imgui和SDL2做的一个弹球小游戏-Bounze

油管上面TheCherno博主分享的一个视频FIRST GAME in C++! Did He Do a Good Job? // Code Review (C++/SDL2)里面分享了一个Github项目:
https://github.com/staticaron/Bounze
使用了Imgui和SDL2,并且可以设置音乐播放,修改音量等,玩家可以得分等,目前游戏支持Windows和Linux,稍微改一下代码还可以支持MacOS,最终支持Windows、Linux、MacOS的源码版本我已经上传至我的github上,源代码链接地址为:https://github.com/ccf19881030/Bounze,欢迎下载体验学习。

修改代码已支持MacOS

  • 1、处理编译告警错误 -Wc++11-narrowing warning
    我的MacOS(Mac Mini4)实际编译过程中遇到如下的类型转换错误:
    make之后报错如下:-Wc++11-narrowing 需要在CMakeLists.txt文件中添加预处理定义避免次错误,如下所示:
In file included from /Users/john/WorkSpace/CppProjects/Bounze/src/Ball.cpp:10:/Users/john/WorkSpace/CppProjects/Bounze/include/managers/config.h:4:10: warning: non-portable path to file \'\"mini/ini.h\"\'; specified path differs in case from file name on disk [-Wnonportable-include-path] 4 | #include \"mIni/ini.h\" | ^~~~~~~~~~~~ | \"mini/ini.h\"1 warning generated.[ 91%] Building CXX object CMakeFiles/bounze.dir/src/Bat.cpp.oIn file included from /Users/john/WorkSpace/CppProjects/Bounze/src/Bat.cpp:7:/Users/john/WorkSpace/CppProjects/Bounze/include/managers/config.h:4:10: warning: non-portable path to file \'\"mini/ini.h\"\'; specified path differs in case from file name on disk [-Wnonportable-include-path] 4 | #include \"mIni/ini.h\" | ^~~~~~~~~~~~ | \"mini/ini.h\"/Users/john/WorkSpace/CppProjects/Bounze/src/Bat.cpp:37:20: error: type \'float\' cannot be narrowed to \'int\' in initializer list [-Wc++11-narrowing] 37 | SDL_Rect rect = { GetCenter().x - GetBoundDetails().GetHalfBounds().x, GetCenter().y - GetBoundDetails().GetHalfBounds().y, m_EntityBounds.bounds.x, m_EntityBounds.bounds.y }; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/Users/john/WorkSpace/CppProjects/Bounze/src/Bat.cpp:37:20: note: insert an explicit cast to silence this issue 37 | SDL_Rect rect = { GetCenter().x - GetBoundDetails().GetHalfBounds().x, GetCenter().y - GetBoundDetails().GetHalfBounds().y, m_EntityBounds.bounds.x, m_EntityBounds.bounds.y }; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | static_cast( )/Users/john/WorkSpace/CppProjects/Bounze/src/Bat.cpp:37:73: error: type \'float\' cannot be narrowed to \'int\' in initializer list [-Wc++11-narrowing] 37 | SDL_Rect rect = { GetCenter().x - GetBoundDetails().GetHalfBounds().x, GetCenter().y - GetBoundDetails().GetHalfBounds().y, m_EntityBounds.bounds.x, m_EntityBounds.bounds.y }; |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/Users/john/WorkSpace/CppProjects/Bounze/src/Bat.cpp:37:73: note: insert an explicit cast to silence this issue 37 | SDL_Rect rect = { GetCenter().x - GetBoundDetails().GetHalfBounds().x, GetCenter().y - GetBoundDetails().GetHalfBounds().y, m_EntityBounds.bounds.x, m_EntityBounds.bounds.y }; |  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |  static_cast( )/Users/john/WorkSpace/CppProjects/Bounze/src/Bat.cpp:37:126: error: type \'float\' cannot be narrowed to \'int\' in initializer list [-Wc++11-narrowing] 37 | SDL_Rect rect = { GetCenter().x - GetBoundDetails().GetHalfBounds().x, GetCenter().y - GetBoundDetails().GetHalfBounds().y, m_EntityBounds.bounds.x, m_EntityBounds.bounds.y }; | ^~~~~~~~~~~~~~~~~~~~~~~/Users/john/WorkSpace/CppProjects/Bounze/src/Bat.cpp:37:126: note: insert an explicit cast to silence this issue 37 | SDL_Rect rect = { GetCenter().x - GetBoundDetails().GetHalfBounds().x, GetCenter().y - GetBoundDetails().GetHalfBounds().y, m_EntityBounds.bounds.x, m_EntityBounds.bounds.y }; | ^~~~~~~~~~~~~~~~~~~~~~~ | static_cast( )/Users/john/WorkSpace/CppProjects/Bounze/src/Bat.cpp:37:151: error: type \'float\' cannot be narrowed to \'int\' in initializer list [-Wc++11-narrowing] 37 | SDL_Rect rect = { GetCenter().x - GetBoundDetails().GetHalfBounds().x, GetCenter().y - GetBoundDetails().GetHalfBounds().y, m_EntityBounds.bounds.x, m_EntityBounds.bounds.y }; | ^~~~~~~~~~~~~~~~~~~~~~~/Users/john/WorkSpace/CppProjects/Bounze/src/Bat.cpp:37:151: note: insert an explicit cast to silence this issue 37 | SDL_Rect rect = { GetCenter().x - GetBoundDetails().GetHalfBounds().x, GetCenter().y - GetBoundDetails().GetHalfBounds().y, m_EntityBounds.bounds.x, m_EntityBounds.bounds.y }; | ^~~~~~~~~~~~~~~~~~~~~~~ | static_cast( )1 warning and 4 errors generated.make[2]: *** [CMakeFiles/bounze.dir/src/Bat.cpp.o] Error 1make[1]: *** [CMakeFiles/bounze.dir/all] Error 2make: *** [all] Error 2

-Wc++11-narrowing 是一个编译器警告,通常与 C++11 标准中对窄化转换(narrowing conversion)的限制有关。如果你想通过在 CMakeLists.txt 文件中添加预处理定义来避免此错误,可以使用以下方法:

修改 CMakeLists.txt
在你的 CMakeLists.txt 文件中,添加以下行以禁用该警告:

# Suppress the -Wc++11-narrowing warning based on platformif (APPLE) target_compile_options(\"${PROJECT_NAME}\" PRIVATE -Wno-c++11-narrowing)elseif (UNIX AND NOT APPLE) # Linux target_compile_options(\"${PROJECT_NAME}\" PRIVATE -Wno-c++11-narrowing)elseif (WIN32) # Windows target_compile_options(\"${PROJECT_NAME}\" PRIVATE /wd4267 /wd4996)endif()

修改后的完整CMakeLists.txt文件内容如下:

cmake_minimum_required(VERSION \"3.19.2\")set(CMAKE_MSVC_RUNTIME_LIBRARY \"MultiThreaded$<$:Debug>\")project(\"bounze\")option(BUILD_SHARED_LIBS \"\" OFF)set(SDL2IMAGE_VENDORED ON CACHE BOOL \"\" FORCE)set(SDL2IMAGE_PNG ON CACHE BOOL \"\" FORCE)set(SDL2IMAGE_AVIF OFF CACHE BOOL \"\" FORCE)set(SDL2IMAGE_JPG OFF CACHE BOOL \"\" FORCE)set(SDL2IMAGE_TIF OFF CACHE BOOL \"\" FORCE)set(SDL2IMAGE_WEBP OFF CACHE BOOL \"\" FORCE)set(SDL2IMAGE_STB OFF CACHE BOOL \"\" FORCE)set(SDL2TTF_VENDORED ON CACHE BOOL \"\" FORCE)set(SDL2MIXER_FLAC OFF CACHE BOOL \"\" FORCE)set(SDL2MIXER_MP3 OFF CACHE BOOL \"\" FORCE)set(SDL2MIXER_MOD OFF CACHE BOOL \"\" FORCE)set(SDL2MIXER_OPUS OFF CACHE BOOL \"\" FORCE)set(SDL2MIXER_MIDI OFF CACHE BOOL \"\" FORCE)set(SDL2MIXER_INSTALL OFF CACHE BOOL \"\" FORCE)add_subdirectory(vendor/SDL)add_subdirectory(vendor/SDL_image)add_subdirectory(vendor/SDL_ttf)add_subdirectory(vendor/SDL_mixer)add_subdirectory(vendor/imgui)add_subdirectory(vendor/glm)add_subdirectory(vendor/mIni)set(CMAKE_CXX_STANDARD 20)file(GLOB_RECURSE MY_SOURCES CONFIGURE_DEPENDS \"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp\")add_executable(\"${PROJECT_NAME}\" \"${MY_SOURCES}\")# target_compile_definitions(\"${PROJECT_NAME}\" PUBLIC RESOURCE_PATH=\"${CMAKE_CURRENT_SOURCE_DIR}/resources/\")target_compile_definitions(\"${PROJECT_NAME}\" PUBLIC RESOURCE_PATH=\"./resources/\")target_compile_definitions(\"${PROJECT_NAME}\" PRIVATE SDL_MAIN_HANDLED)# Suppress the -Wc++11-narrowing warning based on platformif (APPLE) target_compile_options(\"${PROJECT_NAME}\" PRIVATE -Wno-c++11-narrowing)elseif (UNIX AND NOT APPLE) # Linux target_compile_options(\"${PROJECT_NAME}\" PRIVATE -Wno-c++11-narrowing)elseif (WIN32) # Windows target_compile_options(\"${PROJECT_NAME}\" PRIVATE /wd4267 /wd4996)endif()target_include_directories(\"${PROJECT_NAME}\" PUBLIC \"${CMAKE_CURRENT_SOURCE_DIR}/include\")target_include_directories(\"${PROJECT_NAME}\" PUBLIC \"${CMAKE_CURRENT_SOURCE_DIR}/vendor/SDL_mixer/include\")target_include_directories(\"${PROJECT_NAME}\" PUBLIC \"${CMAKE_CURRENT_SOURCE_DIR}/vendor/SDL_ttf\")target_include_directories(\"${PROJECT_NAME}\" PUBLIC \"${CMAKE_CURRENT_SOURCE_DIR}/vendor/SDL_image/include\")target_link_libraries(\"${PROJECT_NAME}\" PRIVATE SDL2::SDL2-static SDL2_image::SDL2_image-static SDL2_ttf::SDL2_ttf-static SDL2_mixer::SDL2_mixer-static imgui mINI glm)
  • 2、需要注释掉源代码Bounze/src/levels/About.cpp中的一行代码#error \"Unsupported OS\",如下所示:
void openUrlAllPlatforms( std::string url ){#ifdef _WIN32std::string command = \"start \";command += url;system( command.c_str() );#elif __linux__std::string command = \"xdg-open \";command += url;system( command.c_str() );#else// #error \"Unsupported OS\"#endif}}

或者更近一步修改成如下的代码已支持About菜单项在MacOS中打开代码和音乐等资源网址:

void openUrlAllPlatforms( std::string url ){#ifdef _WIN32std::string command = \"start \";command += url;system( command.c_str() );#elif __linux__std::string command = \"xdg-open \";command += url;system( command.c_str() );#else#ifdef __APPLE__#include #if TARGET_OS_MAC // macOS-specific code std::string command = \"open \"; command += url; system( command.c_str() );#endif#endif#endif}

不然会报如下的错误:

/Users/john/WorkSpace/CppProjects/Bounze/include/levels/ILevel.h:18:15: note: overridden virtual function is here 18 | virtual void Unload() = 0; |^4 warnings generated.[ 92%] Building CXX object CMakeFiles/bounze.dir/src/levels/About.cpp.oIn file included from /Users/john/WorkSpace/CppProjects/Bounze/src/levels/About.cpp:9:/Users/john/WorkSpace/CppProjects/Bounze/include/managers/config.h:4:10: warning: non-portable path to file \'\"mini/ini.h\"\'; specified path differs in case from file name on disk [-Wnonportable-include-path] 4 | #include \"mIni/ini.h\" | ^~~~~~~~~~~~ | \"mini/ini.h\"/Users/john/WorkSpace/CppProjects/Bounze/src/levels/About.cpp:59:2: error: \"Unsupported OS\" 59 | #error \"Unsupported OS\" | ^1 warning and 1 error generated.make[2]: *** [CMakeFiles/bounze.dir/src/levels/About.cpp.o] Error 1make[1]: *** [CMakeFiles/bounze.dir/all] Error 2make: *** [all] Error 2

发现现在的AI对于写代码还有解决错误实在是太友好了,比如在VSCode中集成Github Copilot或者CodeMate能省事不少,比如说编译报错,代码格式化,CMake编译问题、C++问题等等。

紧接着MacOS和Linux编译运行的流程一样:

  1. Create a folder /build
  2. Enter the folder cd build
  3. Run the cmake command cmake ..
  4. Make the build file make
    编译完成生成bounze二进制文件之后,需要将资源文件夹resources和二进制文件bounze放在同一目录下,不然直接运行bounze二进制文件,会报如下错误:
    使用Imgui和SDL2做的一个弹球小游戏-Bounze

在我的Mac Mini4中的运行截图如下所示:
使用Imgui和SDL2做的一个弹球小游戏-Bounze

Bounze 游戏

游戏开始界面菜单

使用Imgui和SDL2做的一个弹球小游戏-Bounze

How to Play.

  • The ball bounces off the bat randomly in normal mode.
  • If boost is active, the ball bounces off according to where it collides with the bat.
  • Balancing the ball on bat and destroying the diamonds using the boosted ball gives points.
  • Get the highscore.

  • I left the debug imgui in the game where you can modify the volumes etc. Press TAB to access.

How to build.

Windows + Visual Studio

  1. Open the folder in visual studio as Cmake Project.
  2. Ctrl + S on the CMakeLists.txt file to build the project.
  3. Run bounze.exe.

NOTE : Copy the /resources folder in same directory as the .exe file.

LINUX

  1. Create a folder /build
  2. Enter the folder cd build
  3. Run the cmake command cmake ..
  4. Make the build file make

macOS

  1. Create a folder /build
  2. Enter the folder cd build
  3. Run the cmake command cmake ..
  4. Make the build file make

NOTE : Copy the /resources folder in same directory as the .exe file.

参考上述https://github.com/staticaron/Bounze的README.md文件,下载上述项目后,在Window11中使用VS2022打开下载的目录,以CMake工程打开;
接着打开CMakeLists.txt,执行Ctrl+S编译,生成Makefile等工程文件;最后将代码根目录下的resources资源文件夹拷贝到和bounze.exe同级目录,运行bounze.exe可执行程序
使用Imgui和SDL2做的一个弹球小游戏-Bounze
然后鼠标双击bounze.exe可执行程序,
使用Imgui和SDL2做的一个弹球小游戏-Bounze
如果不拷贝resources资源文件夹,直接鼠标双击bounze.exe可执行程序,会报如下的错误:
使用Imgui和SDL2做的一个弹球小游戏-Bounze

ERROR loading the font at : ./resources/fonts/mightysouly.ttf Couldn\'t open ./resources/fonts/mightysouly.ttf

加载资源文件报错,因为找不到资源文件所在目录。