第八章(下)SFML媒体应用开发

游戏进程管理

首先需要修改一下prompt_info函数,让界面能显示开关按键的状态以及游戏的分数

分数显示关键在与将Int型的变量数值以字符的形式显示在信息面板上

添加头文件

下面来讲解一下游戏进程管理。在游戏进程结束的时候让游戏循环能够重新开始。创建布尔变量gameQuit, 初始化为false

 在main函数中用do-while循环来建立一个大循环,在内部建立一个while循环用于获取窗口的消息,并进行游戏重启和退出的判断

在Input函数中也加入gameQuit,使得游戏能够退出

游戏结束的提示信息编写在新创建的gameOver()函数中进行封装

在Draw函数中添加

 在最前方定义变量的地方声明

到此的完整代码(一开始切换成平滑模式时蛇吃果子的音效没有了,问题在Logicstep里面,现在好了) 

#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <iostream>
#include <sstream>
#define WINDOW_WIDTU 80     //窗口的宽度
#define WINDOW_HEIGHT 25    //窗口的高度
#define STAGE_WIDTH 20      //舞台宽度
#define STAGE_HEIGHT 20      //舞台宽度
#define GRIDSIZE 25          //纹理尺寸
#define SCALE      0.5       
#define MAXLENGTH 100        //蛇身最大长度
#define INFO_WIDTH 400
#define STEP 0.1

using namespace sf;
bool gameOver,gameQuit;
const int width = STAGE_HEIGHT;
const int height = STAGE_WIDTH;
int x, y, fruitX, fruitY, score;
int tailX[MAXLENGTH], tailY[MAXLENGTH];
int nTail;
enum eDirectin { STOP = 0, LEFT, RIGHT, UP, DOWN };
eDirectin dir, dir_ing;
int headRotation;
int delay;
int GameMode;
float stepX, stepY;
SoundBuffer sbEat, sbDie;
Sound soundEat, soundDie;
Music bkMusic;
int soundVolume;
bool MusicOn;

void gameOver_info(int _x, int _y);

Font font;
Text text;

//这里我们还没有用到类的封装,所以暂时把window作为全局变量
//对新建窗口的封装,第一个参数是一个VideoMode,表示窗口大小,第二个表示窗口标题,实际上最多可以使用4个参数,最后两个是可选的 -Style 和Cont...
//标题中有宽字符的,字符串前要加L,不然会显示乱码

sf::RenderWindow window(sf::VideoMode(width* GRIDSIZE + INFO_WIDTH, height* GRIDSIZE + GRIDSIZE), L"Keep going");

Texture tBackgroud, tSnakeHead, tSnakeBody, tFruit;         //创建3个纹理对象
Sprite spBackgroud, spSnakeHead, spSnakeBody, spFruit;       //创建3个精灵对象

