这是另一个运动教程的例子,能向你展示如何通过文件的输入或输出来加载或保存游戏数据。
#include "SDL/SDL.h" #include "SDL/SDL_image.h" #include <string> #include <fstream>
你需要包含fstream头文件来进行文件读写。它是一个标准库,并不是SDL的一部分。
//点
class Dot
{
private:
//点的X/Y坐标
int x, y;
//点的速度
int xVel, yVel;
public:
//初始化变量
Dot();
//处理按键并调整点的速度
void handle_input();
//移动点
void move();
//在屏幕上显示点
void show();
//设置点的x/y坐标
void set_x( int X );
void set_y( int Y );
//获得点的x/y坐标
int get_x();
int get_y();
};
这又是Dot类。这里仅有的一个真正的变化是我们增加了x/y坐标的get/set函数。
bool load_files( Dot &thisDot, Uint32 &bg )
{
//加载点的图像
dot = load_image( "dot.png" );
//如果加载点时出现问题
if( dot == NULL )
{
return false;
}
//打开一个文件以供读取
std::ifstream load( "game_save" );
在
ifstream(即 input file stream,输入文件流)让你能够从一个文件流中获得输入。当你将一个文件名传入构造函数时,它将打开那个文件以供读取。
load_files()函数中,我们加载完图像后创建了一个ifstream对象。
ifstream(即 input file stream,输入文件流)让你能够从一个文件流中获得输入。当你将一个文件名传入构造函数时,它将打开那个文件以供读取。
//如果文件加载完成
if( load != NULL )
{
//坐标
int offset;
//关卡名
std::string level;
//设置x坐标
load >> offset;
thisDot.set_x( offset );
//设置y坐标
load >> offset;
thisDot.set_y( offset );
如果加载文件时出现问题,ifstream对象将会为NULL。
这里我们检查文件是否加载成功。如果加载成功,我们声明"offset"来提取坐标,并声明"level"来决定如何设置背景。
然后,我们首先从文件获得第一个整数并设为点的x坐标。然后,我们获取第二个整数并将其设为y坐标。正如你看到的那样,我们我们采用与cin相同的方式从ifstream中获取整数。那是因为它们都是istream(即 input stream,输入流)。
文件"game_save"的内容将是类似于这样的内容:
0 0
White Level
我们可以看到,既然文件中的和我们在控制台应用中输入的都是字符,那么我们有理由将它们视为几乎一样。
这里我们检查文件是否加载成功。如果加载成功,我们声明"offset"来提取坐标,并声明"level"来决定如何设置背景。
然后,我们首先从文件获得第一个整数并设为点的x坐标。然后,我们获取第二个整数并将其设为y坐标。正如你看到的那样,我们我们采用与cin相同的方式从ifstream中获取整数。那是因为它们都是istream(即 input stream,输入流)。
文件"game_save"的内容将是类似于这样的内容:
0 0
White Level
我们可以看到,既然文件中的和我们在控制台应用中输入的都是字符,那么我们有理由将它们视为几乎一样。
//如果x坐标不合法
if( ( thisDot.get_x() < 0 ) || ( thisDot.get_x() > SCREEN_WIDTH - DOT_WIDTH ) )
{
return false;
}
//如果y坐标不合法
if( ( thisDot.get_y() < 0 ) || ( thisDot.get_y() > SCREEN_HEIGHT - DOT_HEIGHT ) )
{
return false;
}
考虑到用户可以轻易地修改文件,我们也必须检查从文件中获得的坐标是否合法。
//跳过行末
load.ignore();
//获得下一行
getline( load, level );
//如果在尝试加载数据时发生了错误
if( load.fail() == true )
{
return false;
}
然后我们使用
对于使用Visual C++ 6.0的小伙伴们来说,你们必须使用
随后,我们检查从文件读取是否存在问题。如果存在问题,函数
ignore()函数跳过了下一个字符('\n')。接着我们通过getline()函数获得并存储下一行内容。getline()函数与使用>>不同,它会获取直到行末前的所有内容。
对于使用Visual C++ 6.0的小伙伴们来说,你们必须使用
std::getline()。
随后,我们检查从文件读取是否存在问题。如果存在问题,函数
fail()会返回true。
//如果关卡是白色的
if( level == "White Level" )
{
//设置背景色
bg = SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF );
}
//如果关卡是红色的
else if( level == "Red Level" )
{
//设置背景色
bg = SDL_MapRGB( screen->format, 0xFF, 0x00, 0x00 );
}
//如果关卡是绿色的
else if( level == "Green Level" )
{
//设置背景色
bg = SDL_MapRGB( screen->format, 0x00, 0xFF, 0x00 );
}
//如果关卡是蓝色的
else if( level == "Blue Level" )
{
//设置背景色
bg = SDL_MapRGB( screen->format, 0x00, 0x00, 0xFF );
}
既然我们有了关卡字符串,我们就依照这个设置背景色。
//关闭文件
load.close();
}
//如果所有内容加载正常
return true;
}
我们完成读取文件后,我们将文件关闭。
void clean_up( Dot &thisDot, Uint32 &bg )
{
//释放表面
SDL_FreeSurface( dot );
//打开一个文件以供写入
std::ofstream save( "game_save" );
//将坐标写入文件
save << thisDot.get_x();
save << " ";
save << thisDot.get_y();
save << "\n";
在
既然ifstream与cin类似,那么显然ofstream与cout类似。
In this piece of code we write the dot's offsets to a file. 在这部分代码中,我们将点的坐标写入了一个文件。
clean_up()函数中,我们创建了一个ofstream来写入文件。ofstream(即 output file stream,输出文件流)让你能够输出到文件流中。
既然ifstream与cin类似,那么显然ofstream与cout类似。
In this piece of code we write the dot's offsets to a file. 在这部分代码中,我们将点的坐标写入了一个文件。
//背景的RGB值
Uint8 r, g, b;
//从背景色中获取RGB值
SDL_GetRGB( bg, screen->format, &r, &g, &b );
然后我们用
SDL_GetRGB()函数从背景中获取单独的R、G、B值。
//如果背景是白色
if( ( r == 0xFF ) && ( g == 0xFF ) && ( b == 0xFF ) )
{
//将关卡类型写入文件
save << "White Level";
}
//如果背景是红色
else if( r == 0xFF )
{
//将关卡类型写入文件
save << "Red Level";
}
//如果背景是绿色
else if( g == 0xFF )
{
//将关卡类型写入文件
save << "Green Level";
}
//如果背景是蓝色
else if( b == 0xFF )
{
//将关卡类型写入文件
save << "Blue Level";
}
之后,我们写入关卡类型。
//关闭文件
save.close();
//退出SDL
SDL_Quit();
}
最后,我们关闭文件。
//退出标志
bool quit = false;
//初始化
if( init() == false )
{
return 1;
}
//点
Dot myDot;
//背景色
Uint32 background = SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF );
//帧率校准器
Timer fps;
//加载文件
if( load_files( myDot, background ) == false )
{
return 1;
}
这里你可以看到我们使用了
load_files()函数。
//当用户还未推出
while( quit == false )
{
//启动帧计数器
fps.start();
//当有事件要处理
while( SDL_PollEvent( &event ) )
{
//为小点处理事件
myDot.handle_input();
//如果用户按下了按键
if( event.type == SDL_KEYDOWN )
{
//根据按键更改背景
switch( event.key.keysym.sym )
{
case SDLK_1: background = SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF ); break;
case SDLK_2: background = SDL_MapRGB( screen->format, 0xFF, 0x00, 0x00 ); break;
case SDLK_3: background = SDL_MapRGB( screen->format, 0x00, 0xFF, 0x00 ); break;
case SDLK_4: background = SDL_MapRGB( screen->format, 0x00, 0x00, 0xFF ); break;
}
}
//如果用户叉掉了窗口
if( event.type == SDL_QUIT )
{
//退出程序
quit = true;
}
}
//移动点
myDot.move();
//填充背景
SDL_FillRect( screen, screen->clip_rect, background );
//在屏幕上显示点
myDot.show();
//更新屏幕
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
//捕获帧率
if( fps.get_ticks() < 1000 / FRAMES_PER_SECOND )
{
SDL_Delay( ( 1000 / FRAMES_PER_SECOND ) - fps.get_ticks() );
}
}
这里是主循环。要改变背景,你可以按下1,2,3或4。当你再次启动程序时,点和背景将会和你退出程序时的一样。
//清理并保存
clean_up( myDot, background );
}
最终,我们调用
clean_up()函数来清理并保存数据。