這次是寫了兩個小遊戲,並從裡面學到一點 member function 的用法,還有字串跟血魔量的顯示。
今天學到了第一個是上一個遊戲的進階版
另外我也自己查了字串要怎麼在 window 上顯示
#include<iostream>
#include<SFML\Graphics.hpp>
#include<SFML\Window.hpp>
#include<SFML\System.hpp>
#include<sstream> // for string
using namespace sf;
using namespace std;
// 上一個遊戲的進化版
int main()
{
	RenderWindow window(VideoMode(640, 480), "Simple game");
	window.setFramerateLimit(60);
	//記分板
	// 計分用
	int score = 0;
	Font arial;
	arial.loadFromFile("Arial.ttf");
	ostringstream ssScore;
	ssScore << "Score: " << score;
	Text Score;
	Score.setFont(arial);
	Score.setCharacterSize(30);
	Score.setPosition(0.f, window.getSize().y / 2);
	Score.setString(ssScore.str());
	//血量
	int health = 3;
	ostringstream ssHealth;
	ssHealth << "Health: " << health;
	Text Health;
	Health.setFont(arial);
	Health.setCharacterSize(30);
	Health.setPosition(0.f, (window.getSize().y / 2 + 35));
	Health.setString(ssHealth.str());
	Text gameOver;
	gameOver.setFont(arial);
	gameOver.setFillColor(Color::Red);
	gameOver.setCharacterSize(60);
	gameOver.setPosition(window.getSize().x / 4, window.getSize().y / 2);
	gameOver.setString("Game Over!");
	//敵人 (黑球)
	CircleShape hoop;
	int dir = 0;
	hoop.setRadius(50.f);
	hoop.setFillColor(Color::White);
	hoop.setOutlineThickness(2);
	hoop.setOutlineColor(Color::Blue);
	hoop.setPosition(Vector2f(0, 10.f));
	//操作的腳色 (紅球)
	CircleShape ball;
	bool isShot = false; // 用來操作發射的子彈 / 跟滑鼠做互動
	ball.setRadius(20.f);
	ball.setFillColor(Color::Red);
	ball.setPosition(Vector2f(0, window.getSize().y - ball.getRadius() * 3));
	while (window.isOpen())
	{
		Event event;
		while (window.pollEvent(event))
		{
			if (event.type == Event::Closed)
				window.close();
			if (event.KeyPressed && event.key.code == Keyboard::Escape)
				window.close();
		}
		//Update hoop
		if (hoop.getPosition().x <= 0)
			dir = 1;
		else if (hoop.getPosition().x + 2 * hoop.getRadius() >= window.getSize().x)
			dir = 0;
		if (health != 0)
		{
			if (dir == 0)
			{
				hoop.move(-5.f, 0);
			}
			else
			{
				hoop.move(5.f, 0);
			}
		}
		else // 當血量歸零時就不動
		{
			hoop.setPosition(hoop.getPosition().x, hoop.getPosition().y);
		}
		//Update ball
		// for shooting 
		if (Keyboard::isKeyPressed(Keyboard::Space) && !isShot)
			isShot = true;
		if (!isShot)
			ball.setPosition(Mouse::getPosition(window).x, ball.getPosition().y);
		else
			ball.move(0, -5.f);
		//for collision ball
		if (health > 0)
		{
			if (ball.getPosition().y < 0) // 撞到牆生命就 - 1
			{
				//Reset the ball
				isShot = false;
				ball.setPosition(Vector2f(0, window.getSize().y - ball.getRadius() * 3));
				//扣血
				health--;
				ssHealth.str("");
				ssHealth << "Health: " << health;
				Health.setString(ssHealth.str());
			}
			else if (ball.getGlobalBounds().intersects(hoop.getGlobalBounds())) // 撞到黑球 point + 1
			{
				//Reset the ball
				isShot = false;
				ball.setPosition(Vector2f(0, window.getSize().y - ball.getRadius() * 3));
				score++;
				// 增加分數
				ssScore.str("");
				ssScore << "Score: " << score;
				Score.setString(ssScore.str());
			}
		}
		else // 遊戲終止 
		{
			isShot = false;
			ball.setPosition(Vector2f(0, window.getSize().y - ball.getRadius() * 3));
			ball.setPosition(ball.getPosition().x, ball.getPosition().y); //讓紅球停在原地
			ssHealth.str("");
			ssScore.str("");
		}
		//Drawing
		window.clear(Color::Black);
		window.draw(hoop);
		window.draw(ball);
		window.draw(Score);
		window.draw(Health);
		if (health == 0)
			window.draw(gameOver);
		window.display();
	}
}
首先,這一段是我為了計分(螢幕顯示左下角),而引進的字串
每個段的解釋都在他的註解上
	int score = 0;
	Font arial; // 宣告一個 object 叫 arial 
	arial.loadFromFile("Arial.ttf"); // 從同的資料夾中取 arial 的字檔
	ostringstream ssScore; //他是一個 output stream class -> 也就是專門在印出東西的
	ssScore << "Score: " << score; // 可見 << 也被 operator overloading 
	Text Score; // 這個就是文字了
	Score.setFont(arial); // 想要甚麼文字
	Score.setCharacterSize(30); // 文字大小
	Score.setPosition(0.f, window.getSize().y / 2); //位置
	Score.setString(ssScore.str()); //直接取用 output stream 的字串就可以顯示