void Initial()
{
	window.setFramerateLimit(30);    //用来控制窗口的更新频率,每秒设置目标帧数
	if (!font.loadFromFile("data/Fonts/simsun.ttc"))     //选择字体,SFML不能直接访问系统的字体,特殊的字体,需要自己加载
	{
		std::cout << "字体没有找到" << std::endl;
	}
	text.setFont(font);

	tBackgroud.loadFromFile("data/images/BK.png");
	tSnakeHead.loadFromFile("data/images/sh01.png");
	tSnakeBody.loadFromFile("data/images/sb0102.png");
	tFruit.loadFromFile("data/images/sb0202.png");

	if (!sbEat.loadFromFile("data/Audios/Eat01.ogg"))//加载音频
	{
		std::cout << "Eat01.ogg没有找到" << std::endl;
	}
	if (!sbDie.loadFromFile("data/Audios/Die01.ogg"))//加载音频
	{
		std::cout << "Die01.ogg没有找到" << std::endl;
	}
	if (!bkMusic.openFromFile("data/Audios/BGM01.ogg"))//加载音频
	{
		std::cout << "BGM01.ogg没有找到" << std::endl;
	}

	spBackgroud.setTexture(tBackgroud);                   //设置精灵对象的纹理
	spSnakeHead.setTexture(tSnakeHead);
	spSnakeBody.setTexture(tSnakeBody);
	spFruit.setTexture(tFruit);

	spBackgroud.setOrigin(GRIDSIZE / SCALE / 2, GRIDSIZE / SCALE / 2);
	spSnakeHead.setOrigin(GRIDSIZE / SCALE / 2, GRIDSIZE / SCALE / 2);
	spSnakeBody.setOrigin(GRIDSIZE / SCALE / 2, GRIDSIZE / SCALE / 2);
	spFruit.setOrigin(GRIDSIZE / SCALE / 2, GRIDSIZE / SCALE / 2);

	spBackgroud.setScale(SCALE, SCALE);
	spSnakeHead.setScale(SCALE, SCALE);
	spSnakeBody.setScale(SCALE, SCALE);
	spFruit.setScale(SCALE, SCALE);

	soundEat.setBuffer(sbEat);//音效读入缓冲
	soundDie.setBuffer(sbDie);//音效读入缓冲
	bkMusic.play();//背景音播放
	bkMusic.setLoop(true);//背景音循环

	soundVolume = 50;
	MusicOn = true;

	gameOver = false;
	gameQuit = false;
	GameMode = 1;
	stepX = 0.0;
	stepY = 0.0;
	headRotation = 0;
	delay = 0;
	dir = STOP;
	dir_ing = STOP;
	x = width / 2;
	y = height / 2;
	fruitX = rand() % width;
	fruitY = rand() % height;
	score = 0;

	nTail = 1;
	for (int i = 0; i < MAXLENGTH; i++)
	{
		tailX[i] = 0;
		tailY[i] = 0;
	}

}

void Input()
{
	sf::Event event;  //event types 包括Window、Keyboard、Mouse、Joystick,4类消息
	                 //通过 bool Window :: pollEvent (sf :: Event&event)  从窗口顺序询问(polled)事件。
                   	//如果有一个事件等待处理,该函数将返回true,并且事件变量将填充(filled)事件数据。
	                //如果不是,则还函数返回false。同样重要的是要注意,一次可能有多个事件;因此我们必须确保捕获每个可能的事件。
	while (window.pollEvent(event))
	{
		if (event.type == sf::Event::Closed)
		{
			window.close();   //窗口可以移动、调整大小和最小化。但是如果要关闭,需要自己去调用close()函数
			gameOver = true;
			gameQuit = true;
		}
		if (event.type == sf::Event::EventType::KeyReleased && event.key.code == sf::Keyboard::X)
			window.close();
		if (event.type == sf::Event::EventType::KeyReleased && event.key.code == sf::Keyboard::Space)
		{
			if (GameMode == 1)
			{
				GameMode = 2;
			}
			else
				GameMode = 1;
		}
		if (event.type == sf::Event::EventType::KeyReleased && event.key.code == sf::Keyboard::Add)
		{
			soundVolume += 5;
			bkMusic.setVolume(soundVolume);
		}
		if (event.type == sf::Event::EventType::KeyReleased && event.key.code == sf::Keyboard::Subtract)
		{
			soundVolume -= 5;
			bkMusic.setVolume(soundVolume);
		}
		if (event.type == sf::Event::EventType::KeyReleased && (event.key.code == sf::Keyboard::Multiply|| event.key.code == sf::Keyboard::Enter))
		{
			if (MusicOn == true)
			{
				bkMusic.stop();
				MusicOn = false;
			}
			else
			{
				bkMusic.play();
				MusicOn = true;
			}
		}
	}


	if (Keyboard::isKeyPressed(Keyboard::Left))//按键判定
		if (dir != RIGHT)
			dir = LEFT;
	if (Keyboard::isKeyPressed(Keyboard::Right))
		if (dir != LEFT)
			dir = RIGHT;
	if (Keyboard::isKeyPressed(Keyboard::Up))
		if (dir != DOWN)
			dir = UP;
	if (Keyboard::isKeyPressed(Keyboard::Down))
		if (dir != UP)
			dir = DOWN;
}

