1.1 Pacman

1.1.1 准备

源码:

Kerndog73/EnTT-Pacman: An example of how to use … - GitHub
https://github.com/Kerndog73/EnTT-Pacman

安装 vcpkg:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
.\bootstrap-vcpkg.bat

参考:

vcpkg安装遇到的问题记录 - JK-Z - 博客园
https://www.cnblogs.com/JK-Z/p/12264762.html

安装工程:

git clone https://github.com/Kerndog73/EnTT-Pacman.git
cd EnTT-Pacman/build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
./pacman

使用命令行是不太靠谱,很容易克隆不到……
最好还是先下载 zip,然后 cd 到解压出来的库里面

PS D:\Tools\vcpkg-master> .\vcpkg install sdl2
Computing installation plan...
The following packages will be built and installed:sdl2[core]:x86-windows -> 2.0.20* vcpkg-cmake[core]:x64-windows -> 2022-01-19* vcpkg-cmake-config[core]:x64-windows -> 2022-02-06
Additional packages (*) will be modified to complete this operation.
Detecting compiler hash for triplet x64-windows...
A suitable version of git was not found (required v2.35.1). Downloading portable git v2.35.1...
Extracting git...
A suitable version of 7zip was not found (required v19.0.0). Downloading portable 7zip v19.0.0...
Downloading 7zip...https://www.7-zip.org/a/7z1900-x64.msi -> D:\Tools\vcpkg-master\downloads\7z1900-x64.msi
Extracting 7zip...
-- Automatically setting HTTP(S)_PROXY environment variables to 127.0.0.1:7890
A suitable version of powershell-core was not found (required v7.2.1). Downloading portable powershell-core v7.2.1...
Downloading powershell-core...https://github.com/PowerShell/PowerShell/releases/download/v7.2.1/PowerShell-7.2.1-win-x86.zip -> D:\Tools\vcpkg-master\downloads\PowerShell-7.2.1-win-x86.zip
Extracting powershell-core...
Detecting compiler hash for triplet x86-windows...
Restored 0 packages from C:\Users\18221\AppData\Local\vcpkg\archives in 654.9 us. Use --debug to see more details.
Starting package 1/3: vcpkg-cmake:x64-windows
Building package vcpkg-cmake[core]:x64-windows...
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake_x64-windows/share/vcpkg-cmake/vcpkg_cmake_configure.cmake
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake_x64-windows/share/vcpkg-cmake/vcpkg_cmake_build.cmake
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake_x64-windows/share/vcpkg-cmake/vcpkg_cmake_install.cmake
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake_x64-windows/share/vcpkg-cmake/vcpkg_cmake_get_vars.cmake
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake_x64-windows/share/vcpkg-cmake/cmake_get_vars
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake_x64-windows/share/vcpkg-cmake/cmake_get_vars/CMakeLists.txt
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake_x64-windows/share/vcpkg-cmake/vcpkg-port-config.cmake
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake_x64-windows/share/vcpkg-cmake/copyright
-- Performing post-build validation
-- Performing post-build validation done
Stored binary cache: C:\Users\18221\AppData\Local\vcpkg\archives\46\462fcc355ce001e0fc8be8a27307ded83503a18a3c16d1a10473fc3036040c32.zip
Installing package vcpkg-cmake[core]:x64-windows...
Elapsed time for package vcpkg-cmake:x64-windows: 633.7 ms
Starting package 2/3: vcpkg-cmake-config:x64-windows
Building package vcpkg-cmake-config[core]:x64-windows...
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake-config_x64-windows/share/vcpkg-cmake-config/vcpkg_cmake_config_fixup.cmake
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake-config_x64-windows/share/vcpkg-cmake-config/vcpkg-port-config.cmake
-- Installing: D:/Tools/vcpkg-master/packages/vcpkg-cmake-config_x64-windows/share/vcpkg-cmake-config/copyright
-- Performing post-build validation
-- Performing post-build validation done
Stored binary cache: C:\Users\18221\AppData\Local\vcpkg\archives\38\38dcd680d8ba565bcf7347013545e6e6695b723804eea0dba27afb4323071cd9.zip
Installing package vcpkg-cmake-config[core]:x64-windows...
Elapsed time for package vcpkg-cmake-config:x64-windows: 636.3 ms
Starting package 3/3: sdl2:x86-windows
Building package sdl2[core]:x86-windows...
-- Downloading https://github.com/libsdl-org/SDL/archive/release-2.0.20.tar.gz -> libsdl-org-SDL-release-2.0.20.tar.gz...
-- Extracting source D:/Tools/vcpkg-master/downloads/libsdl-org-SDL-release-2.0.20.tar.gz
-- Applying patch 0001-sdl2-Enable-creation-of-pkg-cfg-file-on-windows.patch
-- Applying patch 0002-sdl2-skip-ibus-on-linux.patch
-- Applying patch 0003-sdl2-disable-sdlmain-target-search-on-uwp.patch
-- Applying patch 0004-Define-crt-macros.patch
-- Applying patch 0005-Fix-uwp-joystick.patch
-- Applying patch 0006-Update-SDL_sysurl.cpp.patch
-- Using source at D:/Tools/vcpkg-master/buildtrees/sdl2/src/ase-2.0.20-4d7f28b96f.clean
-- Configuring x86-windows
-- Building x86-windows-dbg
-- Building x86-windows-rel
CMake Warning at scripts/cmake/vcpkg_copy_pdbs.cmake:70 (message):Could not find a matching pdb file for:D:/Tools/vcpkg-master/packages/sdl2_x86-windows/bin/SDL2.dllD:/Tools/vcpkg-master/packages/sdl2_x86-windows/debug/bin/SDL2d.dllCall Stack (most recent call first):ports/sdl2/portfile.cmake:87 (vcpkg_copy_pdbs)scripts/ports.cmake:145 (include)-- Fixing pkgconfig file: D:/Tools/vcpkg-master/packages/sdl2_x86-windows/lib/pkgconfig/sdl2.pc
-- Downloading https://repo.msys2.org/mingw/i686/mingw-w64-i686-pkg-config-0.29.2-3-any.pkg.tar.zst;https://www2.futureware.at/~nickoe/msys2-mirror/mingw/i686/mingw-w64-i686-pkg-config-0.29.2-3-any.pkg.tar.zst;https://mirror.yandex.ru/mirrors/msys2/mingw/i686/mingw-w64-i686-pkg-config-0.29.2-3-any.pkg.tar.zst;https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/i686/mingw-w64-i686-pkg-config-0.29.2-3-any.pkg.tar.zst;https://mirrors.ustc.edu.cn/msys2/mingw/i686/mingw-w64-i686-pkg-config-0.29.2-3-any.pkg.tar.zst;https://mirror.bit.edu.cn/msys2/mingw/i686/mingw-w64-i686-pkg-config-0.29.2-3-any.pkg.tar.zst;https://mirror.selfnet.de/msys2/mingw/i686/mingw-w64-i686-pkg-config-0.29.2-3-any.pkg.tar.zst;https://mirrors.sjtug.sjtu.edu.cn/msys2/mingw/i686/mingw-w64-i686-pkg-config-0.29.2-3-any.pkg.tar.zst -> msys-mingw-w64-i686-pkg-config-0.29.2-3-any.pkg.tar.zst...
-- Downloading https://repo.msys2.org/mingw/i686/mingw-w64-i686-libwinpthread-git-9.0.0.6373.5be8fcd83-1-any.pkg.tar.zst;https://www2.futureware.at/~nickoe/msys2-mirror/mingw/i686/mingw-w64-i686-libwinpthread-git-9.0.0.6373.5be8fcd83-1-any.pkg.tar.zst;https://mirror.yandex.ru/mirrors/msys2/mingw/i686/mingw-w64-i686-libwinpthread-git-9.0.0.6373.5be8fcd83-1-any.pkg.tar.zst;https://mirrors.tuna.tsinghua.edu.cn/msys2/mingw/i686/mingw-w64-i686-libwinpthread-git-9.0.0.6373.5be8fcd83-1-any.pkg.tar.zst;https://mirrors.ustc.edu.cn/msys2/mingw/i686/mingw-w64-i686-libwinpthread-git-9.0.0.6373.5be8fcd83-1-any.pkg.tar.zst;https://mirror.bit.edu.cn/msys2/mingw/i686/mingw-w64-i686-libwinpthread-git-9.0.0.6373.5be8fcd83-1-any.pkg.tar.zst;https://mirror.selfnet.de/msys2/mingw/i686/mingw-w64-i686-libwinpthread-git-9.0.0.6373.5be8fcd83-1-any.pkg.tar.zst;https://mirrors.sjtug.sjtu.edu.cn/msys2/mingw/i686/mingw-w64-i686-libwinpthread-git-9.0.0.6373.5be8fcd83-1-any.pkg.tar.zst -> msys-mingw-w64-i686-libwinpthread-git-9.0.0.6373.5be8fcd83-1-any.pkg.tar.zst...
-- Using msys root at D:/Tools/vcpkg-master/downloads/tools/msys2/9a1ec3f33446b195
-- Fixing pkgconfig file: D:/Tools/vcpkg-master/packages/sdl2_x86-windows/debug/lib/pkgconfig/sdl2.pc
-- Performing post-build validation
-- Performing post-build validation done
Stored binary cache: C:\Users\18221\AppData\Local\vcpkg\archives\a5\a57c81eb0679aa96746a5c5f6b56b2582c124e3be3b136032ab41b3bb702c2f1.zip
Installing package sdl2[core]:x86-windows...
Elapsed time for package sdl2:x86-windows: 2.912 minTotal elapsed time: 7.466 minThe package sdl2 provides CMake targets:find_package(SDL2 CONFIG REQUIRED)target_link_libraries(main PRIVATE SDL2::SDL2 SDL2::SDL2main)

我还以为我没下载成功,毕竟看到了一个 warning
但是之后我再次下载的时候又提示我已经下好了

Computing installation plan...
The following packages are already installed:sdl2[core]:x86-windows -> 2.0.20
Package sdl2:x86-windows is already installed
Restored 0 packages from C:\Users\18221\AppData\Local\vcpkg\archives in 282.8 us. Use --debug to see more details.Total elapsed time: 50.33 msThe package sdl2 provides CMake targets:find_package(SDL2 CONFIG REQUIRED)target_link_libraries(main PRIVATE SDL2::SDL2 SDL2::SDL2main)

但是真正去编译的时候又跟我说没有

PS D:\Tools\vcpkg-master> cd D:\Documents\ECSProject\EnTT-Pacman-master\build
PS D:\Documents\ECSProject\EnTT-Pacman-master\build> cmake -DCMAKE_BUILD_TYPE=Release ..
-- Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.22000.
Finding SDL2
CMake Error at D:/Tools/CMake/share/cmake-3.23/Modules/FindPackageHandleStandardArgs.cmake:230 (message):Could NOT find SDL2 (missing: SDL2_LIBRARY SDL2_INCLUDE_DIR)
Call Stack (most recent call first):D:/Tools/CMake/share/cmake-3.23/Modules/FindPackageHandleStandardArgs.cmake:594 (_FPHSA_FAILURE_MESSAGE)cmake/modules/FindSDL2.cmake:173 (FIND_PACKAGE_HANDLE_STANDARD_ARGS)CMakeLists.txt:73 (find_package)-- Configuring incomplete, errors occurred!
See also "D:/Documents/ECSProject/EnTT-Pacman-master/build/CMakeFiles/CMakeOutput.log".
See also "D:/Documents/ECSProject/EnTT-Pacman-master/build/CMakeFiles/CMakeError.log".

