SDL_Engine游戏引擎制作 4-Surface 1.x的遗孀

SDL自更新至2.x后,原先在1.x大放异彩的SDL_Surface大部分功能被SDL_Texture所取代,如渲染。不过SDL_Surface还是有用武之地的,比如在使用SDL_ttf.h的部分函数时还是需要用到SDL_Surface,之后再转换成SDL_Texture。

列举一些常用的API(Application Programming Interface),详细可参见SDL wiki

1.IMG_Load。加载图片(.png .jpg 等)并返回SDL_Surface

2.SDL_LoadBMP。 加载BMP图片并返回SDL_Surface

3.SDL_CreateRGBSurface 。根据RGB 宽高等 创建一个新的Surface

4.SDL_BlitSurface 。渲染SDL_Surface 到对应SDL_Surface

5.SDL_FillRect 。在SDL_Surface中填充一个矩形

6.SDL_UpdateWindowSurface。使用这个函数复制这个窗口的Surface到屏幕上。

首先,需要在Window类下增加getWindowSurface函数。

Surface* Window::getWindowSurface()
{
	if(_window != nullptr)
		return Surface::create(SDL_GetWindowSurface(_window));
	return NULL;
}

SDL_GetWindowSurface函数是用来返回该SDL_Window所对应的SDL_Surface(该函数返回的SDL_Surface相同),以便于其他的SDL_Surface可以绘制到该窗口上等。

Surface.h

#ifndef __SDL_Surface_H__
#define __SDL_Surface_H__
#include "SDL.h"
#include "SDL_image.h"
#include "Object.h"
NS_SDL_BEGIN
class Renderer;

class Surface : public Object
{
private:
	SDL_Surface*_surface;
public:
	Surface();
	virtual~Surface();
	//调用这个函数后,就把内存交给了引擎处理,就不需要主动释放,若主动释放,会出错
	static Surface*create(SDL_Surface*surface);
	static Surface*create(const std::string&filepath);
	static Surface*createWithBMP(const std::string&filepath);
	static Surface*create(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask);
	
	bool init(SDL_Surface*sur);
	bool init(const std::string&filepath);
	bool initWithBMP(const std::string&filepath);
	bool init(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask);

	//绘制 可切割,但不能缩放
	int blitSurface(const SDL_Rect*srcRect,Surface*dest,SDL_Rect*destRect);
	//SDL_ConvertSurface(SDL_Surface*src,const SDL_PixelFormat* fmt,Uint32flags)
	Surface*convertSurface(const SDL_PixelFormat*fmt,Uint32 flags);

	//矩形填充函数
	int fillRect(const SDL_Rect*rect,Uint32 color);
	//设置关键色并返回关键色
	Uint32 mapRGB(Uint8 r,Uint8 g,Uint8 b)const;
	Uint32 mapRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)const;
	//设置关键色,对png图片格式尤其有效
	int setColorKey(Uint32 colorkey)const;
	//获得对应位置像素的ARGB值
	Uint32 getARGB(int x,int y)const;
	//混合模式
	int setSurfaceBlendMode(SDL_BlendMode blendMode);
	int getSurfaceBlendMode(SDL_BlendMode*blendMode);

	SDL_Surface*getSDL_Surface()const;
	friend class Renderer;
};
NS_SDL_END
#endif

Surface.cpp

#include "Surface.h"
NS_SDL_BEGIN
Surface::Surface()
	:_surface(nullptr)
{
}

Surface::~Surface()
{
	SDL_FreeSurface(_surface);
	_surface = nullptr;
}

Surface*Surface::create(SDL_Surface*surface)
{
	Surface*sur = new Surface();

	if(sur && sur->init(surface))
		sur->autorelease();
	else
		SDL_SAFE_DELETE(sur);

	return sur;
}

Surface*Surface::create(const std::string& filepath)
{
	auto sur = new Surface();

	if(sur && sur->init(filepath))
		sur->autorelease();
	else
		SDL_SAFE_DELETE(sur);

	return sur;
}

Surface*Surface::createWithBMP(const std::string& filepath)
{
	auto sur = new Surface();

	if(sur && sur->initWithBMP(filepath))
		sur->autorelease();
	else
		SDL_SAFE_DELETE(sur);

	return sur;
}

Surface*Surface::create(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)
{
	Surface* sur = new Surface();

	if(sur && sur->init(flags,width,height,depth,Rmask,Gmask,Bmask,Amask))
		sur->autorelease();
	else
		SDL_SAFE_DELETE(sur);

	return sur;
}

bool Surface::init(SDL_Surface* sur)
{
	_surface = sur;

	return true;
}

bool Surface::init(const std::string&filepath)
{
	_surface = IMG_Load(filepath.c_str());

	if(_surface == nullptr)
	{
		printf("error:%s",IMG_GetError());
		return false;
	}
	return true;
}

bool Surface::initWithBMP(const std::string&filepath)
{
	_surface = SDL_LoadBMP(filepath.c_str());

	if(_surface == nullptr)
	{
		printf("error:%s",SDL_GetError());
		return false;
	}
	return true;
}

bool Surface::init(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)
{
	_surface = SDL_CreateRGBSurface(flags,width,height,depth,Rmask,Gmask,Bmask,Amask);
	
	if(_surface == nullptr)
	{
		printf("error:%s",SDL_GetError());
		return false;
	}
	return true;
}