void Prompt_info(int _x, int _y)
{
	int initialX = 20, initialY = 0;
	int CharacterSize = 24;
	text.setCharacterSize(CharacterSize);
	text.setFillColor(Color(255, 255, 255, 255));
	text.setStyle(Text::Bold);   // |Text::Underlined


	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"■游戏说明:"); window.draw(text);
	initialY += CharacterSize;  //空一行,可以根据需要调整
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"A.蛇身自撞,游戏结束"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"B.蛇可撞墙"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"■操作说明:"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"     □向左移动:←A"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"     □向右移动:→D"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"     □向下移动:↓S"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"     □向上移动:↑W"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"     □开始游戏,任意方向键"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"     □背景音开关: *或回车"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"     □背景音音量:+/-键"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"     □动画模式切换:空格键"); window.draw(text);
	initialY += CharacterSize*1.5;
	text.setPosition(_x + initialX, _y + initialY);
	if (GameMode==1)
	{
		text.setFillColor(Color(0,0,255,255));   //蓝色字体
		text.setString(L"     步进移动"); window.draw(text);
	}
	else
	{
		text.setFillColor(Color(255, 0, 0, 255));//红色字体
		text.setString(L"     连续移动"); window.draw(text);
	}
	window.draw(text);
	text.setFillColor(Color(255, 255, 255, 255));//白色字体
	initialY += CharacterSize*1.5;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"     □退出游戏: x键退出"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"☆ 当前得分:"); window.draw(text);
	text.setFillColor(Color(255, 0, 0, 255));
	initialY += CharacterSize;
	text.setPosition(_x + initialX + CharacterSize*7, _y + initialY);
    CharacterSize = 48;
	text.setCharacterSize(CharacterSize);
	std::stringstream ss;
	ss << score;
	text.setString(ss.str()); window.draw(text);

	CharacterSize = 24;
	text.setCharacterSize(CharacterSize);
	text.setFillColor(Color(255, 255, 255, 255));
	initialY += CharacterSize;
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"☆ 当前难度:"); window.draw(text);
	text.setString(L"              3"); window.draw(text);
	text.setString(L"               级"); window.draw(text);
}

void Logic()         //上一章的代码,没改
{
	int prevX = tailX[0];
	int prevY = tailY[0];
	int prev2X, prev2Y;
	tailX[0] = x;
	tailY[0] = y;//把新增的蛇身坐标存放在0位

	switch (dir)
	{
		//case STOP:
			//break;    为什么这两行不要
	case LEFT:
		x--;
		headRotation = -90;
		break;
	case RIGHT:
		x++;
		headRotation = 90;
		break;
	case UP:     //向上居然是y--
		y--;
		headRotation = 0;
		break;
	case DOWN:
		y++;
		headRotation = 90;
		break;
	default:
		break;
	}
	//if (x > width || x<0 || y>height || y < 0) //蛇头遇到墙壁则停止
	//{
	//	gameOver = true;
	//}



	if (x == fruitX && y == fruitY)   //蛇头遇到果子
	{
		score += 10;
		soundEat.play();//播放吃的音效
		fruitX = rand() % width;
		fruitY = rand() % height;
		nTail++;
	}

	for (int i = 1; i < nTail; i++)
	{
		prev2X = tailX[i];
		prev2Y = tailY[i];
		tailX[i] = prevX;
		tailY[i] = prevY;
		prevX = prev2X;
		prevY = prev2Y;
	}
	for (int i = 1; i < nTail; i++)
	{
		if (tailX[i] == x && tailY[i] == y)
		{
			soundDie.play();    //播放死亡的音效
			gameOver = true;
		}
			
	}

	if (x >= width) x = 0; else if (x < 0)x = width - 1;
	if (y >= height) y = 0; else if (y < 0)y = height - 1;
}