// 最後記得要 draw 出來就好了!!
基本上就是照著邏輯寫就可以寫出來了,但是要注意的是那個 .tff 檔要放在跟專案同個資料夾裡面才會被讀到,其實基本上要讀檔案都是要放在同個資料夾裡,除非你有設定絕對路徑。
這個遊戲是躲貓貓(真的是字面上的意思)!
簡單說就是要讓我們操作的角色(狗狗)躲開螢幕右邊隨機出現的貓咪。
#include<iostream>
#include<SFML\Graphics.hpp>
#include<SFML\Window.hpp>
#include<SFML\System.hpp>
#include<sstream> 
using namespace sf;
using namespace std;
/*
	【這次會用 texture 還有 Sprite 做一些事情】
*/
int main()
{	
	//srand(time(NULL));
	RenderWindow window(VideoMode(640, 480), "Cat Do(d)ge");
	window.setFramerateLimit(60);
    /*===========================================================//
	   	【Cats object】
    //===========================================================*/ 
	Texture catTex;
	Sprite cat;
	if (!catTex.loadFromFile("textures/cat.png"))
		throw "couldnt load cat.png!";
	
	cat.setTexture(catTex);
	cat.setScale(Vector2f(0.3f, 0.3f));
	int catSpawnTimer = 15;
	std::vector<Sprite>cats;
	cats.push_back(Sprite(cat));
	/*===========================================================//
		【Dogge object】
	//===========================================================*/
	Texture doggeTex;
	Sprite dogge;
	if (!doggeTex.loadFromFile("textures/dogge.png"))
		throw "couldnt load dogge.png!";
	dogge.setTexture(doggeTex);
	dogge.setScale(Vector2f(0.15f, 0.15f));
	
	/*===========================================================//
		【Dogge hp】
	//===========================================================*/
	int hp = 10;
	RectangleShape hpBar;
	hpBar.setFillColor(Color::Red);
	hpBar.setSize(Vector2f((float)hp * 20.f, 20.f));
	hpBar.setPosition(Vector2f(200.f, 10.f));
	
	// 【game loop】
	while (window.isOpen() && hp > 0) // hp  < 0 的時候就 shut down
	{
		Event event;
		while (window.pollEvent(event))
		{
			if (event.type == Event::Closed)
				window.close();
			if (event.type == Event::KeyPressed && event.key.code == Keyboard::Escape)
				window.close();
		}
		// 【Update】
		
		// 【Update】 Dogge (Player)
		dogge.setPosition(dogge.getPosition().x, Mouse::getPosition(window).y);
		if (dogge.getPosition().y > window.getSize().y - dogge.getGlobalBounds().height)
			dogge.setPosition(dogge.getPosition().x, window.getSize().y - dogge.getGlobalBounds().height);
		if (dogge.getPosition().y < 0)
			dogge.setPosition(dogge.getPosition().x, 0);
		// 【Update】Cats (Enemies)
		// 【Update】Cats movement & spawning
		for (size_t i = 0; i < cats.size(); i++)
		{
			cats[i].move(-7.f, 0.f);
			// 當 cat 跑出螢幕外面的時候,讓它消失
			if (cats[i].getPosition().x < 0 - cat.getGlobalBounds().width)
				cats.erase(cats.begin() + i); 
		}
		if (catSpawnTimer < 40)
			catSpawnTimer++;
		if (catSpawnTimer >= 40)
		{
			cat.setPosition(window.getSize().x, rand()%int(window.getSize().y - cat.getGlobalBounds().height)); // getGlobalBound => 抓到他的邊界
			cats.push_back(Sprite(cat));
			catSpawnTimer = 0;
		}
		// 【Update】Collision
		for (size_t i = 0; i < cats.size(); i++)
		{
			if (dogge.getGlobalBounds().intersects(cats[i].getGlobalBounds()))
			{
				hp--;
				cats.erase(cats.begin() + i);
			}
		}
		
		// 【Update】 UI
		hpBar.setSize(Vector2f((float)hp * 20.f, 20.f));
		// 【Draw】
		window.clear(Color::Black);
		
		// 【Draw】dogge
		window.draw(dogge);
		//【Draw】Cat
		for (size_t i = 0; i < cats.size(); i++)
		{
			window.draw(cats[i]);
		}
		// 【Draw】UI 
		window.draw(hpBar);
		
			
		window.display();
	}
}
最後會長這樣
在這個遊戲裡面有幾個小重點
圖片要找背景是透明的,也就是你會看到圖片後面是有小方格的(但是有些會是透明),像是這個

而且這種檔案只有 .png 所以在找圖的時候要注意一下(有時候後面的方格會騙你)
幾個新增功能:
getGlobalBound // => 抓到他的邊界
rand = random
push_back
碰撞寫法:
if (dogge.getGlobalBounds().intersects(cats[i].getGlobalBounds())) // intersect = 碰到誰 
			{
				hp--;
				cats.erase(cats.begin() + i);
			}
原本讓我有點苦惱的血量還有魔量的顯示問題,好像就在這次的示範裡面解決了,簡單說就是要設
int hp = 10;
int mp = 430;
//建立 hp mp 所要用的方塊
RectangleShape hpBar;
hpBar.setFillColor(Color::Red);
hpBar.setSize(Vector2f((float)hp * 20.f, 20.f));
hpBar.setPosition(Vector2f(200.f, 10.f));
RectangleShape mpBar;
mpBar.setFillColor(Color::Blue);
mpBar.setSize(Vector2f((float)mp * 20.f, 20.f));
mpBar.setPosition(Vector2f(250.f, 10.f));
//最後記得要在 Update 的地方寫 他新的更新,不然就會永遠是一開始初始化的值
//例如在 Collision 要 hp--; 或是 使用技能的時候 mp -= 30;
hpBar.setSize(Vector2f((float)hp * 20.f, 20.f));
mpBar.setSize(Vector2f((float)hp * 20.f, 20.f)); 
一樣也是 這個 YouTuber 的影片!
字體的嵌入:
向量: