不知不觉都做到这里了,是不是再学习完音频之后就考虑做个小游戏呢?可惜不会PS呢...
国庆每天的娱乐活动就是搞搞SDL,和朋友打打篮球,看看电影,吃吃美食之类的,很爽了。
哈哈,切入正题吧,今天学习SDL如何进行图片分割,如果使图片动起来,在贴代码之前,博主说几句废话:
虽然我们现在写的是测试Demo,但不要以为就可以随意为之,良好的代码风格和设计思想在哪都是需要注意的
下面来看看博主的工程结构:
工程下多了一个sheet.jpg,这就是今天要用于切割的图片
图片是400 * 400 pixel(像素)
接下来我们要做的工作就是,把这张图切割成4个圆,并且把背景变成透明
说明:博主在SDL_fun.h这个头文件中增加了一个类,用于管理全局唯一的屏幕接口,我的考虑是,screen surface实际上只需要建立一个。并且,其他的surface实际上都是“依赖”于这个surface才能显示出来的。在SDL中,多次SDL_SetVideoMode()的效果实际上是保留了最后一次的surface作为了screen surface,所以,多次SDL_SetVideoMode()其实是没有实际意义的。
/*
* SDL_fun.h
*
* Created on: 2013-10-1
* Author: Christian
*/
#ifndef SDL_FUN_H_
#define SDL_FUN_H_
#include <iostream>
#include <SDL/SDL.h>
class ScreenSurface{
public:
ScreenSurface(SDL_Surface* screen);
ScreenSurface(int width, int height, int bpp = 32, Uint32 flags = SDL_SWSURFACE);
~ScreenSurface(void);
bool flip(void) const;
SDL_Surface* acquire(void);
private:
SDL_Surface* screen;
};
void drawBitmap(ScreenSurface s, const char* fileName);
void readKeyboard(ScreenSurface s);
void getRadioInfo(ScreenSurface s);
void renderPictures(ScreenSurface s, const char* fgFile, const char* bgFile);
void drawClips(ScreenSurface s, const char* file, SDL_Rect* clip = NULL, int size = 0);
#endif /* SDL_FUN_H_ */
大家看到了吧,其中的ScreenSurface的flip方法是将数据化的SDL_Surface Push到屏幕上,让用户看到,而acquire是获取当前的屏幕接口,其他的就是一些构造方法和构析方法。下面的方法都需要传一个ScreenSurface,这样是不是就统一管理了呢?全局就只需创建一个唯一的通向物理屏幕的接口~
头文件中的drawClips就是图片分割的方法,下面是它的实现:
/** 图片切割 */
void drawClips(ScreenSurface s, const char* file, SDL_Rect* clip, int size) {
SDL_Surface* dots = IMG_Load(file);
SDL_Surface* optimizedImage = NULL;
if (s.acquire() == 0 || dots == 0 || clip == NULL) {
std::cerr << SDL_GetError() << " 227 \n";
return;
} else {
optimizedImage = SDL_DisplayFormat(dots);
SDL_FreeSurface(dots);
//这两句代码把图片背景置为透明
Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF);
SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
}
//把整个背景填充为白色
SDL_FillRect(s.acquire(), &s.acquire()->clip_rect,
SDL_MapRGB(s.acquire()->format, 0xFF, 0xFF, 0xFF));
bool over = false;
SDL_Event event;
SDL_Rect offset;
while (!over) {
SDL_ClearError();
SDL_PollEvent(&event);
if (event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE) {
over = true;
}
//参数size代表图片切割的数量,也就是clip数组的数量
for (int x = 0; x < size; x++) {
offset.x = clip[x].x + x*100;
offset.y = clip[x].y + x*100;
if (SDL_BlitSurface(optimizedImage, &clip[x], s.acquire(), &offset)
!= 0) {
std::cerr << SDL_GetError() << " 275 \n";
break;
}
}
if (!s.flip()) {
std::cerr << SDL_GetError() << " 281\n";
break;
}
}
SDL_FreeSurface(dots);
}
再来看看main的入口函数:
//===================================================================
// Name : SDL_demo.cpp
// Author : Christian
// Version :
// Copyright : Copyright (c) Christian 2012/9/28
// Description : Hello World in C++, Ansi-style
//===================================================================
#include "include/SDL_init.h"
#include "include/SDL_fun.h"
using namespace std;
//这里定义了4个clip
void cutPic(ScreenSurface s){
SDL_Rect clip[4];
//Clip range for the top left
clip[0].x = 0;
clip[0].y = 0;
clip[0].w = 100;
clip[0].h = 100;
//Clip range for the top right
clip[1].x = 100;
clip[1].y = 0;
clip[1].w = 100;
clip[1].h = 100;
//Clip range for the bottom left
clip[2].x = 0;
clip[2].y = 100;
clip[2].w = 100;
clip[2].h = 100;
//Clip range for the bottom right
clip[3].x = 100;
clip[3].y = 100;
clip[3].w = 100;
clip[3].h = 100;
drawClips(s, "sheet.jpg", clip, 4);
}
int main(int argc, char* args[]) {
//SDL_putenv("SDL_VIDEODRIVER=directx");
//putenv("SDL_VIDEODRIVER=directx");
createSDL("Christian Test");
ScreenSurface s(600, 600);
//drawBitmap(s, "3.jpg");
//readKeyboard();
//getRadioInfo();
//renderPictures(s, "3.jpg", "2.bmp");
cutPic(s);
atexit(destorySDL);
return EXIT_SUCCESS;
}
下面是运行效果:
![](http://static.oschina.net/uploads/space/2013/1002/162910_OIrn_250247.jpg)
博主是按照官网文档去做的,为什么图片背景还是没有完全透明请高手解答一下。
好了,图片切割完成!下面讲讲如果对图片进行移动~第一章的时候咱们不是讲了SDL的按键的事件功能么,是时候结合一下了~
下面是改动后的drawClips函数:
/** 图片切割及移动 */
void drawClips(ScreenSurface s, const char* file, SDL_Rect* clip, int size) {
SDL_Surface* dots = IMG_Load(file);
SDL_Surface* optimizedImage = NULL;
if (s.acquire() == 0 || dots == 0 || clip == NULL) {
std::cerr << SDL_GetError() << " 227 \n";
return;
} else {
optimizedImage = SDL_DisplayFormat(dots);
SDL_FreeSurface(dots);
Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 0, 0xFF, 0xFF);
SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
}
//把整个背景填充为白色
SDL_FillRect(s.acquire(), &s.acquire()->clip_rect,
SDL_MapRGB(s.acquire()->format, 0xFF, 0xFF, 0xFF));
bool over = false;
SDL_Event event;
SDL_Rect offset;
Uint8* keys;
offset.x = 0;
offset.y = 0;
while (!over) {
//从这里获取每个按键的即时状态,监听8个按键,w/s/a/d/up/down/left/right
keys = SDL_GetKeyState(0);
if (keys[SDLK_UP] || keys[SDLK_w]) {
offset.y -= 1;
}
if (keys[SDLK_DOWN] || keys[SDLK_s]) {
offset.y += 1;
}
if (keys[SDLK_LEFT] || keys[SDLK_a]) {
offset.x -= 1;
}
if (keys[SDLK_RIGHT] || keys[SDLK_d]) {
offset.x += 1;
}
SDL_ClearError();
SDL_PollEvent(&event);
if (event.type == SDL_QUIT || event.key.keysym.sym == SDLK_ESCAPE) {
over = true;
}
for (int x = 0; x < size; x++) {
// offset.x = clip[x].x;
// offset.y = clip[x].y;
if (SDL_BlitSurface(optimizedImage, &clip[x], s.acquire(), &offset)
!= 0) {
std::cerr << SDL_GetError() << " 275 \n";
break;
}
}
if (!s.flip()) {
std::cerr << SDL_GetError() << " 281\n";
break;
}
}
SDL_FreeSurface(dots);
}
好了,就这么简单~只需在轮询线程内加上事件监听,判断后做出响应即可
运行结果图:
![](http://static.oschina.net/uploads/space/2013/1002/163616_JCjQ_250247.jpg)
不好意思的说,这是我乱按上下左右键的结果...
这里是Freestyletime@foxmail.com,欢迎交流。
本人原创作品,转载请标明出处。