void Draw()
{
	window.clear(Color::Color(255, 0, 255, 255));  //清屏
	Prompt_info(width * GRIDSIZE + GRIDSIZE, GRIDSIZE);

	int detaX = GRIDSIZE / SCALE / 2;
	int detaY = GRIDSIZE / SCALE / 2;
	//绘制背景
	for (int i = 0; i < width; i++)
	{
		for (int j = 0; j < height; j++)
		{
			spBackgroud.setPosition(i * GRIDSIZE + detaX, j * GRIDSIZE + detaY);  //指定纹理的位置
			window.draw(spBackgroud);
		}
	}
	//绘制蛇
	spSnakeHead.setPosition(tailX[0] * GRIDSIZE + detaX, tailY[0] * GRIDSIZE + detaY);
	spSnakeHead.setRotation(headRotation);
	window.draw(spSnakeHead);

	for (int i = 1; i < nTail; i++)
	{
		spSnakeBody.setPosition(tailX[i] * GRIDSIZE + detaX, tailY[i] * GRIDSIZE + detaY);
		window.draw(spSnakeBody);
	}
	//绘制水果
	spFruit.setPosition(fruitX * GRIDSIZE + detaX, fruitY * GRIDSIZE + detaY);
	window.draw(spFruit);

	window.display();                           //把显示缓冲区的内容,显示在屏幕上。SFML采用的是双缓冲机制
}

