SDL_Engine游戏引擎制作 6-Director 负责全局的导演

    在前面几节中,测试代码主要是在main.cpp中编写的。但是,如果接下来还是在main.cpp中修改的话,要么添加静态函数需要传递的参数,要么需要各种全局变量,这两种方法都不是权宜之计。因此,应该有一个能统筹整个游戏开发,并且提供各种需要用到的功能的类,它就是Director(导演)类

导演类主要控制游戏流程,其功能包括:

1.游戏的绘制方面的设定,窗口的大小,FPS显示,帧率设置等。

2.切换当前的游戏场景,暂停或者恢复游戏场景的运行。

导演类的函数大致包括:

1.初始化函数,创建Window和Renderer等。

2.刷新函数,帧率控制和事件监听,一些对象内部状态的刷新。

3.功能函数,比如获取当前的窗口大小等。

4.场景切换函数(待实现)。负责从一个场景切换到另一个场景。

    Director类是把main.cpp中的部分语句封装成自己的成员函数以及属性。

#ifndef __SDL_Director_H__
#define __SDL_Director_H__
#include <ctime>
#include "SDL.h"
#include "Object.h"
#include "Size.h"

NS_SDL_BEGIN

class Window;
class Renderer;

class Director : public Object
{
private:
	static Director* _pInstance;
	//窗口和渲染器
	Window* _window;
	Renderer* _renderer;
	//是否正在运行
	bool _running;
	//每一帧花费的秒数
	float _secondsPerFrame;
	//是否显示状态
	bool _displayStates;
	//帧率控制
	Uint32 _lastTick;
	Uint32 _nextTick;
	
	int _currentFrame;
	int _lastFrame;
	long _lastTime;
	unsigned int _totalFrames;
private:
	Director();
	~Director();
public:
	static Director* getInstance()
	{
		if (nullptr == _pInstance)
		{
			_pInstance = new Director();
		}
		return _pInstance;
	}
	static void purge();
	//初始化函数,创建窗口和渲染器
	bool init(const char* title,int x,int y,int width,int height,Uint32 flags);
	//刷新
	void update();
	//是否正在运行
	bool isRunning()const {return _running;}
	void setRunning(bool running) {_running = running;}
	//TODO:场景切换函数
	//设置FPS
	void setSecondsPerFrame(float secondsPerFrame) {_secondsPerFrame = secondsPerFrame;}
	//状态
	void setDisplayStates(bool displayStates) {_displayStates = displayStates;}
	bool isDisplayStates()const {return _displayStates;}
	//开启屏幕适配
	int setResolutionScale();
	//获取窗口
	Window* getWindow() const {return _window;}
	//获取渲染器
	Renderer* getRenderer() const {return _renderer;}
	//获取窗口可视大小
	Size getVisibleSize() const;
private:
	void handleScenes();
	void updateStates();
};
NS_SDL_END
#endif

Director类为单例类,在程序运行期间有且仅有一个。

init为初始化函数,除了创建窗口和渲染器外以后还会进行一些必要的初始化。

bool Director::init(const char* title,int x,int y,int width,int height,Uint32 flags)
{
	//初始化SDL
	if(SDL_Init(SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS)!=0)
	{
		printf("%s",SDL_GetError());
		return false;
	}
	//创建窗口和渲染器
	_window = Window::create(title,x,y,width,height,flags);
	_renderer = Renderer::create(_window,-1,SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE
		| SDL_RENDERER_PRESENTVSYNC);
	//保持引用
	_window->retain();
	_renderer->retain();
	//初始化随机数种子
	srand((unsigned int)time(nullptr));

	return true;
}

init函数中调用了初始化随机数种子语句,这个函数以后会在获取随机数的宏函数中用到,故在这里进行一次初始化。

void Director::update()
{
	Uint32 currentTick = SDL_GetTicks();
	//进行帧率控制
	if(currentTick >= _nextTick)
	{
		++_totalFrames;
		++_currentFrame;
		//真实帧率
		float dt = _secondsPerFrame;
		_lastTick = currentTick;
		_nextTick = _lastTick + (Uint32)(_secondsPerFrame * 1000);
		//TODO:进行渲染和部分更新
	}
	this->handleScenes();
	//更新FPS
	this->updateStates(currentTick);
}

update函数的主要作用包括:

1.帧率控制。

2.渲染(待添加)。

3.对其他对象进行更新(待添加)。

4.监听事件(待添加)。

int Director::setResolutionScale()
{
	Size originalSize = _window->getWindowSize();
	Size realSize = _window->getRealWindowSize();

	if(originalSize == realSize)
		return 0;

	Size scale = realSize / originalSize;

	return _renderer->renderSetScale(scale.width,scale.height);
}

简单的屏幕适配,即根据创建的窗口大小实际的窗口大小的比进行拉伸,仅在android等移动端才会发挥作用。

Size Director::getVisibleSize() const
{
	return _window->getWindowSize();
}
//TODO
void Director::handleScenes()
{
}

void Director::updateStates(Uint32 currentTick)
{
	//每过一秒就更新一下FPS
	if(currentTick - _lastTime >= 1000)
	{
		//由于是从0开始加,所以得加一
		_lastFrame = _currentFrame;
		_currentFrame = 0;

		_lastTime = currentTick;
		//显示FPS,暂时输出在控制台
		if(_displayStates)
		{
			printf("FPS:%d\n",_lastFrame);
		}
	}
}

updateStates函数的作用就是更新FPS的显示,当前显示在控制台(以后显示在屏幕的左上角)。

Director类创建完成,接下来就是main.cpp的修改。

#include <iostream>
#include "SDL_Engine.h"
#include "SDL.h"
#include "vld.h"

USING_NS_SDL;
using namespace std;

int main(int argc,char** argv)
{

	//窗口创建成功
	if(Director::getInstance()->init("SDL_Engine Test",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,800,480,SDL_WINDOW_SHOWN))
	{
		Director::getInstance()->setDisplayStates(true);
		Director::getInstance()->setSecondsPerFrame(1/60.f);
		Director::getInstance()->setResolutionScale();

		while(Director::getInstance()->isRunning())
		{
			Director::getInstance()->update();
			PoolManager::getInstance()->getCurReleasePool()->clear();
		}
		//系统清除
		Director::purge();
		//释放内存池
		PoolManager::getInstance()->purge();
	}
	return 0;
}

在main函数中,先调用Director的init初始化函数,创建了窗口和渲染器,然后显示FPS,并设置FPS为60帧,并开启了屏幕适配(在android等移动端有效),之后便是一直的循环,每一帧都进行更新和释放池的刷新。在程序退出时,回收内存。另外需要注意的是,main函数中的内容在以后的开发中基本是固定的。

另外,由于本节没有监听事件,所以SDL窗口是无法移动或者是关闭的,这个在添加了事件监听后会消除此现象(在第三四节中有提到)。

本节代码:链接:https://pan.baidu.com/s/13CIQvwjjUHpKcG9B4omRLA 密码:k7hf

猜你喜欢

转载自blog.csdn.net/bull521/article/details/79743703