大部分前期工作都已经完成了,可以正式开始敲游戏代码了。之前显示的都是死循环的窗口,这次终于可以来解决这个问题了,先看看今天的结果。
这次C++中有部分修改的代码,但有了之前的基础,就不花费很多精力在这上面,代码会放到最后面。首先将之前的Game.lua修改下名字,改成GameBase.lua。
GameBase.lua
require "Module.Enum.SDL"
local GameBase =
{
m_bIsRunning = false, --是否在运行
m_pSDLWindow = nil, --SDL_Window指针
m_pSDLRenderer = nil, --SDL_Renderer指针
m_title = "Game", --窗口标题
m_width = 0, --窗口宽度
m_height = 0, --窗口高度
m_bFullscreen = false, --是否是全屏运行
m_lastTime = 0, --上次运行时间
}
--初始化
function GameBase:Init()
self.m_bIsRunning = false
--SDL初始化
local flags = SDL_INIT_TYPE.SDL_INIT_VIDEO
local bResult = Renderer.SDLInit(flags)
if not bResult then
Logger.LogError("Renderer.SDLInit(%d) failed, %s", flags, Renderer.GetError())
return false
end
--读取Window.ini配置
local filePath = "Config/Window.ini"
local windowConfig = io.open(filePath, "r")
if not windowConfig then
Logger.LogError("Error: Can't find %s", filePath)
return false
end
self.m_title = windowConfig:read()
self.m_width = tonumber(windowConfig:read())
self.m_height = tonumber(windowConfig:read())
self.m_bFullscreen = tonumber(windowConfig:read()) ~= 0
windowConfig:close()
--根据Window.ini配置创建SDL窗口
flags = 0
if self.m_bFullscreen then
flags = flags | SDL_WINDOW_TYPE.SDL_WINDOW_FULLSCREEN
end
self.m_pSDLWindow = Renderer.CreateWindow(self.m_title, 100, 100, self.m_width, self.m_height, flags)
--创建SDLRenderer
flags = SDL_RENDERER_TYPE.SDL_RENDERER_ACCELERATED | SDL_RENDERER_TYPE.SDL_RENDERER_PRESENTVSYNC
self.m_pSDLRenderer = Renderer.CreateRenderer(self.m_pSDLWindow, -1, flags)
--SDL_Image初始化
flags = SDL_IMAGE_INIT_TYPE.IMG_INIT_PNG
bResult = Renderer.SDLImageInit(flags)
if not bResult then
Logger.LogError("Renderer.SDLImageInit(%d) failed, %s", flags, Renderer.GetError())
return false
end
if self.OnInit then
bResult = self:OnInit()
if not bResult then
return false
end
end
self.m_bIsRunning = true
return true
end
--运行
function GameBase:Run()
while self:IsRunning() do
self:HandleEvents()
self:Update()
self:Render()
end
end
--释放
function GameBase:Release()
if self.OnRelease then
self:OnRelease()
end
if self.m_pSDLRenderer then
Renderer.DestroyRenderer(self.m_pSDLRenderer)
end
if self.m_pSDLWindow then
Renderer.DestroyWindow(self.m_pSDLWindow)
end
Renderer.Quit()
end
--是否在运行中
function GameBase:IsRunning()
return self.m_bIsRunning
end
--退出游戏
function GameBase:QuitGame()
self.m_bIsRunning = false
end
--事件处理
function GameBase:HandleEvents()
local bResult, eventType = Renderer.PollEvent()
while bResult do
if eventType == SDL_EVENT_TYPE.SDL_QUIT then
self:QuitGame()
else--other event
end
bResult, eventType = Renderer.PollEvent()
end
--按下Escape键退出游戏
bResult = Renderer.GetKeyboardState(SDL_KEYCODE.SDL_SCANCODE_ESCAPE)
if bResult then
self:QuitGame()
end
if self.OnHandleInput then
self:OnHandleInput()
end
end
--更新
function GameBase:Update()
--限制一帧至少16ms
while not Renderer.TICKS_PASSED(Renderer.GetTicks(), self.m_lastTime + 16) do
end
local currentTime = Renderer.GetTicks()
local deltaTime = (currentTime - self.m_lastTime) / 1000
self.m_lastTime = currentTime
--调试会导致deltaTime变大,限制一下
if deltaTime > 0.05 then
deltaTime = 0.05
end
if self.OnUpdate then
self:OnUpdate(deltaTime)
end
end
--渲染
function GameBase:Render()
Renderer.SetRenderDrawColor(self.m_pSDLRenderer, 0, 0, 255, 255)
Renderer.RenderClear(self.m_pSDLRenderer)
if self.OnRender then
self:OnRender()
end
Renderer.RenderPresent(self.m_pSDLRenderer)
end
return GameBase
可以看出来GameBase是作为元表的,我把很多框架上的函数都写在GameBase上,是不想被人重载掉这些接口。按顺序逐个说下API:GameBase:Init()应该是最简单的,只是将之前的代码完善而已。
SDL初始化应该没有多少问题,跳过。在创建SDL窗口之前,添加了一堆读取Window.ini的代码,实际上只是把创建窗口需要的参数提取出来,放到Window.ini中,利用IO操作来获取数据,减少在代码中频繁修改窗口名,窗口宽度等数据的次数。可以来看下Window.ini的配置:
创建SDLRenderer也没有多少变化,跳过。新增加的SDLImageInit其实跟SDL_Init一样(我避免歧义,重命名了Renderer.Init函数名)。接下来代码就比较核心了,过会还会看到很多OnXXX的函数,这些才是我们真正关心的函数。
没有用过lua的估计会有点懵逼,这是啥意思,这里简单解释下,因为GameBase本身是没有OnInit字段(key),所以会跳过这段代码,但是不要忘记GameBase是作为元表的,也就是父类,而我们后面将使用的也是子类(也就是后面的RyuujinnGame)来创建游戏的。因此如果是子类(RyuujinnGame表)在调用Init函数的时候,执行到同样的地方时候,self.OnInit就会从子类(RyuujinnGame表)查找这个OnInit字段(key),找到后,就调用OnInit函数,这样就使得子类(RyuujinnGame表)只关心游戏的逻辑,不去关系SDL窗口的创建,SDL事件的处理等。
接下来的GameBase:Run()就是之前的死循环修改后的版本,主要负责3个工作,处理事件,更新游戏,渲染游戏。再接着的GameBase:Release()也是之前提取出来的代码,只是加了OnRelease调用而已,这个跟之前的OnInit是一致的,这边不再重复。GameBase:IsRunning()和GameBase:QuitGame()的代码就一句,没啥可说的。
GameBase:HandleEvents()主要功能就是事件处理,比如处理点击关闭按钮事件,按下Escape按键等。lua这边代码也很简单,但这里有一个特殊的地方就是,C++函数只能有一个返回值(不算把结果按地址传递,类似c#的out),lua这边直接返回了2个值,来看C++这边的代码,int PollEvent(lua_State* L)就实现了lua这边可以接受2个返回值的功能,因为事件处理只关心类型,也做一步处理,不传SDL_Event,而是传SDL_Event的type字段。
接下来的GameBase:Update()和GameBase:Render()代码很简单,可以修改Renderer.SetRenderDrawColor函数后面4个参数来修改SDL窗口的颜色。SDL一些枚举值,也有部分提取到lua中,在Script文件夹中,创建Module文件夹,再在Module文件夹下创建Enum文件夹,再在Enum文件夹下创建SDL.lua文件,工作也很简单,就是把大部分ctrl+c,ctrl+v就ok了。需要注意的就是16进制要转成10进制。
SDL.lua
--SDL初始化类型
SDL_INIT_TYPE =
{
SDL_INIT_VIDEO = tonumber("00000020", 16),--将16进制字符串转换成10进制数字
}
--SDL窗口类型
SDL_WINDOW_TYPE =
{
SDL_WINDOW_FULLSCREEN = tonumber("00000001", 16),
}
SDL_RENDERER_TYPE =
{
SDL_RENDERER_ACCELERATED = tonumber("00000002", 16),
SDL_RENDERER_PRESENTVSYNC = tonumber("00000004", 16),
}
--SDL_Image初始化类型
SDL_IMAGE_INIT_TYPE =
{
IMG_INIT_PNG = tonumber("00000002", 16),
}
--事件类型
SDL_EVENT_TYPE =
{
SDL_QUIT = tonumber("100", 16),
}
--按键
SDL_KEYCODE =
{
SDL_SCANCODE_A = 4,
SDL_SCANCODE_B = 5,
SDL_SCANCODE_C = 6,
SDL_SCANCODE_D = 7,
SDL_SCANCODE_E = 8,
SDL_SCANCODE_F = 9,
SDL_SCANCODE_G = 10,
SDL_SCANCODE_H = 11,
SDL_SCANCODE_I = 12,
SDL_SCANCODE_J = 13,
SDL_SCANCODE_K = 14,
SDL_SCANCODE_L = 15,
SDL_SCANCODE_M = 16,
SDL_SCANCODE_N = 17,
SDL_SCANCODE_O = 18,
SDL_SCANCODE_P = 19,
SDL_SCANCODE_Q = 20,
SDL_SCANCODE_R = 21,
SDL_SCANCODE_S = 22,
SDL_SCANCODE_T = 23,
SDL_SCANCODE_U = 24,
SDL_SCANCODE_V = 25,
SDL_SCANCODE_W = 26,
SDL_SCANCODE_X = 27,
SDL_SCANCODE_Y = 28,
SDL_SCANCODE_Z = 29,
SDL_SCANCODE_1 = 30,
SDL_SCANCODE_2 = 31,
SDL_SCANCODE_3 = 32,
SDL_SCANCODE_4 = 33,
SDL_SCANCODE_5 = 34,
SDL_SCANCODE_6 = 35,
SDL_SCANCODE_7 = 36,
SDL_SCANCODE_8 = 37,
SDL_SCANCODE_9 = 38,
SDL_SCANCODE_0 = 39,
SDL_SCANCODE_RETURN = 40,
SDL_SCANCODE_ESCAPE = 41,
SDL_SCANCODE_BACKSPACE = 42,
SDL_SCANCODE_TAB = 43,
SDL_SCANCODE_SPACE = 44,
}
大部分工作已经在GameBase上完成了,接下来就是来实现子类,添加RyuujinnGame.lua,代码也很简单,关键就是通过__newindex元方法来进制重载GameBase上的函数。
RyuujinnGame.lua
RyuujinnGame = setmetatable({},
{
__index = require "GameBase",
__newindex = function(t, key, newValue)--禁止重载GameBase函数
local oldValue = t[key]
if oldValue == nil or type(oldValue) ~= "function" then
rawset(t, key, newValue)
else
Logger.LogError("This action overrides GameBase's function is not allowed\n"..debug.traceback())
end
end
})
function RyuujinnGame:OnInit()
return true
end
function RyuujinnGame:OnRelease()
end
function RyuujinnGame:OnHandleInput()
end
function RyuujinnGame:OnUpdate(deltaTime)
end
function RyuujinnGame:OnRender()
end
Main.lua脚本估计后面也不会用太大的改动,这应该算是最终版吧。
Main.lua
require "Logger"
require "RyuujinnGame"
function Main()
Logger.Log("Main")
local bResult = RyuujinnGame:Init()
if bResult then
RyuujinnGame:Run()
end
RyuujinnGame:Release()
end
运行后就会得到一个蓝色的窗口,点击关闭按钮和按下Escape按键都能关闭掉SDL窗口。
是时候在窗口上显示一张图片啥的,接下来就只要修改RyuujinnGame.lua的脚本,就会在窗口上显示一张图片,并且可以通过WSAD按键控制图片的移动。Renderer.Test只是测试代码,后面会删除的。
RyuujinnGame.lua
RyuujinnGame = setmetatable({},
{
__index = require "GameBase",
__newindex = function(t, key, newValue)--禁止重载GameBase函数
local oldValue = t[key]
if oldValue == nil or type(oldValue) ~= "function" then
rawset(t, key, newValue)
else
Logger.LogError("This action overrides GameBase's function is not allowed\n"..debug.traceback())
end
end
})
function RyuujinnGame:OnInit()
self.texture = Renderer.GetTexture(self.m_pSDLRenderer, "Resource/body.png")
self.posX = 0
self.posY = 0
return true
end
function RyuujinnGame:OnRelease()
end
function RyuujinnGame:OnHandleInput()
if Renderer.GetKeyboardState(SDL_KEYCODE.SDL_SCANCODE_W) then
self.posY = self.posY - 10
end
if Renderer.GetKeyboardState(SDL_KEYCODE.SDL_SCANCODE_S) then
self.posY = self.posY + 10
end
if Renderer.GetKeyboardState(SDL_KEYCODE.SDL_SCANCODE_A) then
self.posX = self.posX - 10
end
if Renderer.GetKeyboardState(SDL_KEYCODE.SDL_SCANCODE_D) then
self.posX = self.posX + 10
end
end
function RyuujinnGame:OnUpdate(deltaTime)
end
function RyuujinnGame:OnRender()
local destWidth = 100
local destHeight = 100
Renderer.Test(self.m_pSDLRenderer, self.texture, 100, 100, self.posX, self.posY)
end
Renderer.h
#pragma once
#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")
class Renderer
{
public:
#pragma region 初始化
static bool SDLInit(Uint32 flags);
static bool SDLImageInit(int flags);
static SDL_Window* CreateWindow(const char* title, int posX, int posY, int width, int hegiht, Uint32 flags);
static SDL_Renderer* CreateRenderer(SDL_Window* pWindow, int index, Uint32 flags);
#pragma endregion
#pragma region 释放
static void DestroyWindow(SDL_Window* pWindow);
static void DestroyRenderer(SDL_Renderer* pRenderer);
static void Quit();
#pragma endregion
#pragma region 报错
static const char* GetError();
#pragma endregion
#pragma region 事件
static bool PollEvent(SDL_Event& event);
#pragma endregion
#pragma region 时间
static Uint32 GetTicks();
static bool TICKS_PASSED(Uint32 currentTime, Uint32 targetTime);
#pragma endregion
#pragma region 渲染
static void SetRenderDrawColor(SDL_Renderer* pRenderer, Uint8 r, Uint8 g, Uint8 b,
Uint8 a);
static void RenderClear(SDL_Renderer* pRenderer);
static void RenderPresent(SDL_Renderer* pRenderer);
static SDL_Texture* GetTexture(SDL_Renderer* pRenderer, const char* fileName);
static void Test(SDL_Renderer* pRenderer, SDL_Texture* pTexture, int width, int height, int x, int y);
#pragma endregion
#pragma region 按钮
static bool GetKeyboardState(int keycode);
#pragma endregion
};
struct lua_State;
namespace LuaWrap
{
void RegisterRenderer(lua_State* L);
}
Renderer.cpp
#include "Renderer.h"
#include "Logger.h"
bool Renderer::SDLInit(Uint32 flags)
{
return 0 == SDL_Init(flags);
}
bool Renderer::SDLImageInit(int flags)
{
return 0 != IMG_Init(IMG_INIT_PNG);
}
SDL_Window* Renderer::CreateWindow(const char* title, int posX, int posY, int width, int hegiht, Uint32 flags)
{
return SDL_CreateWindow(title, posX, posY, width, hegiht, flags);
}
SDL_Renderer* Renderer::CreateRenderer(SDL_Window* pWindow, int index, Uint32 flags)
{
return SDL_CreateRenderer(pWindow, index, flags);
}
void Renderer::DestroyWindow(SDL_Window* pWindow)
{
if (pWindow)
SDL_DestroyWindow(pWindow);
}
void Renderer::DestroyRenderer(SDL_Renderer* pRenderer)
{
if (pRenderer)
SDL_DestroyRenderer(pRenderer);
}
void Renderer::Quit()
{
SDL_Quit();
}
const char* Renderer::GetError()
{
return SDL_GetError();
}
bool Renderer::PollEvent(SDL_Event& event)
{
return SDL_PollEvent(&event);
}
Uint32 Renderer::GetTicks()
{
return SDL_GetTicks();
}
bool Renderer::TICKS_PASSED(Uint32 currentTime, Uint32 targetTime)
{
return SDL_TICKS_PASSED(currentTime, targetTime);
}
void Renderer::SetRenderDrawColor(SDL_Renderer* pRenderer, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
SDL_SetRenderDrawColor(pRenderer, r, g, b, a);
}
void Renderer::RenderClear(SDL_Renderer* pRenderer)
{
SDL_RenderClear(pRenderer);
}
void Renderer::RenderPresent(SDL_Renderer* pRenderer)
{
SDL_RenderPresent(pRenderer);
}
SDL_Texture* Renderer::GetTexture(SDL_Renderer* pRenderer, const char* fileName)
{
SDL_Texture* pTexture = nullptr;
SDL_Surface* pSurface = IMG_Load(fileName);
if (!pSurface)
{
Logger::LogError("IMG_Load() failed in Renderer::GetTexture(): %s", fileName);
return nullptr;
}
pTexture = SDL_CreateTextureFromSurface(pRenderer, pSurface);
SDL_FreeSurface(pSurface);
if (!pTexture)
{
SDL_Log("SDL_CreateTextureFromSurface() failed in GetTexture(): %s", SDL_GetError());
return nullptr;
}
return pTexture;
}
void Renderer::Test(SDL_Renderer* pRenderer, SDL_Texture* pTexture, int width, int height, int x, int y)
{
SDL_Rect rect;
rect.w = width;
rect.h = height;
rect.x = x;
rect.y = y;
SDL_RenderCopy(pRenderer, pTexture, nullptr, &rect);
}
bool Renderer::GetKeyboardState(int keycode)
{
bool bResult = false;
const Uint8* pState = SDL_GetKeyboardState(nullptr);
if (pState)
bResult = pState[keycode];
return bResult;
}
RendererWrap.cpp
#include "Renderer.h"
#include <LuaClient.h>
#include "Logger.h"
int SDLInit(lua_State* L)
{
Uint32 flag = (Uint32)lua_tointeger(L, 1);
lua_pushboolean(L, Renderer::SDLInit(flag));
return 1;
}
int SDLImageInit(lua_State* L)
{
Uint32 flag = (Uint32)lua_tointeger(L, 1);
lua_pushboolean(L, Renderer::SDLImageInit(flag));
return 1;
}
int CreateWindow(lua_State* L)
{
const char* title = lua_tostring(L, 1);
int posX = (int)lua_tointeger(L, 2);
int posY = (int)lua_tointeger(L, 3);
int width = (int)lua_tointeger(L, 4);
int hegiht = (int)lua_tointeger(L, 5);
Uint32 flag = (Uint32)lua_tointeger(L, 6);
lua_pushlightuserdata(L, Renderer::CreateWindow(title, posX, posY, width, hegiht, flag));
return 1;
}
int CreateRenderer(lua_State* L)
{
SDL_Window* pWindow = (SDL_Window*)lua_touserdata(L, 1);
int index = (int)lua_tointeger(L, 2);
Uint32 flag = (Uint32)lua_tointeger(L, 3);
lua_pushlightuserdata(L, Renderer::CreateRenderer(pWindow, index, flag));
return 1;
}
int DestroyWindow(lua_State* L)
{
SDL_Window* pWindow = (SDL_Window*)lua_touserdata(L, 1);
Renderer::DestroyWindow(pWindow);
return 0;
}
int DestroyRenderer(lua_State* L)
{
SDL_Renderer* pRenderer = (SDL_Renderer*)lua_touserdata(L, 1);
Renderer::DestroyRenderer(pRenderer);
return 0;
}
int Quit(lua_State* L)
{
Renderer::Quit();
return 0;
}
int GetError(lua_State* L)
{
auto ss = Renderer::GetError();
lua_pushstring(L, Renderer::GetError());
return 1;
}
int PollEvent(lua_State* L)
{
SDL_Event event;
bool bResult = 1 == SDL_PollEvent(&event);
long type = -1;
if (bResult)
type = event.type;
lua_pushboolean(L, bResult);
lua_pushnumber(L, type);
return 2;
}
int GetTicks(lua_State* L)
{
lua_pushnumber(L, Renderer::GetTicks());
return 1;
}
int TICKS_PASSED(lua_State* L)
{
Uint32 currentTime = (Uint32)lua_tonumber(L, 1);
Uint32 targetTime = (Uint32)lua_tonumber(L, 2);
lua_pushboolean(L, Renderer::TICKS_PASSED(currentTime, targetTime));
return 1;
}
int SetRenderDrawColor(lua_State* L)
{
SDL_Renderer* pRenderer = (SDL_Renderer*)lua_touserdata(L, 1);
Uint8 r = (Uint8)lua_tonumber(L, 2);
Uint8 g = (Uint8)lua_tonumber(L, 3);
Uint8 b = (Uint8)lua_tonumber(L, 4);
Uint8 a = (Uint8)lua_tonumber(L, 5);
Renderer::SetRenderDrawColor(pRenderer, r, g, b, a);
return 0;
}
int RenderClear(lua_State* L)
{
SDL_Renderer* pRenderer = (SDL_Renderer*)lua_touserdata(L, 1);
Renderer::RenderClear(pRenderer);
return 0;
}
int RenderPresent(lua_State* L)
{
SDL_Renderer* pRenderer = (SDL_Renderer*)lua_touserdata(L, 1);
Renderer::RenderPresent(pRenderer);
return 0;
}
int GetTexture(lua_State* L)
{
SDL_Renderer* pRenderer = (SDL_Renderer*)lua_touserdata(L, 1);
const char* fileName = lua_tostring(L, 2);
lua_pushlightuserdata(L, Renderer::GetTexture(pRenderer, fileName));
return 1;
}
int Test(lua_State* L)
{
SDL_Renderer* pRenderer = (SDL_Renderer*)lua_touserdata(L, 1);
SDL_Texture* pTexture = (SDL_Texture*)lua_touserdata(L, 2);
int width = (int)lua_tonumber(L, 3);
int height = (int)lua_tonumber(L, 4);
int x = (int)lua_tonumber(L, 5);
int y = (int)lua_tonumber(L, 6);
Renderer::Test(pRenderer, pTexture, width, height, x, y);
return 0;
}
int GetKeyboardState(lua_State* L)
{
int keycode = (int)lua_tonumber(L, 1);
lua_pushboolean(L, Renderer::GetKeyboardState(keycode));
return 1;
}
int RendererGet(lua_State* L)
{
const char* strKey = lua_tostring(L, 2);
luaL_getmetatable(L, "RendererMetaTable");
lua_pushvalue(L, 2);
lua_rawget(L, -2);
if (lua_isnil(L, -1))
Logger::LogError("Renderer don't have the field: %s.\n%s:%d: in function '%s'", strKey, __FILE__, __LINE__, __FUNCTION__);
return 1;
}
int RendererSet(lua_State* L)
{
luaL_getmetatable(L, "RendererMetaTable");
lua_pushvalue(L, 2);
lua_rawget(L, -2);
if (lua_isnil(L, -1))
{
lua_pop(L, 1);
lua_pushvalue(L, 2);
lua_pushvalue(L, 3);
lua_rawset(L, -3);
}
else
{
if(LUA_TFUNCTION == lua_type(L, -1))
Logger::LogError("The action is not allowed.\n%s:%d: in function '%s'", __FILE__, __LINE__, __FUNCTION__);
else
{
lua_pop(L, 1);
lua_pushvalue(L, 2);
lua_pushvalue(L, 3);
lua_rawset(L, -3);
}
}
return 0;
}
void LuaWrap::RegisterRenderer(lua_State* L)
{
if (!L) return;
lua_newtable(L);
luaL_newmetatable(L, "RendererMetaTable");
lua_pushstring(L, "__index");
lua_pushcfunction(L, RendererGet);
lua_rawset(L, -3);
lua_pushstring(L, "__newindex");
lua_pushcfunction(L, RendererSet);
lua_rawset(L, -3);
lua_pushstring(L, "SDLInit");
lua_pushcfunction(L, SDLInit);
lua_rawset(L, -3);
lua_pushstring(L, "SDLImageInit");
lua_pushcfunction(L, SDLImageInit);
lua_rawset(L, -3);
lua_pushstring(L, "CreateWindow");
lua_pushcfunction(L, CreateWindow);
lua_rawset(L, -3);
lua_pushstring(L, "CreateRenderer");
lua_pushcfunction(L, CreateRenderer);
lua_rawset(L, -3);
lua_pushstring(L, "GetTexture");
lua_pushcfunction(L, GetTexture);
lua_rawset(L, -3);
lua_pushstring(L, "Test");
lua_pushcfunction(L, Test);
lua_rawset(L, -3);
lua_pushstring(L, "DestroyWindow");
lua_pushcfunction(L, DestroyWindow);
lua_rawset(L, -3);
lua_pushstring(L, "DestroyRenderer");
lua_pushcfunction(L, DestroyRenderer);
lua_rawset(L, -3);
lua_pushstring(L, "Quit");
lua_pushcfunction(L, Quit);
lua_rawset(L, -3);
lua_pushstring(L, "GetError");
lua_pushcfunction(L, GetError);
lua_rawset(L, -3);
lua_pushstring(L, "PollEvent");
lua_pushcfunction(L, PollEvent);
lua_rawset(L, -3);
lua_pushstring(L, "SetRenderDrawColor");
lua_pushcfunction(L, SetRenderDrawColor);
lua_rawset(L, -3);
lua_pushstring(L, "RenderClear");
lua_pushcfunction(L, RenderClear);
lua_rawset(L, -3);
lua_pushstring(L, "RenderPresent");
lua_pushcfunction(L, RenderPresent);
lua_rawset(L, -3);
lua_pushstring(L, "GetTicks");
lua_pushcfunction(L, GetTicks);
lua_rawset(L, -3);
lua_pushstring(L, "TICKS_PASSED");
lua_pushcfunction(L, TICKS_PASSED);
lua_rawset(L, -3);
lua_pushstring(L, "GetKeyboardState");
lua_pushcfunction(L, GetKeyboardState);
lua_rawset(L, -3);
lua_setmetatable(L, -2);
lua_setglobal(L, "Renderer");
}
源码下载地址