void LogicStep()           //步径细化
{
	int prevX = tailX[0];
	int prevY = tailY[0];
	int prev2X, prev2Y;
	bool updateFlag = false;

	switch (dir_ing)
	{
		//case STOP:
			//break;    为什么这两行不要
	case LEFT:
		stepX -= STEP;
		if ((stepX < -0.9999) || (stepX > 0.9999))
		{
			x--;
			stepX = 0;
			stepY = 0;
			dir_ing = dir;
			headRotation = -90;
			updateFlag = true;
		}
		break;
	case RIGHT:
		stepX += STEP;
		if ((stepX < -0.9999) || (stepX > 0.9999))
		{
			x++;
			stepX = 0;
			stepY = 0;
			dir_ing = dir;
			headRotation = 90;
			updateFlag = true;
		}
		break;
	case UP:     //向上居然是y--
		stepY -= STEP;
		if ((stepY < -0.9999) || (stepY > 0.9999))
		{
			y--;
			stepX = 0;
			stepY = 0;
			dir_ing = dir;
			headRotation = 0;
			updateFlag = true;
		}
		break;
	case DOWN:
		stepY += STEP;
		if ((stepY < -0.9999) || (stepY > 0.9999))
		{
			y++;
			stepX = 0;
			stepY = 0;
			dir_ing = dir;
			headRotation = 90;
			updateFlag = true;
		}
		break;
	default:
		dir_ing = dir;
		break;
	}
	if (x >= width) x = 0; else if (x < 0)x = width - 1;
	if (y >= height) y = 0; else if (y < 0)y = height - 1;
	tailX[0] = x;
	tailY[0] = y;
	if (updateFlag == true)
	{
		if (x == fruitX && y == fruitY)   //蛇头遇到果子
		{
			score += 10;
            soundEat.play();      
			fruitX = rand() % width;
			fruitY = rand() % height;
			nTail++;
		}

		for (int i = 1; i < nTail; i++)
		{
			prev2X = tailX[i];
			prev2Y = tailY[i];
			tailX[i] = prevX;
			tailY[i] = prevY;
			prevX = prev2X;
			prevY = prev2Y;
		}
		for (int i = 1; i < nTail; i++)
		{
			if (tailX[i] == x && tailY[i] == y)
		   {
			      soundDie.play();    //播放死亡的音效
			      gameOver = true;
		   }
		}
	}
}
void DrawStep()
{
	window.clear(Color::Color(255, 0, 255, 255));  //清屏
	Prompt_info(width * GRIDSIZE + GRIDSIZE, GRIDSIZE);

	int detaX = GRIDSIZE / SCALE / 2;
	int detaY = GRIDSIZE / SCALE / 2;
	//绘制背景
	for (int i = 0; i < width; i++)
	{
		for (int j = 0; j < height; j++)
		{
			spBackgroud.setPosition(i * GRIDSIZE + detaX, j * GRIDSIZE + detaY);  //指定纹理的位置
			window.draw(spBackgroud);
		}
	}
	//绘制蛇
	float stepLength;
	stepLength = stepX + stepY;
	if (stepLength<0)
	{
		stepLength = -stepLength;
	}
	spSnakeHead.setPosition((tailX[0]+stepX) * GRIDSIZE + detaX, (tailY[0]+stepY) * GRIDSIZE + detaY);
	spSnakeHead.setRotation(headRotation);
	window.draw(spSnakeHead);

	for (int i = 1; i < nTail; i++)
	{
		if (tailY[i]==tailY[i-1]&& tailX[i] != tailX[i - 1])//水平跟随
			spSnakeBody.setPosition((tailX[i]+(tailX[i-1]-tailX[i])*stepLength) * GRIDSIZE + detaX, tailY[i] * GRIDSIZE + detaY);
		if (tailY[i] != tailY[i - 1] && tailX[i] == tailX[i - 1])//竖直跟随
			spSnakeBody.setPosition(tailX[i] * GRIDSIZE + detaX, (tailY[i] + (tailY[i - 1] - tailY[i]) * stepLength) * GRIDSIZE + detaY);
		//if (tailY[i] != tailY[i - 1] && tailX[i] != tailX[i - 1])//拐角跟随
		//	spSnakeBody.setPosition((tailX[i] + (tailX[i - 1] - tailX[i]) * stepLength)* GRIDSIZE + detaX, (tailY[i] + (tailY[i - 1] - tailY[i]) * stepLength)* GRIDSIZE + detaY);
		window.draw(spSnakeBody);
	}
	//绘制水果
	spFruit.setPosition(fruitX * GRIDSIZE + detaX, fruitY * GRIDSIZE + detaY);
	window.draw(spFruit);


	if (gameOver)
		gameOver_info(width / 8 * GRIDSIZE, height / 4 * GRIDSIZE);
	window.display();                           //把显示缓冲区的内容,显示在屏幕上。SFML采用的是双缓冲机制
}

void gameOver_info(int _x, int _y)
{
	int initialX = 20, initialY = 0;
	int CharacterSize = 48;
	text.setCharacterSize(CharacterSize);
	text.setFillColor(Color(255, 0, 0, 255));
	text.setStyle(Text::Bold);

	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"    游戏结束!!"); window.draw(text);
	initialY += CharacterSize;
	text.setPosition(_x + initialX, _y + initialY);
	text.setString(L"    Y重新开始/N退出"); window.draw(text);
}
int main()
{
	do 
	{
		Initial();

		while (window.isOpen() && gameOver == false)
		{
			Input();
			switch (GameMode)
			{
			case 1:
				delay++;
				if (delay % 10 == 0)
				{
					delay = 0;
					Logic();
				}
				Draw();
				break;
			case 2:
				LogicStep();
				DrawStep();
				break;
			}
		}
		while (gameOver)
		{
			Event e;
			while (window.pollEvent(e))
			{
				if (e.type == Event::Closed)
				{
					window.close();
					gameOver = false;
					gameQuit = true;
				}
				if (e.type == Event::EventType::KeyReleased && e.key.code == Keyboard::Y)
					gameOver = false;
				if (e.type == Event::EventType::KeyReleased && e.key.code == Keyboard::N)
				{
					gameOver = false;
					gameQuit = true;
				}

			}
		}
	} while (!gameOver);
	system("pause");
	return 0;
}

精灵动画(额外)

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值