[实战]C++加Lua加SDL来重写龙神录弹幕游戏(4):完善Game类

       大部分前期工作都已经完成了,可以正式开始敲游戏代码了。之前显示的都是死循环的窗口,这次终于可以来解决这个问题了,先看看今天的结果。


       这次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");
}

源码下载地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值