int Surface::blitSurface(const SDL_Rect*srcRect,Surface*dest,SDL_Rect*destRect)
{
	return SDL_BlitSurface(_surface,srcRect,dest->_surface,destRect);
}

Surface*Surface::convertSurface(const SDL_PixelFormat*fmt,Uint32 flags)
{
	SDL_Surface* sur = SDL_ConvertSurface(_surface,fmt,flags);
	return Surface::create(sur);
}

int Surface::fillRect(const SDL_Rect*rect,Uint32 color)
{
	return SDL_FillRect(_surface,rect,color);
}

Uint32 Surface::mapRGB(Uint8 r,Uint8 g,Uint8 b)const
{
	return SDL_MapRGB(_surface->format,r,g,b);
}

Uint32 Surface::mapRGBA(Uint8 r,Uint8 g,Uint8 b,Uint8 a)const
{
	return SDL_MapRGBA(_surface->format,r,g,b,a);
}

int Surface::setColorKey(Uint32 colorkey)const
{
	return SDL_SetColorKey(_surface,SDL_TRUE,colorkey);
}

Uint32 Surface::getARGB(int x,int y)const
{
	int index = y*_surface->w+x;
	Uint32*pixels = (Uint32*)_surface->pixels;

	return pixels[index];
}

int Surface::setSurfaceBlendMode(SDL_BlendMode mode)
{
	return SDL_SetSurfaceBlendMode(_surface,mode);
}

int Surface::getSurfaceBlendMode(SDL_BlendMode*mode)
{
	return SDL_GetSurfaceBlendMode(_surface,mode);
}

SDL_Surface*Surface::getSDL_Surface()const
{
	return _surface;
}

NS_SDL_END

Surface类包括了创建和销毁,绘制(如blitSurface),以及一些功能函数。另外,setColorKey函数是设置关键色,用于纯背景色图片的背景隐藏。比如一个角色,带有0x00ff00的背景色,如果设置为该关键色的话,在渲染的时候则不会显示该颜色。

接着就是修改main.cpp函数

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

USING_NS_SDL;
using namespace std;
//初始化
void initlize();
void clear();
//绘制
void draw(Surface* screen);
//更新
void update(float dt);
//事件处理
void handleEvents();

bool g_bRunning = true;
Surface* g_pSurface = nullptr;

int main(int argc,char** argv)
{
	float secondsPerFrame = 1.f/60.f;
	float time = 0.f;
	Uint32 nextTick = 0u;
	Uint32 lastTick = 0u;
	int currentFrame = 0;
	//初始化全部子系统
	SDL_Init(SDL_INIT_EVERYTHING);
	IMG_Init(IMG_INIT_PNG);
	//创建窗口
	Window* window = Window::create("SDL_EngineTest",SDL_WINDOWPOS_CENTERED,SDL_WINDOWPOS_CENTERED,800,480,SDL_WINDOW_SHOWN);
	window->retain();
	//获取窗口对应的surface
	Surface* screen = window->getWindowSurface();
	screen->retain();

	initlize();
	//游戏循环
	while (g_bRunning)
	{
		Uint32 currentTick = SDL_GetTicks();
		if(currentTick >= nextTick)
		{
			//帧率固定为方便调试
			float dt = secondsPerFrame;
			time += (currentTick - lastTick) / 1000.f;

			lastTick = currentTick;
			nextTick = lastTick + (Uint32)(secondsPerFrame * 1000);
			//显示当前帧数
			if (time >= 1.f)
			{
				time -= 1.f;
				printf("%d\n",currentFrame);
				currentFrame = 0;
			}
			else
				currentFrame++;

			update(dt);
			
			draw(screen);
			window->updateWindowSurface();
		}
		handleEvents();

		PoolManager::getInstance()->getCurReleasePool()->clear();
	}
	screen->release();
	window->release();
	//清除
	clear();

	PoolManager::purge();

	IMG_Quit();
	SDL_Quit();
	_CrtDumpMemoryLeaks();
	return 0;
}

void initlize()
{
	g_pSurface = Surface::create("crop7_5.png");
	g_pSurface->retain();
}

void clear()
{
	g_pSurface->release();
}

void draw(Surface* screen)
{
	SDL_Rect rect = {};
	screen->fillRect(nullptr,0x00ffff);

	SDL_Rect srcRect = {0,0,94,48};
	SDL_Rect destRect = {100,100,94,48};
	g_pSurface->blitSurface(&srcRect,screen,&destRect);
}

void update(float dt)
{
}

void handleEvents()
{
	SDL_Event event = {};
	//对事件进行轮询
	while(SDL_PollEvent(&event))
	{
		switch(event.type)
		{
		case SDL_QUIT: g_bRunning = false; break;
		}
	}
}

除了增加一些语句外,还增加了一些函数,用于在合适的地方进行初始化,内存回收,绘制,以及逻辑更新。在draw函数中,先在屏幕上用0x00ffff进行渲染整个窗口,然后绘制了一个图片到窗口对应的Surface上,之后调用的window->updateWindowSurface()显示到窗口上。结果如图所示:


本节代码:链接:https://pan.baidu.com/s/100kTbyxnchP0K6y86LTZOw 密码:ye0g

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值