我也加好了 vcpkg 的环境变量
sdl2 的环境变量我也试过了 ...\vcpkg-master\packages\sdl2_x86-windows 或者 ...\vcpkg-master\packages\sdl2_x86-windows\bin

之后我看那个 FindSDL2.cmake 中好像需要 SDL2_PATH,我就建了个,也还是不行
我再看 missing: SDL2_LIBRARY SDL2_INCLUDE_DIR,感觉又可能是需要建这两个

结果还是不行

指令果然又靠不住啊……还是用 GUI 吧

构建了之后在本地调试,报错说没找到 sdl2 的头文件
似乎头文件的文件夹还要再深一层

再本地调试,没头文件问题了,但是还是有别的问题

严重性  代码  说明  项目  文件  行   禁止显示状态
错误  LNK1107 文件无效或损坏: 无法在 0x2D8 处读取  pacman  D:\Tools\vcpkg-master\packages\sdl2_x86-windows\bin\SDL2.dll    1

看上去是 sdl2 本身的问题啊
哦,不对,这个是我的 SDL2MAIN_LIBRARY 选的,说明我其实不应该选它
思考……

Selecting Windows SDK version 10.0.19041.0 to target Windows 10.0.22000.
Finding SDL2
Configuring done
CMake Warning at CMakeLists.txt:79 (target_link_libraries):Target "pacman" requests linking to directory"D:/Tools/vcpkg-master/packages/sdl2_x86-windows/lib".  Targets may linkonly to libraries.  CMake is dropping the item.CMake Warning at CMakeLists.txt:79 (target_link_libraries):Target "pacman" requests linking to directory"D:/Tools/vcpkg-master/packages/sdl2_x86-windows/lib".  Targets may linkonly to libraries.  CMake is dropping the item.CMake Warning at CMakeLists.txt:79 (target_link_libraries):Target "pacman" requests linking to directory"D:/Tools/vcpkg-master/packages/sdl2_x86-windows/lib".  Targets may linkonly to libraries.  CMake is dropping the item.CMake Warning at CMakeLists.txt:79 (target_link_libraries):Target "pacman" requests linking to directory"D:/Tools/vcpkg-master/packages/sdl2_x86-windows/lib".  Targets may linkonly to libraries.  CMake is dropping the item.Generating done

这样连会报错,难道 SDL2_LIBRARY 指的不是 lib 文件夹而是整个 sdl2?
一个个试:
.../vcpkg-master/packages/sdl2_x86-windows 不行
.../vcpkg-master/packages/sdl2_x86-windows/lib 不行
.../vcpkg-master/packages/sdl2_x86-windows/lib/SDL2.lib 不行
.../vcpkg-master/packages/sdl2_x86-windows/bin/SDL2.dll 不行

啊……那就真不知道他到底要什么了

我感觉果然还是取 .lib 的路径最靠谱
但是他的报错是这样子的

严重性  代码  说明  项目  文件  行   禁止显示状态
错误  LNK2019 无法解析的外部符号 SDL_UpdateTexture,函数 "class std::unique_ptr<struct SDL_Texture,struct SDL::DeleteTexture> __cdecl SDL::loadTexture(struct SDL_Renderer *,unsigned char const *,unsigned __int64)" (?loadTexture@SDL@@YA?AV?$unique_ptr@USDL_Texture@@UDeleteTexture@SDL@@@std@@PEAUSDL_Renderer@@PEBE_K@Z) 中引用了该符号  pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\sdl_load_texture.obj   1
错误  LNK2019 无法解析的外部符号 main,函数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) 中引用了该符号  pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\MSVCRTD.lib(exe_main.obj)  1
错误  LNK2019 无法解析的外部符号 SDL_CreateRenderer,函数 "public: void __cdecl Application::run(void)" (?run@Application@@QEAAXXZ) 中引用了该符号   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_CreateTexture,函数 "class std::unique_ptr<struct SDL_Texture,struct SDL::DeleteTexture> __cdecl SDL::loadTexture(struct SDL_Renderer *,unsigned char const *,unsigned __int64)" (?loadTexture@SDL@@YA?AV?$unique_ptr@USDL_Texture@@UDeleteTexture@SDL@@@std@@PEAUSDL_Renderer@@PEBE_K@Z) 中引用了该符号  pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\sdl_load_texture.obj   1
错误  LNK2019 无法解析的外部符号 SDL_CreateWindow,函数 "public: void __cdecl Application::run(void)" (?run@Application@@QEAAXXZ) 中引用了该符号 pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_DestroyRenderer,函数 "public: void __cdecl SDL::DeleteRenderer::operator()(struct SDL_Renderer *)const " (??RDeleteRenderer@SDL@@QEBAXPEAUSDL_Renderer@@@Z) 中引用了该符号  pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2001 无法解析的外部符号 SDL_DestroyTexture    pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\sdl_load_texture.obj   1
错误  LNK2019 无法解析的外部符号 SDL_DestroyTexture,函数 "public: void __cdecl SDL::DeleteTexture::operator()(struct SDL_Texture *)const " (??RDeleteTexture@SDL@@QEBAXPEAUSDL_Texture@@@Z) 中引用了该符号   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_DestroyWindow,函数 "public: void __cdecl SDL::DeleteWindow::operator()(struct SDL_Window *)const " (??RDeleteWindow@SDL@@QEBAXPEAUSDL_Window@@@Z) 中引用了该符号    pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_GetDisplayUsableBounds,函数 "int __cdecl `anonymous namespace'::getScaleFactor(void)" (?getScaleFactor@?A0x04216aae@@YAHXZ) 中引用了该符号   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2001 无法解析的外部符号 SDL_GetError  pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\sdl_load_texture.obj   1
错误  LNK2001 无法解析的外部符号 SDL_GetError  pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\sdl_quad_writer.obj    1
错误  LNK2019 无法解析的外部符号 SDL_GetError,函数 "void __cdecl SDL::raise(void)" (?raise@SDL@@YAXXZ) 中引用了该符号   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_Init,函数 "public: __cdecl Application::Application(void)" (??0Application@@QEAA@XZ) 中引用了该符号    pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_PollEvent,函数 "public: void __cdecl Application::run(void)" (?run@Application@@QEAAXXZ) 中引用了该符号    pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_Quit,函数 "public: __cdecl Application::~Application(void)" (??1Application@@QEAA@XZ) 中引用了该符号   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_RenderClear,函数 "public: void __cdecl Application::run(void)" (?run@Application@@QEAAXXZ) 中引用了该符号  pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_RenderCopyEx,函数 "public: void __cdecl SDL::QuadWriter::render(void)const " (?render@QuadWriter@SDL@@QEBAXXZ) 中引用了该符号 pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\sdl_quad_writer.obj    1
错误  LNK2019 无法解析的外部符号 SDL_RenderPresent,函数 "public: void __cdecl Application::run(void)" (?run@Application@@QEAAXXZ) 中引用了该符号    pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_RenderSetLogicalSize,函数 "public: void __cdecl Application::run(void)" (?run@Application@@QEAAXXZ) 中引用了该符号 pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_SetRenderDrawColor,函数 "public: void __cdecl Application::run(void)" (?run@Application@@QEAAXXZ) 中引用了该符号   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\app.obj    1
错误  LNK2019 无法解析的外部符号 SDL_SetTextureBlendMode,函数 "class std::unique_ptr<struct SDL_Texture,struct SDL::DeleteTexture> __cdecl SDL::loadTexture(struct SDL_Renderer *,unsigned char const *,unsigned __int64)" (?loadTexture@SDL@@YA?AV?$unique_ptr@USDL_Texture@@UDeleteTexture@SDL@@@std@@PEAUSDL_Renderer@@PEBE_K@Z) 中引用了该符号    pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\sdl_load_texture.obj   1
错误  LNK1120 19 个无法解析的外部命令   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\Debug\pacman.exe   1
警告  LNK4272 库计算机类型“x86”与目标计算机类型“x64”冲突  pacman  D:\Tools\vcpkg-master\packages\sdl2_x86-windows\lib\SDL2.lib    1

我试试换成我自己下载的 sdl2

https://www.libsdl.org/download-2.0.php

这回好了……我才发现自己下载的 sdl2 的 lib 文件有区分 main,这才是环境变量区分 MAIN 的意义啊……vcpkg 你怎么回事

但是之后还有问题……

严重性  代码  说明  项目  文件  行   禁止显示状态
错误  LNK2019 无法解析的外部符号 main,函数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) 中引用了该符号  pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\MSVCRTD.lib(exe_main.obj)  1
错误  LNK1120 1 个无法解析的外部命令    pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\Debug\pacman.exe   1
警告  C4267   “参数”: 从“size_t”转换到“int”,可能丢失数据   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\src\util\sdl_load_texture.cpp    36

挺无敌的,main 函数都识别不了

根据这个改了

https://blog.csdn.net/weixin_45189666/article/details/116563083

然后居然又出来了 sdl2 的问题……我无语了,还以为我搞定了

严重性  代码  说明  项目  文件  行   禁止显示状态
错误  LNK1107 文件无效或损坏: 无法在 0x2D8 处读取  pacman  D:\Tools\vcpkg-master\packages\sdl2_x86-windows\bin\SDL2.dll    1
警告  C4267   “参数”: 从“size_t”转换到“int”,可能丢失数据   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\src\util\sdl_load_texture.cpp    36

但是首先确定我这个 sdl2 库是没问题的

cmake 用的 sdl2.dll 是 vcpkg 的,gui 里面没地方给我填 dll 的路径,但是我 lib 的路径全都填的自己的
如果真的是 vcpkg 的问题的话,那我应该 dll 也应该用自己的,可是我改不了
怎么会有这种操作啊,简直无敌

CMake 里面都没给出来的变量,它自己就配好了,我觉得这就是有东西干扰了
刚好我看了工程里面的 cmake 文件夹里面有它自己的寻找 SDL2 的文件,我不知道我在用 gui 的时候这个文件会不会起什么作用

这个文件的内容在谷歌上面很常见

我在想,如果我 CMake 里面指定了 dll 的位置,那么我会不会覆盖掉其他所有设置……

于是我新建了一个 SDL2_PATH

然后报错

严重性  代码  说明  项目  文件  行   禁止显示状态
错误  LNK2019 无法解析的外部符号 main,函数 "int __cdecl invoke_main(void)" (?invoke_main@@YAHXZ) 中引用了该符号  pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\MSVCRTD.lib(exe_main.obj)  1
错误  LNK1120 1 个无法解析的外部命令    pacman  D:\Documents\ECSProject\EnTT-Pacman-master\build\Debug\pacman.exe   1
警告  C4267   “参数”: 从“size_t”转换到“int”,可能丢失数据   pacman  D:\Documents\ECSProject\EnTT-Pacman-master\src\util\sdl_load_texture.cpp    36

那就把之前改过的东西改回来

哦……看了一下,重新生成之后,链接器都会变回控制台
嗯……
之后改了好多的链接器都不行……难道这个游戏工程的入口很特别?

我感觉好像也没问题啊……

然后我按照这个方法 4 来

https://www.cnblogs.com/eve612/p/13823073.html

原先是这样

然后改成这样

没用捏……

