[实战]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的配置:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值