自学程序加工作好几年了,是时候来练个手了(不算用引擎开发游戏)。之前Google学习资料的时候,找到一个弹幕射击游戏的教程,稍微瞄了眼,还挺不错的,但用的是封装的DxLib库,这就不开心了,后面就没看了。学习DirectX也有年头了,觉得是时候可以练习下,但不打算用DirectX来开发,打算用最近刚学习的SDL或者SFML来开发。
为了加大难度,就打算采用C++加Lua的方式来开发,不用第3方库,全部自己手写导出到Lua这边,加深一下自己对C++和Lua的通信原理。
PS:之前有人联系我说,说看不懂,还说只有写的人能看懂,还有让我帮你来做功能的。我就奇了怪了,你自己基础不到位,怪作者,为啥不怨一下你自己不努力呢?
准备工作
IDE用的是Visual Stuido 2019,这个下载就不介绍了,版本很新,一直在推荐更新╮(╯▽╰)╭。接下来准备lua源码和SDL库。
Lua准备工作
去lua官网(https://www.lua.org/download.html)下载源代码。
新建一个Visual Stuido空工程,空工程名为Lua,将刚才下的lua源码解压,解压得到lua-5.3.5文件夹,将lua-5.3.5文件夹中的子文件夹src文件夹整个拷贝到刚建Lua空工程目录下。在Solution Explorer(解决方案管理器)窗口选择Lua工程,然后在Solution Explorer窗口的工具栏上点击Show All Files按钮。
然后就会看到刚才拷贝过来的src文件夹。然后选择src文件夹,右键点击Include In Project(包含到工程中),然后在src文件中找到lua.c和luac.c文件,右键点击Exclude In Project(从工程中排除)。
右键Lua工程,点击属性按钮,先将EXE工程改成静态库工程。
接着修改Output Directory(输出目录)和Intermediate Directory(中间目录),也可以不改,用默认的也可以,主要是这样链接Lua库比较方便。
Output Directory(输出目录):$(SolutionDir)bin\$(Platform)\$(Configuration)\$(ProjectName)\
Intermediate Directory(中间目录):$(SolutionDir)bin-int\$(Platform)\$(Configuration)\$(ProjectName)\
然后右键Lua工程编译得到Lua.lib。Lua这边的准备工作就已经完成了,接下来就是测试。
接着在同一个Solution下新建一个Visual Stuido空工程,空工程名为Ryuujinn(日语名为龍(りゅう)(
ryuu)神(じん)(jinn))。右键Ryuujinn工程添加新文件夹,命名为Source,再在Source目录下添加新文件Main.cpp(这个就不需要列出具体步骤吧)。
现在需要做的事,是链接Lua库来测试。首先右键Ryuujinn工程,点击属性按钮,修改Output Directory和Intermediate Directory,改成跟Lua工程一样的,这个步骤上面有,就不再介绍了。
点击属性面板中左侧的C/C++按钮,选择General(一般),然后在右侧的Additional Include Directories(附加的包含目录)中添加Include;$(SolutionDir)Lua\Src;Include指的是我等下会再建一个Include文件夹目录,$(SolutionDir)Lua\Src指的是之前创建Lua工程下的拷贝过来的lua源码目录。
接着点击属性面板中左侧的Linker(链接器)按钮,选择General(一般),然后在右侧的Additional Library Directories(附加的库目录)中添加$(SolutionDir)bin\$(Platform)\$(Configuration)\Lua\;这个$(SolutionDir)bin\$(Platform)\$(Configuration)\Lua\就是前面Lua工程中Output Directory的目录。之前说修改Output Directory和Intermediate Directory的方便就在这个地方。如果没有修改的话,就需要自己去定位到静态库的生成目录。
好了,链接Lua库的大部分工作做完了,开始测试是否可以调用Lua。在之前添加的Main.cpp中添加如下代码:
// 引入lua需要的头文件
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
// 链接Lua工程生成的静态库
#pragma comment(lib, "Lua.lib")
#include <iostream>
int main()
{
// 创建虚拟栈
lua_State* L = luaL_newstate();
// 引入lua的标准库,不然调用print会报错,可以注释掉代码,查看报错
luaL_openlibs(L);
// 很简单的lua代码,输出Hello, lua
const char* strLuaScript = R"(
print("Hello, lua")
)";
// 执行lua代码
int result = luaL_dostring(L, strLuaScript);
if (LUA_OK != result)
std::cout << lua_tostring(L, -1) << std::endl;
else
{
}
// 关闭虚拟栈
lua_close(L);
system("pause");
return 0;
}
代码中注释很多,就不一一解释了,如果想要仔细了解C++调用Lua,可以通过百度和Google搜索文章看,也可以通过搜视频看,国内有一个还可以,但是需要付费,也不贵(60多),但我就不列出具体网址了,国外的我在看,讲的很不错,英文不错的可以看下,网址在这里,需要科学上网,最近有个测试的酷鸟浏览器是可以科学上网看的(用过,比较差,经常打不开,或者看到一半就挂了,勉强能用)
如果输出了Hello, lua就说明lua配置没有问题。lua配置就到此结束了,接下来就是SDL的配置了。
SDL准备工作
去SDL官网(https://www.libsdl.org/download-2.0.php)下载Development Libraries。还需SDL的扩展库SDL_Image,去该网址下载(https://www.libsdl.org/projects/SDL_image/)Development Libraries。
将下载的2个文件都解压,放到自己喜欢的硬盘下,接下来配置环境变量,因为我存放到D盘下,文件名为_SDL2-2.0.10和_SDL2_image-2.0.5,因此我的环境变量是
SDL_IncludePath: "D:_SDL2-2.0.10\include"
SDL_LibraryPath: "D:_SDL2-2.0.10\lib"
SDL_Image_IncludePath: "D:_SDL2_image-2.0.5\include"
SDL_Image_LibraryPath: "D:_SDL2_image-2.0.5\lib"
win7只能截成这样了,win10的话就会好一点。环境变量生效的话需要重启Visual Studio 2019,如果不生效,就关闭explorer.exe,再不行就重启电脑就OK。
跟之前配置Lua一样,在Ryuujinn工程的属性面板上添加刚配置好的环境变量就OK:Additional Include Directories(附加的包含目录)再添加$(SDL_IncludePath);$(SDL_Image_IncludePath)。
Additional Library Directories(附加的库目录)就需要特殊处理下,要根据平台来处理:
32位(Win32)添加$(SDL_LibraryPath)\x86;$(SDL_Image_LibraryPath)\x86;
64位(x64)添加$(SDL_LibraryPath)\x64;$(SDL_Image_LibraryPath)\x64;
还需要一步处理,也是需要根据平台来,在Ryuujinn工程的属性面板点击左侧的Build Events(编译事件),接着点击Build Events下方的Pre-Build Evnet(预编译事件),在属性面板右侧的Command Line(命令行)中点击,会弹出Edit(编辑)按钮,点击后会弹出一个窗口,接下来填入需要处理的命令。
32位(Win32)添加
XCOPY "$(SDL_LibraryPath)\x86\*.dll" "$(TargetDir)" /D /K /Y
XCOPY "$(SDL_Image_LibraryPath)\x86\*.dll" "$(TargetDir)" /D /K /Y
64位(x64)添加
XCOPY "$(SDL_LibraryPath)\x64\*.dll" "$(TargetDir)" /D /K /Y
XCOPY "$(SDL_Image_LibraryPath)\x64\*.dll" "$(TargetDir)" /D /K /Y
这2句命令的主要功能就是将之前下载下来的SDL和SDL_Image目录中的DLL拷贝到Ryuujinn工程的生成目录中而已。
SDL配置也已经结束了,接下来在之前Lua测试代码中添加SDL测试代码来测试:
新的Main.cpp:
// 引入lua需要的头文件
extern "C"
{
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
// 链接Lua工程生成的静态库
#pragma comment(lib, "Lua.lib")
#define SDL_MAIN_HANDLED
// 引入SDL需要的头文件
#include <SDL.h>
#include <SDL_image.h>
// 链接SDL静态库
#pragma comment(lib, "SDL2.lib")
#pragma comment(lib, "SDL2main.lib")
#pragma comment(lib, "SDL2_image.lib")
#include <iostream>
int main()
{
// 创建虚拟栈
lua_State* L = luaL_newstate();
// 引入lua的标准库,不然调用print会报错,可以注释掉代码,查看报错
luaL_openlibs(L);
// 很简单的lua代码,输出Hello, lua
const char* strLuaScript = R"(
print("Hello, lua")
)";
// 执行lua代码
int result = luaL_dostring(L, strLuaScript);
if (LUA_OK != result)
std::cout << lua_tostring(L, -1) << std::endl;
else
{
}
// 关闭虚拟栈
lua_close(L);
if (0 != SDL_Init(SDL_INIT_EVERYTHING))
return -1;
int flags = 0;
SDL_Window* pWindow = SDL_CreateWindow("Test", 100, 100, 500, 500, flags);
if (!pWindow)
return -1;
SDL_Renderer* pRenderer = SDL_CreateRenderer(pWindow, -1, 0);
SDL_SetRenderDrawColor(pRenderer, 255, 255, 255, 255);
if (!pRenderer)
return -1;
while (1);
SDL_DestroyWindow(pWindow);
SDL_DestroyRenderer(pRenderer);
SDL_Quit();
system("pause");
return 0;
}
弹出如下窗口,就说明SDL配置成功,但新加的代码是没有测试SDL_Image的配置是否成功的,因为基本差不多,但是要加测试代码,就不是这么一点了,还得找资源就有点麻烦了,可以自行上网搜索添加代码测试。
如果有下图编译失败的,看是不是这个错误,这个错误的原因是SDL修改了main函数(#define main SDL_main),这个可以在SDL_main.h头文件中可以查看,解决这个错误有多个方法,这边就采取最简单的,看是不是没有添加#define SDL_MAIN_HANDLED,或者这个是否在#include <SDL.h>之前。
好了,Lua和SDL的配置大体完成了,可以舒一口气了。