哦,有没有一种可能,我不能用 visualstudio
毕竟游戏项目的首界面在 cmake 构建完之后直接输入指令开启游戏的
让我试试

好吧,我放弃了

1.1.2 脑运行

一开始是 app,然后 run(),那就看 Application

然后可以发现有挺多 sdl 的 api 的……我觉得我应该尽量不去深究这些 api,知道作用就好了……

这个 run() 的主循环好厉害
使用了一个计数器实现逻辑帧和渲染帧的分离

  while (!quit) {FrameCap sync{fps};SDL_Event e;while (SDL_PollEvent(&e)) {if (e.type == SDL_QUIT) {quit = true;break;} else if (e.type == SDL_KEYDOWN) {game.input(e.key.keysym.scancode);}}// Game::logic is called once for each tile// Game::render is called for each pixel between tilesif (frame % tileSize == 0) {if (!game.logic()) {quit = true;}}SDL_CHECK(SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, 255));SDL_CHECK(SDL_RenderClear(renderer.get()));game.render(writer, frame % tileSize);++frame;SDL_RenderPresent(renderer.get());}

然后 sdl 也有内置的事件机制哦

逻辑还在 game 里面,那就看 Game

const entt::entity player = makePlayer(reg);

首先是,实体类就是 entt::entity

entt::entity makePlayer(entt::registry &reg) {const entt::entity e = reg.create();reg.emplace<Player>(e);reg.emplace<DesiredDir>(e, playerSpawnDir);reg.emplace<ActualDir>(e, playerSpawnDir);reg.emplace<Position>(e, playerSpawnPos);reg.emplace<PlayerSprite>(e, animera::SpriteID::pacman_beg_);return e;
}

然后组件是用 entt::registry 存放的
组件本身就是一个结构体,声明放在头文件中,不需要定义

const entt::entity blinky = makeBlinky(reg, player);

创建实体就在一个仓库中 .create(),返回一个 entt::entity

可以使用实体作为另一个实体的组件

bool Game::logic() {// The order of systems is very important in an ECS. Each system reads some// state and modifies some state. If the state isn't read and modified in the// right order, subtle bugs can occur. Make sure that the order of systems is// easy to see (i.e. not hidden away by some abstraction that sets the order// for you). Always think carefully about the order that systems should be in.// It's OK to keep some game state outside of the ECS (e.g. maze, dots,// dotSprite) but try to keep as much state within the ECS as you can.// Keeping too much state outside of the ECS can lead to problems.// For example: `dots` is the amount of dots eaten by the player. If there// were more than one player, then each player might want to keep track of how// many dots they've eaten. So `dots` would have to be moved into a componentif (state != State::playing) {return true;}if (scattering) {if (ticks >= scatterTicks) {ghostChase(reg);ticks = 0;scattering = false;}} else {if (ticks >= chaseTicks) {ghostScatter(reg);ticks = 0;scattering = true;}}++ticks;movement(reg);wallCollide(reg, maze);dots += eatDots(reg, maze);if (eatEnergizer(reg, maze)) {ghostScared(reg);}ghostScaredTimeout(reg);enterHouse(reg);setBlinkyChaseTarget(reg);setPinkyChaseTarget(reg);setInkyChaseTarget(reg);setClydeChaseTarget(reg);setScaredTarget(reg, maze, rand);setScatterTarget(reg);setEatenTarget(reg);leaveHouse(reg);pursueTarget(reg, maze);const GhostCollision collision = playerGhostCollide(reg);if (collision.type == GhostCollision::Type::eat) {ghostEaten(reg, collision.ghost);}if (collision.type == GhostCollision::Type::lose) {state = State::lost;} else if (dots == dotsInMaze) {state = State::won;}return true;
}

主逻辑就是所有系统排列下来

值得注意的是,接受输入的系统和逻辑中顺序排列的系统是分开的

void Game::input(const SDL_Scancode key) {if (state == State::playing) {playerInput(reg, key);}
}

挨个挨个看吧

运动系统

void movement(entt::registry &reg) {auto view = reg.view<Position, ActualDir>();for (const entt::entity e : view) {Pos &pos = view.get<Position>(e).p;const Dir dir = view.get<ActualDir>(e).d;pos += toPos(dir);// The tunnel.// This assumes the exact position of the tunnel.// It's good enough for this simple game but a more robust solution might// involve making the tunnel into an entityif (pos.y == 10) {if (pos.x <= -1 && dir == Dir::left) {pos.x = 19;} else if (pos.x >= 19 && dir == Dir::right) {pos.x = -1;}}}
}

取到 gamereg,这个 reg 应该是存着场景中所有实体引用
刚开始看,也没看到内部修改 gamereg 的逻辑,全是引用传下去各个系统里面改hhh,不管了

.view<T>() 用来取 registry 中包含这些组件的实体

已知实体,使用 view 类的方法 .get<T>() 获得组件
为啥不能直接访问实体的 reg 呢……估计 view 类中写好的方法更好吧

撞墙检测

void wallCollide(entt::registry &reg, const MazeState &maze) {auto view = reg.view<Position, ActualDir, DesiredDir>();for (const entt::entity e : view) {const Pos pos = view.get<Position>(e).p;const Dir desiredDir = view.get<DesiredDir>(e).d;if (canMove(reg, maze, e, pos, desiredDir)) {view.get<ActualDir>(e).d = desiredDir;continue;}const Dir prevDir = view.get<ActualDir>(e).d;if (canMove(reg, maze, e, pos, prevDir)) {continue;}view.get<ActualDir>(e).d = Dir::none;}
}

如果向期望运动方向上运动不会发生碰撞,那么实际运动方向就是期望运动方向
如果向期望运动方向上运动会发生碰撞,就抛弃期望运动方向,检查上一次的实际运动方向,如果向上一次的实际运动方向上运动不会发生碰撞,那么实际运动方向就是上一次的实际运动方向;否则实际运动方向为零

能变速就变速,不能变速就原速,不能原速就停

吃豆

一开始看到还以为是,maze 是一个 PosTileMap
然后去看 maze,发现是个 Grid 类重载了 [] 而已

public:Grid(): size{0, 0}, storage{} {}
private:Pos size;std::vector<Elem> storage;

一开始看到这个还以为是使用了两个 {}storage 初始化
我还以为是什么神奇的新特性,原来后面那个花括号时空的函数体hhhh

他这个运算符重载还挺厉害的

  Elem &operator[](const std::size_t i) {return const_cast<Elem &>(std::as_const(*this)[i]);}Elem &operator[](const Pos pos) {return const_cast<Elem &>(std::as_const(*this)[pos]);}const Elem &operator[](const std::size_t i) const {assert(!outOfRange(i));return storage[i];}const Elem &operator[](const Pos pos) const {assert(!outOfRange(pos));return storage[pos.y * size.x + pos.x];}

先传给操作常量的函数,然后再用 const_cast 把常量返回值的 const 去掉
const 函数中,因为 *thisstd::as_const 视为常量,所以接下来会跳转到 const 的重载函数
这样就完成了 const 函数的封装

一个地图格有不同类型,比如食物格、能量格或者空格
小游戏嘛,就直接把物品绑定到格子上了

如果吃到了豆子,那么所有鬼都会进入受惊模式,已经处于受惊模式的鬼的受惊计时器会延长剩余时间
碰到了处于受惊模式的鬼就可以把这个鬼吃掉

//
//  change_ghost_mode.hpp
//  EnTT Pacman
//
//  Created by Indiana Kernick on 29/9/18.
//  Copyright © 2018 Indiana Kernick. All rights reserved.
//#ifndef SYS_CHANGE_GHOST_MODE_HPP
#define SYS_CHANGE_GHOST_MODE_HPP#include <entt/entity/fwd.hpp>// This is called when pacman eats an energizer. All ghosts in chase or scatter
// mode will be put into scared mode. Ghosts that are already in scared mode
// will have there scared timer extended
void ghostScared(entt::registry &);// Ghosts in scared mode have a timer. When the timer runs out, they will enter
// chase mode.
void ghostScaredTimeout(entt::registry &);// This is called when pacman collides with a ghost that is in scared mode.
// This system puts the ghost into eaten mode
void ghostEaten(entt::registry &, entt::entity);// Puts all of the ghosts into scatter mode
void ghostScatter(entt::registry &);// Puts all of the ghost into chase mode
void ghostChase(entt::registry &);#endif

所以我还挺好奇计时器在 ecs 中是什么样的
毕竟应该是需要反射的而不是 update 的

void ghostScaredTimeout(entt::registry &reg) {auto view = reg.view<Ghost, ScaredMode>();for (const entt::entity e : view) {ScaredMode &scared = view.get<ScaredMode>(e);--scared.timer;if (scared.timer <= 0) {// Adding and removing components from the entity that is currently// returned by the view is OKreg.remove<ScaredMode>(e);reg.emplace<ChaseMode>(e);}}
}

现在知道了,他这个计时器跟逻辑有关的话,就是经过的逻辑帧的数量代表经过的时间

void ghostScatter(entt::registry &reg) {const auto view = reg.view<Ghost, ChaseMode>();for (const entt::entity e : view) {reg.remove<ChaseMode>(e);reg.emplace<ScatterMode>(e);}
}

然后他这个鬼的行动模式也是做成了一个组件,而且是每一个模式是一个组件,比如这个切换模式就是加一个组件减一个组件
这样的话,到后期组件会很多吧……我看那个守望先锋的讲座上面展示的组件也不过是二十几个大概吧
不过现在小游戏也什么

啊……之后好像差不多了hhh

1.2 CrashCourse

这个看上去像是百科全书……但是看过一遍简单的项目之后应该大概似乎能看懂……吧

https://entt.docsforge.com/master/configuration/

不行,我还是看不懂
我觉得这名义上说是速成课,实际上还是需要真正理解到项目需求才能知道他在做什么我觉得我还是要找些别的来看

1.3 godot_entt_example

Github 地址:
https://github.com/portaloffreedom/godot_entt_example

用 3.4 的版本打开这个项目好像用不了,在 godot 里面看不到脚本
可能也是因为我没用过 gdnative 的原因

直接看代码吧

view.each 中使用 callback 的用法

registry.view<position, velocity, Spatial*>().each([delta](position &pos, velocity &vel, Spatial* s_entity) {pos.x += vel.dx * delta;pos.y += vel.dy * delta;pos.z += vel.dz * delta;s_entity->set_translation(Vector3(pos.x, pos.y, pos.z));});

view 写到了条件语句里面,紧凑的写法

for(auto &entity: registry.view<position, Spatial*>()){const float arena_size = 36.0f;auto &pos = registry.get<position>(entity);if (fabs(pos.x) > arena_size or fabs(pos.y) > arena_size){registry.get<Spatial*>(entity)->queue_free();registry.destroy(entity);}}

queue_free()godot 的在帧末尾安全销毁节点并将其从树中删除的快捷方式
registry.destroy()entt 的仓库对实体的销毁

registry.assign<position>(entity, 0.0f, 0.0f, 0.0f);

之前的吃豆人是 registry.emplace<struct>(entity,structIns)
现在是 registry.assign<struct>(entity,structData)

但是在官网没搜到 assign 的 api……

1.4 EnttPong

Github 地址:
https://github.com/DomRe/EnttPong

1.4.1 准备

一开始我是不会用 CMake GUI 来构建这个项目的,不知道为啥,选文件没选对?不懂
后来我试了一下吃豆人的指令,居然可以hhh

cd EnttPong-master\cmake
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .

在 VisualStudio 中将 entt_pong 设为启动项目,然后解决方案配置设为 Release,就可以运行了

1.4.2 调试

in Game.cpp

哦……我知道之前为什么没有查到 assign 的 api 了
应该是因为那个是旧版本的 entt
现在都是用 emplace


之后就有一个事件分发机制的应用,爽

in Game.hpp

namespace ep
{class Game final{private:////// Default event dispatcher.///entt::dispatcher m_dispatcher;////// The movement system.///MoveSystem m_move_system;}
}

声明了事件分发器、运动系统

in KeyDown.hpp

namespace ep
{////// Simple keydown event.///struct KeyDown final{////// Argument constructor.///inline KeyDown(int key_code): m_keycode(key_code){}////// \brief SDL2 Key code.////// Defaults to invalid -1.///int m_keycode = -1;};
} // namespace ep

按键事件结构体

in KeyUp.hpp

namespace ep
{////// Simple keydown event.///struct KeyUp final{////// Argument constructor.///inline KeyUp(int key_code): m_keycode(key_code){}////// \brief SDL2 Key code.////// Defaults to invalid -1.///int m_keycode = -1;};
} // namespace ep

按键事件结构体

in MoveSystem.hpp

namespace ep
{////// This class will take data from the appropriate components/// and update the position based on input.///class MoveSystem final{public:////// Default constructor.///MoveSystem() = default;////// Default destructor.///~MoveSystem() = default;////// Called when a key is pressed.////// \param key_down Key Down Event.///void on_key_down(const KeyDown& key_down) noexcept;////// Called when a key is released.////// \param key_up Key Up Event.///void on_key_up(const KeyUp& key_up) noexcept;////// Process events and update entities accordingly.////// \param time DeltaTime or something similar from fixed-timestep gameloop./// \param registry The registry to retrieve entities from.///void update(const double time, entt::registry& registry);////// Current movement of player.///Player::MoveDirection m_player_movement;};
} // namespace ep

按键回调函数

in Game.cpp

namespace ep
{Game::Game(std::string_view title, const int w, const int h, std::uint32_t flags): m_window {}{// Assign events to systems.m_dispatcher.sink<KeyDown>().connect<&MoveSystem::on_key_down>(m_move_system);m_dispatcher.sink<KeyUp>().connect<&MoveSystem::on_key_up>(m_move_system);}
}

综上,订阅事件的方法为
entt::dispatcher.sink<EventStruct>().connect<CallBack>(Listener)

之后触发事件是在

namespace ep
{void Game::events(){// Process all user and system events.while (SDL_PollEvent(&m_window.m_event) != 0){switch (m_window.m_event.type){case SDL_QUIT:m_window.close();break;case SDL_KEYDOWN:m_dispatcher.trigger<KeyDown>(m_window.m_event.key.keysym.sym);break;case SDL_KEYUP:m_dispatcher.trigger<KeyUp>(m_window.m_event.key.keysym.sym);break;}}}
}

trigger 的泛型就是事件,圆括号里面是事件参数

namespace ep
{const int Game::run(){// 60 updates per second. We divide 1000 by 60 instead of 1 because sdl operates on milliseconds// not nanoseconds.const constexpr double dt = 1000.0 / 60.0;// This is a fixed-step gameloop.// See https://gafferongames.com/post/fix_your_timestep/// For an explanation.double time         = 0.0;double accumulator  = 0.0;double current_time = SDL_GetTicks();double new_time     = 0.0;double frame_time   = 0.0;while (m_window.is_open()){new_time     = SDL_GetTicks();frame_time   = new_time - current_time;current_time = new_time;accumulator += frame_time;events();while (accumulator >= dt){update(accumulator);accumulator -= dt;time += dt;}render();}return EXIT_SUCCESS;}
}

这个是固定帧率内执行逻辑 update,实际帧率内渲染

in AISystem.cpp

namespace ep
{void AISystem::update(const double time, entt::registry& registry){// Center the ai to the ball so it is always in the right position.// we want to increase or decrese ai position based on if the ball is above or below it.// so something like:/*if ball position is above ai:move ai smoothly up towards ball so middle of ai paddle is at ball pos.*/// Takes advantage of the fact that there is only 1 AI and 1 Ball.auto ai_view   = registry.view<AI, Position>();auto ball_view = registry.view<Ball, Position>();ai_view.each([&](auto& ai, auto& ai_pos) {ai.m_x = ai_pos.m_x;ai.m_y = ai_pos.m_y;ball_view.each([&](auto& ball, auto& ball_pos) {if (ball_pos.m_y > ai_pos.m_y){ai_pos.m_y += 2.5;}else if (ball_pos.m_y < ai_pos.m_y){ai_pos.m_y -= 2.5;}});});}
}

原来 each 输入的函数参数就是组件

之前在 api 里面看过,但是没看到他这个 component&

此外就没有什么了

1.5 entt-breakout

Github 地址:
https://github.com/vblanco20-1/entt-breakout

没编译成……好像要下个 SDL2_Image。我懒

他是把所有组件的结构体声明放在一个头文件 component.hpp 里面
这样挺好诶,一眼看到所有

这个是个把主逻辑放在 main 中的
我一点开就看到有用 entt::observer entt::collector,就感觉很厉害

//holds the observers for the reactive systems of this program
struct RegistryObservers {entt::observer sprite_transform_observer;void initialize(entt::registry& registry) {auto sprite_collector = entt::collector.replace<SpriteLocation>().when<SDL_RenderSprite>().group<SpriteLocation,SDL_RenderSprite>();sprite_transform_observer.connect( registry, sprite_collector );printf( "initializing observers");}
};

看了一会才知道这个 entt::observer 的作用是找到给定 registry 中满足条件的实体,这个条件就是 entt::collector
但是在哪里都找不到 entt::collectorreplace 方法,太奇怪了



还有 when 也是

可能还是因为这是三年前的项目,所以用的 api 都被改动过吧

sprite_transform_observer.connect( registry, sprite_collector );

但是至少这个句子的意思就是,使用 sprite_collector 来筛选 registry,得到的结果在 sprite_transform_observer

void transform_sprites(entt::registry &registry)
{       int nexecutions = 0;registry.ctx<RegistryObservers>().sprite_transform_observer.each([&registry,&nexecutions](auto et) {SDL_RenderSprite& sprite = registry.get<SDL_RenderSprite>(et);SpriteLocation& location = registry.get<SpriteLocation>(et);Vec2i screenspace = game_space_to_screen_space(location.location);sprite.location = screenspace;   nexecutions++;});//printf("transform executions %i, \n",nexecutions);
}

ctx 的作用就好像一个……一种类型只有一种值的黑板
好奇怪,为什幺做成一个类型只有一个值

https://entt.docsforge.com/master/entity-component-system/#context-variables

此外就没有什么了

唉……看了这么多,估计大家的示例程序都差不多把……或许我也要开始自己写了

[ESC] EnTT 学习记录 1相关推荐

  1. [ESC] EnTT 学习记录 2

    EnTT and Unreal 教程 https://entt.docsforge.com/master/entt-and-unreal-engine/#table-of-contents BwdYe ...

  2. (一)Git学习记录(不断更新)

    作为程序员如果你还不知道 Git 和 GitHub,说不过去吧,赶紧来学习一波. 一.认识GitHub Git 是个版本控制系统,说明白点就是进行代码的各种管理,比如你写错代码进行回滚啊.追寻 Bug ...

  3. Opencv 入门篇学习记录(图片)

    title: Opencv 入门篇学习记录(图片) Opencv 入门篇学习记录(图片) 前言 很早以前就接触Python了,大学的时候还自学了一段时间去做了课设,写了一些最速梯度下降法.黄金分割法. ...

  4. 【学习记录】QT5界面设计的踩坑记录

    学习记录:QT5 界面设计的踩坑记录 前言 一.Qlabel显示视频与图片 1. 图片显示 1.1 显示格式 1.2 label随界面缩放 1.3 界面刷新 2. 视频显示 二.常见控件的StyleS ...

  5. 如何在阿里云上搭建个人网站(学习记录)

    如何在阿里云上搭建个人网站(学习记录) 第一次写博客记录学习的过程,不仅可以巩固学习知识,也方便日后复习.并且可以记录自己的成长. 先购买阿里ECS云服务器 购买网站https://promotion ...

  6. linux个人学习记录

    linux学习记录 资料: Linux 黑马程序员_bilibili AcWing Linux基础课 可能是东半球最全面易懂的 Tmux 使用教程! Shell 教程 | 菜鸟教程 (runoob.c ...

  7. 【VUE】学习记录一

    [VUE]学习记录 学习视频为:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs从入门到精通 1.查询vue知识点: https://v2.cn.vuejs.org/ 2. 下载和引入 2.1 下 ...

  8. [VNCTF 2021]Ez_game-JS类题目学习记录

    [VNCTF 2021]Ez_game-JS类题目学习记录 之前没咋做过js的题,也没写过js项目,但还是能简单看懂一些js代码,基础有点薄弱,所以记录下这次的做题. 这就是游戏的开始叭,你有一个回旋 ...

  9. java预科基础篇2021.2.3学习记录

    java预科基础篇2021.2.3学习记录 初识博客 本以为老师会讲是在微博上写博客做记录,没想到会是很多程序员专用的博客 博客为音译,正确翻译结果为网络日记,英文为bog 较为专业的程序员用博客为: ...

最新文章

  1. Linux Kernel TCP/IP Stack — L1 Layer — NIC bonding
  2. 面对 iPad,Surface 的键盘是必杀技
  3. hbase 单机 java api,HBase学习(一)hbase安装(单机模式)和javaapi客户端访问hbase例子...
  4. 缺省参数-回顾列表的排序方法明确缺省参数的概念及作用
  5. mysql数据库集群备份策略_mysql高可用方案之集群(cluster)
  6. java执行class找不到main函数_你所不知道的HelloWorld背后的执行原理
  7. eclipse git拉取失败_Git(四):分支
  8. 鱼之死,越狱章鱼和雾霾黑客
  9. 腾讯云CDN常见问题
  10. snapchat 登录不上_如何在Snapchat上举报某人
  11. transform.forward和vector3.forward的使用区别
  12. 不懂PS也制作图片倒影效果 – 推荐2个好用的在线为图片添加倒影效果的网站
  13. 阿里蚂蚁金服4面面经(已拿Offer)附答案!突如其来的意外之喜
  14. 如何利用GitHub搜索敏感信息
  15. 函数最值题目及答案_高一函数题目及答案解析
  16. F014-正本清源话通缩 #F1175
  17. C-素数回文数的个数
  18. 数据挖掘冰山立方体构建算法:BUC及实现
  19. App数据统计分析:快速提升运营分析能力
  20. STM32平台下官方DMP库6.12超详细移植教程

热门文章

  1. SpringBoot2.0 整合 SpringSecurity 框架,实现用户权限安全管理
  2. Linux常用命令(第二版) --文件管理命令
  3. 如何实现两列等高效果?
  4. leetcode - Interleaving String
  5. SQL Server -- SQL NULL值,ISNull(),Oracal NVL(),MYSQL IFNULL(),COALESCE()
  6. UILabel(富文本)
  7. Django Web实现动态三级联动
  8. 在SQL Server里为什么我们需要更新锁
  9. java reflect 例子
  10. Linux下监控网卡流量的软件iftop