cpp
//main.cpp
#include <iostream>
#include <SDL2/SDL.h>
#include "sdl_initiator.hpp"
#include "sdl_error.hpp"
#include "sdl_window.hpp"
#include "sdl_surface.hpp"
using namespace std;
int main(int argc, char* argv[])
{
sdl2::Initiator::Instance().Init(SDL_INIT_VIDEO
| SDL_INIT_AUDIO
| SDL_INIT_EVENTS
| SDL_INIT_TIMER);
if(!sdl2::Initiator::Instance())//重载转换符
{
cerr << "初始化就出错,没得玩了!"
<< sdl2::last_error() << endl;
}
//创建并居中显示宽640,高480的游戏窗口
sdl2::Window wnd("hello sdl"
, sdl2::WindowPosition().Centered(true, true)
, 640, 480
//使用空的特性标志
, sdl2::WindowFlags());
if(!wnd)
{
cerr << sdl2::last_error() << endl;
return -1;
}
//准备背景图表层
sdl2::BitmapSurface bmp_surface("sdl.bmp");
if(!bmp_surface)
{
cerr << sdl2::last_error() << endl;
return -1;
}
//指定白色为bmp_surface的透明色
bmp_surface.EnableColorKey(0xff, 0xff, 0xff, 0);
//准备白云图表层
sdl2::BitmapSurface cloud_surface("cloud.bmp");
if(!cloud_surface)
{
cerr << sdl2::last_error() << endl;
return -1;
}
//白云的透明色是红色
cloud_surface.EnableColorKey(0xff, 0, 0, 0);
//白云有更高级的透明效果
cloud_surface.SetBlendMode(SDL_BLENDMODE_BLEND);
cloud_surface.SetAlphaMod(188); //alpha
//加载背景图
sdl2::BitmapSurface bkgnd_surface("bkgnd.bmp");
if(!bkgnd_surface)
{
cerr << sdl2::last_error() << endl;
return -1;
}
//事件循环
bool Q = false;
while(!Q)//一直循环,直到Q为真
{
SDL_Event event;
//会将队列中拖出的event数据存储到event中
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
Q = true;
break;
}
}//内循环
/*外循环:贴骏马图*/
//需要时,在取窗口表层:这个表层将在window对象
//销毁时释放,不需要手工释放
SDL_Surface* wnd_surface = wnd.GetSurface();
if(wnd_surface)
{
//贴背景->窗口
bkgnd_surface.BlitTo(wnd_surface, nullptr, nullptr);
//贴第一朵白云
SDL_Rect cloud_rect_1{200, 20, 156, 78};
cloud_surface.BlitTo(wnd_surface, nullptr
, &cloud_rect_1);
//贴第二朵白云
SDL_Rect cloud_rect_2{340, 6, 156, 78};
cloud_surface.BlitTo(wnd_surface, nullptr
, &cloud_rect_2);
//贴骏马
SDL_Rect dst_rect{86, 65, 468, 350};
if(bmp_surface.BlitTo(wnd_surface, nullptr, &dst_rect))
{
wnd.UpdateSurface();
}
}
SDL_Delay(1);//防止cpu占用率太高
}//外循环
return 0;
}
cpp
//sdl_error.cpp
#include "sdl_error.hpp"
namespace sdl2
{
char const* last_error()
{
return SDL_GetError();
}
}//sdl2
cpp
//sdl_error.hpp
#ifndef SDL_ERROR_HPP_INCLUDED
#define SDL_ERROR_HPP_INCLUDED
#include <SDL2/SDL.h>
namespace sdl2
{
char const* last_error();
}
#endif // SDL_ERROR_HPP_INCLUDED
cpp
//sdl_initiator.hpp
#ifndef SDL_INITIATOR_HPP_INCLUDED
#define SDL_INITIATOR_HPP_INCLUDED
namespace sdl2
{
struct Initiator
{
private: //单例模式,外界无需使用构造函数
Initiator()
: _init_result(-1)
{
}
public:
static Initiator& Instance()
{
static Initiator Instance;
return Instance;
}
~Initiator()
{
SDL_Quit();
}
void GetVersion(Uint8& major, Uint8& minor, Uint8& patch)
{
SDL_version ver;
SDL_GetVersion(&ver);
major = ver.major;
minor = ver.minor;
patch = ver.patch;
}
bool Init(Uint32 flags = SDL_INIT_EVERYTHING)
{
_init_result = SDL_Init(flags);
return 0 == _init_result;
}
// bool operator bool()
explicit operator bool() const
{
return _init_result == 0;
}
private:
int _init_result;
};//Initiator
}//sdl2
#endif // SDL_INITIATOR_HPP_INCLUDED
cpp
//sdl_surface.hpp
#ifndef SDL_SURFACE_HPP_INCLUDED
#define SDL_SURFACE_HPP_INCLUDED
namespace sdl2
{
struct Surface
{
//代管外部创建好的surface指针
explicit Surface(SDL_Surface* surface)
: _surface(surface)
{
}
/*父类的析构函数使用虚函数的主要原因是为了确保多态时的正确清理。
在C++中,析构函数主要用于释放动态分配的资源。如果父类的析构函数不是虚函数,
那么当使用子类指针删除父类对象时,由于没有动态绑定(晚绑定),
只会调用父类的析构函数,而不会调用子类的析构函数。
这样,子类中的资源可能不会被正确释放,导致内存泄漏或其他问题。
如果父类的析构函数是虚函数,那么当使用子类指针删除父类对象时,
会根据实际对象的类型动态调用相应的析构函数。这样,既可以释放父类占用的资源,
又可以释放子类占用的资源,确保资源的正确释放。
因此,为了确保多态时的正确清理,父类的析构函数应该声明为虚函数。*/
virtual ~Surface()
{
SDL_assert(_surface != nullptr);
SDL_FreeSurface(_surface);
};
bool SetAlphaMod(Uint8 alpha)
{
SDL_assert(_surface != nullptr);
return 0 == SDL_SetSurfaceAlphaMod(_surface, alpha);
}
bool SetBlendMode(SDL_BlendMode const& mode)
{
SDL_assert(_surface != nullptr);
return 0 == SDL_SetSurfaceBlendMode(_surface, mode);
}
// EnableColorKey(Uint32 r, Uint32 g, Uint32 b, Uint32 a)
EnableColorKey(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
SDL_assert(_surface != nullptr);
Uint32 key = SDL_MapRGBA(_surface->format, r, g, b, a);
return 0 == SDL_SetColorKey(_surface, SDL_TRUE, key);
}
bool BlitTo(SDL_Surface* dst_surface, SDL_Rect* src_rect, SDL_Rect* dst_rect)
{
SDL_assert(_surface != nullptr);
return 0 == SDL_BlitSurface(_surface, src_rect, dst_surface, dst_rect);
}
explicit operator bool() const
{
return _surface != nullptr;
}
SDL_Surface* _surface;
};
//来自位图的表层
struct BitmapSurface : public Surface
{
explicit BitmapSurface (char const* filename)
: Surface(SDL_LoadBMP(filename))
{
}
};
}//sdl2
#endif // SDL_SURFACE_HPP_INCLUDED
cpp
//sdl_window.hpp
#ifndef SDL_WINDOW_HPP_INCLUDED
#define SDL_WINDOW_HPP_INCLUDED
#include <SDL2/SDL.h>
namespace sdl2
{
struct WindowPosition
{
WindowPosition()//默认构造
: _x(SDL_WINDOWPOS_CENTERED), _y(SDL_WINDOWPOS_CENTERED)
{
}
WindowPosition(int x, int y)//常规初始化
: _x(x), _y(y)
{
}
~WindowPosition()
{
}
WindowPosition& Centered(bool x_centered = true
, bool y_centered = true)
{
if(x_centered)
_x = SDL_WINDOWPOS_CENTERED;
if(y_centered)
_y = SDL_WINDOWPOS_CENTERED;
}
int _x, _y;
};
struct WindowFlags
{
//默认构造,用于构建一个没有指定任何特性的普通窗口
WindowFlags()
: _flags(0)
{
}
~WindowFlags()
{
}
Uint32 _flags;
};
struct Window
{
Window(char const* title
, WindowPosition const& win_position
, int x, int y
, WindowFlags const& win_flags) //必须有const,否则无法引用右值()
{
_window = SDL_CreateWindow(title
, win_position._x, win_position._y
, x, y
, win_flags._flags);
}
~Window()
{
SDL_DestroyWindow(_window);
}
bool UpdateSurface()
{
SDL_assert(_window != nullptr);
return 0 == SDL_UpdateWindowSurface(_window);
}
SDL_Surface* GetSurface()
{
SDL_assert(_window);
return SDL_GetWindowSurface(_window);
}
explicit operator bool() const
{
return _window != nullptr;
}
Uint32 GetID()
{
SDL_assert(_window != nullptr);
return SDL_GetWindowID(_window);
}
bool SetOpacity(float opacity)
{
SDL_assert(_window != nullptr);
return 0 == SDL_SetWindowOpacity(_window, opacity);
}
void Hide()
{
SDL_assert(_window != nullptr);
SDL_HideWindow(_window);
}
void Show()
{
SDL_assert(_window != nullptr);
SDL_ShowWindow(_window);
}
SDL_Window* _window;
};
}//sdl2
#endif // SDL_WINDOW_HPP_INCLUDED
运行效果如下: