从零开始的游戏开发学习笔记系列-01
SFML概述
SFML (Simple and Fast Multimedia Library)是一个用C++编写的,跨平台的,多媒体处理的底层框架库
它封装了操作系统的窗口系统、图形渲染、音频播放等底层功能。通过在C++代码中包含SFML的头文件并链接它的库文件,程序就能调用这些功能,创建出图形窗口,实现游戏效果
底层代码逻辑为C++语法
SFML环境配置
环境:Windows 11/VS Code/MSYS2
背景
之前在VS Code中已配置好MinGW编译器(官网下载),计划在此基础上配置SFML,开始学习2D游戏开发
问题记录
SFML版本不匹配
问题:在官网下载的SFML版本和本地MinGW编译器不匹配,导致无法编译
- 本地编译器与SFML预编译版本必须匹配,否则无法找到SFML的头文件(
#include <SFML/Graphics.hpp>) - 代码语法格式必须与SFML版本匹配,SFML2版本与SFML3版本语法改动较大,若版本不符合会导致语法错误
- 编译器和SFML的位数必须与电脑操作系统的位数(x32和x86_64)匹配
解决:
- 在官网或者GitHub链接下载符合版本的SFML
- 使用vcpkg(微软推出的C/C++包管理器)和CMake自动管理,前提需要安装Git(本人因为网络加载问题最终没有用这个方案,所以不详细介绍了)
- 使用(MSYS2)的包管理器下载符合版本的SFML
使用MSYS2下载符合版本的SFML
- 从官网下载MSYS2程序并按指引安装
- 打开运行MSYS2 UCRT64 或 MSYS2 MinGW 64-bit终端(exe文件)
- 输入命令更新包管理器(可选):
bash
pacman -Syu
- 安装SFML
bash
pacman -S mingw-w64-ucrt-x86_64-sfml
问题:
-
signature is invalid:密钥环过期- 首次运行pacman时需要先初始化密钥环
bash
#1.初始化密钥环
pacman-key --init
#2.填充MSYS2密钥
pacman-key --populate msys2
#3.更新系统(包含密钥环本身)
pacman -Syu
#4.安装SFML
pacman -S mingw-w64-ucrt-x86_64-sfml
-
找不到SFML文件
- 头文件路径
E:/msys2/ucrt64/include - 库文件路径
E:/msys64/ucrt64/lib - CMake配置文件
E:/msys2/ucrt64/lib/cmake/SFML/ - DLL文件
E:/msys64/ucrt64/bin
- 头文件路径
编译配置json文件
文件结构:
-
.vscode文件夹tasks.json编译任务:定义怎么编译(用什么命令、编译哪些文件)launch.json调试设置:定义怎么调试(运行哪个exe、怎么启动调试器)c_cpp_properties.json编译器智能提示:提示VSCode代码补全要用哪些头文件、用哪个C++标准
-
sfml_test.cpp源代码文件
问题:要编译源代码文件还必须要配置tasks.json文件链接所需的SFML库文件,否则查找不到库文件
解决:
-
依据以下代码写好
tasks.json文件 -
配置后按
Ctrl+Shift+B -
会弹出一个下拉菜单,选择配置的
Build SFML任务即可 -
若未出现
Build SFML,说明tasks.json没生效,或者配置有语法错误- 可能是之前提到的版本不匹配
- 可能是库文件路径错误
- 可能是
.vscode\tasks.json和cpp源码不在同一个文件夹里 - 可能是
tasks.json里写的cpp文件名不对
配置tasks.json
用VSCode命令面板自动创建
- 打开命令面板 :在 VSCode 中,按下快捷键
Ctrl+Shift+P(Windows/Linux)或Cmd+Shift+P(Mac) - 输入指令 :在弹出的输入框中,输入
Tasks: Configure Task(或者中文 "任务:配置任务") - 选择模板 :在下拉选项中,选择
Create tasks.json file from template(从模板创建 tasks.json 文件) - 选择"Others"模板 :下拉选项直接拉到最后,选择
Others。这个模板会创建一个最干净、最基础的配置示例,适合从零开始修改
json
{
"version": "2.0.0", //tasks.json版本号,固定写法
"tasks": [ //任务数组,这里包含两个任务:编译,运行
{
"label": "Build SFML", //任务名称,显示在VSCode中
"type": "shell", //任务类型:在shell中执行命令
"command": "g++", //要执行的命令(编译器)
//命令参数数组
"args": [
"${file}", //当前打开要编译的源文件
"-o","${fileDirname}/${fileBasenameNoExtension}.exe", //-o指定输出文件名+生成的exe文件名
"-I", "E:/msys2/ucrt64/include", //-I头文件路径(Include)
"-L", "E:/msys2/ucrt64/lib", //-L库文件路径(Library)
//链接的库
"-lsfml-graphics", //link-SFML图形库
"-lsfml-window", //link-SFML窗口库
"-lsfml-system", //link-SFML系统库
//静态链接选项
"-static-libgcc", //静态链接GCC库
"-static-libstdc++" //静态链接C++标准库
//静态链接意味着把这些库打包进exe,方便分发
],
"group": {
"kind": "build", //属于bulid组
"isDefault": true //是默认编译任务
},
"problemMatcher": ["$gcc"], //使用GCC的错误解析器
"detail": "编译SFML项目" //任务描述
},
{
"label": "Run", //任务名称
"type": "shell", //在shell中执行
"command": "${fileDirname}/${fileBasenameNoExtension}.exe", //运行命令
"dependsOn": ["Build SFML"], //依赖任务:先编译再运行
"group": {
"kind": "test", //属于test组
"isDefault": true //是默认测试任务
},
"detail": "运行编译好的程序"
}
]
}
理解:相当于在终端执行
sql
g++ "sfml_test.cpp" -o "sfml_test.exe" -I "E:/msys2/ucrt64/include" -L "E:/msys2/ucrt64/lib" -lsfml-graphics -lsfml-window -lsfml-system -static-libgcc -static-libstdc++
动态链接库DLL文件缺失
编译成功后,双击exe文件运行可能提示缺少dll文件,需要在下载的SFML的bin文件夹中复制一份到项目文件夹
- 如果直接在官网下载的压缩包文件夹,dll就在对应的bin文件夹中,类似
libsfml-*-3.dll格式 - 如果使用MSYS2下载的SFML,dll文件可能零散放在MSYS的bin文件夹,如果仍提示缺少,可以根据缺失信息在bin文件夹中一个一个找
成品
最终可行的文件目录:
bash
/.vscode/tasks.json
/.vscode/launch.json
/.vscode/settings.json
/.vscode/c_cpp_properties.json
/libb2-1 1.dll
/libbrotlicommon.dll
/libbrotlidec.dll
/libbz2-1.dll
/libfreetype-6.dll
/libglib-2.0-0.dll
/libgraphite2.dll
/libharfbuzz-0.dll
/libiconv-2.dll
/libintl-8.dll
/libpcre2-8-0.dll
/libpng16-16.dll
/libsfml-audio-3.dll
/libsfml-graphics-3.dll
/libsfml-network-3.dll
/libsfml-system-3.dll
/libsfml-window-3.dll
/zlib1.dll
/sfml_test.cpp
源码:
cpp
#include<SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode({800,600}),"MyFirstSFML");
sf::CircleShape circle(100.f);
circle.setFillColor(sf::Color::Green);
circle.setPosition({350.f,250.f});
while(window.isOpen())
{
while(const std::optional event=window.pollEvent())
{
if(event->is<sf::Event::Closed>()) window.close();
}
window.clear(sf::Color::Black);
window.draw(circle);
window.display();
}
return 0;
}
附: GitHub链接:Shiroku233/MySFML_study
小红书/B站同名:Shiroku233
本人是初学者,本文只是个人踩坑记录,非权威教程,如有错误欢迎指正,希望能帮到同样在配环境的伙伴