这次是写了两个小游戏,并从里面学到一点 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 的影片!
字体的嵌入:
向量:
<<: 予焦啦!结论与展望(一):Hoddarla 专案的过去、现在与未来
>>: Progressive Web App 针对应用操作介面优化操作体验 (27)
前言 JS 30 是由加拿大的全端工程师 Wes Bos 免费提供的 JavaScript 简单应用...
OS模组(Python内建) 说明 : os模组是一种与作业系统相关的模组,提供数十种与作业系统沟通...
下载安装包 Armbian Buster 和 Focal之後的作业系统基於完全不同的作业系统,两者所...
使用 Heroku 部署机器学习 API 今日学习目标 动手部署自己的机器学习 API 使用 Her...
Property Graph Diagram (属性图) 与前一篇文章一样是一种针对概念的建模图,他...