经过了这段特别长的暑假,我好像学会了蛮多的东西的!我想对於一个有严重拖延症的患者而言,我看起来好似成功了!(吗?)
好啦其实有些东西跟原本计画的不太一样,原本我想要把去年程序设计的功课全部都写过一遍,但是後来发现写题目的速度太慢,只好改成把上课的影片全部看过一遍,并把他的例子都看一遍这样。
这样的缺点其实显而易见,因为像是在最後我写的游戏里面,想要制作header file 还有他的 game.cpp的时候,忽然发现之前讲过的东西快忘掉,不过也还好我都有打成文章,才可以让我在打这些东西的时候有个依据可以参考。
是的,我做出来了! 虽然最终的成果跟我想像的完全不太一样XD。
先来放上这次的影片内容吧!
他就是一个射击游戏,要利用 WSAD 控制上下左右,用滑鼠左键发射,然後 boss 也会射你,并且会一直追着你跑><。
开发的过程,其实没有到很辛苦,因为大部分的内容都在之前的影片里面有学到了,这次只有发现几个比较困难的点。
因为飞船到滑鼠是一个变量,是一直随着两者的位置不同而改变,所以在这方面,就要使用小杰老师禁止"现在的我"使用的 vector。 对不起老师!
我在里面设置了四个变量
2 for player
aimDir
,也就是玩家与滑鼠之间的向量aimDirNrom
,简单说就是 A / |A| (A为向量)2 for boss
bAimDir
,也就是玩家与boss之间的向量bAimDirNrom
,简单说就是 A / |A| (A为向量)用向量就可以让炮弹从玩家射向指标,或是让 boss 可以追踪玩家。
原本我想要的炮弹是类似雷射光射出的感觉,但是後来发现,如果不设置 rotate,就只会指向同一个方向。为了解决这个问题,我用了 .rotate()
member funtion,但是後来发现他会这样跑....
其实还蛮好笑的,但是真的不知道怎麽解决他QQ
未来有机会会找到方法的! 或是请各位大神们给个意见!
其他的部分就还好了!
但是比较特别的是,我把游戏中自定义的 class 改放到 header file 中,整个版面变得比较清爽一些。
#include<SFML/Graphics.hpp>
#include<iostream>
using namespace std;
using namespace sf;
/*
游戏所需要的 class 宣告
*/
class Bullet
{
public:
Sprite shape;
Vector2f currVelocity;
float maxSpeed;
Bullet(Texture* texture);
~Bullet() {}
};
class Shield
{
public:
Sprite shape;
Shield(Texture* texture, Vector2f pos);
~Shield(){}
};
class Player
{
public:
Sprite shape;
Texture* texture;
int lvl = 1;
int exp = 0;
int HP;
int HPMax;
int MP;
int MPMax;
// for bullets
vector<Bullet> bullets;
Vector2f currVelocity;
float maxSpeed;
// for shield
vector<Shield> shield;
Player(Texture* texture);
~Player() {}
};
class Boss
{
public:
Sprite shape;
int HP;
int HPMax;
vector<Bullet> bullets;
Vector2f currVelocity;
Boss(Texture* texture);
~Boss() {}
};
还有 Game.cpp 里面
#include"MyGame.h"
#include<iostream>
#include<SFML/Graphics.hpp>
using namespace std;
using namespace sf;
Bullet::Bullet(Texture* texture) : currVelocity(0.f, 0.f), maxSpeed(10.f)
{
this->shape.setTexture(*texture);
this->shape.setScale(Vector2f(0.03f, 0.03f));
this->shape.rotate(90);
}
Shield::Shield(Texture* texture, Vector2f pos)
{
this->shape.setTexture(*texture);
this->shape.setScale(0.1f, 0.1f);
this->shape.setPosition(pos);
}
Player::Player(Texture* texture)
{
this->HPMax = this->lvl * 103 + 53;
this->HP = this->HPMax;
this->MPMax = this->lvl * 103 + 53;
this->MP = this->MPMax;
this->texture = texture;
this->shape.setTexture(*texture);
this->shape.setScale(Vector2f(0.15f, 0.15f));
}
Boss::Boss(Texture* texture)
{
this->HPMax = 500;
this->HP = this->HPMax;
this->shape.setTexture(*texture);
this->shape.setScale(0.5f, 0.5f);
}
最後就是游戏的整段程序码,里面都有 comment 应该算写得很仔细!
#include<iostream>
#include<SFML\Graphics.hpp>
#include<SFML\Window.hpp>
#include<SFML\System.hpp>
#include<sstream>
#include<cstdlib>
#include<math.h>
#include<cmath>
#include<vector>
#include"MyGame.h"
using namespace std;
using namespace sf;
int main()
{
srand(time(NULL));
RenderWindow window(VideoMode(1680, 840), "The Final Game!");
window.setFramerateLimit(200);
/*===========================================================//
Init Text
//===========================================================*/
Font font;
font.loadFromFile("font/Arial.ttf");
/*===========================================================//
Init Textures
//===========================================================*/
Texture playerTex;
playerTex.loadFromFile("textures/spaceship.png");
Texture humanBossTex;
humanBossTex.loadFromFile("textures/Boss1.png");
Texture earthBossTex;
earthBossTex.loadFromFile("textures/Boss2.png");
Texture deadHumanBossTex;
deadHumanBossTex.loadFromFile("textures/Boss1-2.png");
Texture deadEarthBossTex;
deadEarthBossTex.loadFromFile("textures/Boss2-3.png");
Texture bulletTex;
bulletTex.loadFromFile("textures/normalshoot.png");
Texture bossBulletTex;
bossBulletTex.loadFromFile("textures/enemyShoot.png");
/*===========================================================//
UI init
//===========================================================*/
Text gameOverText;
gameOverText.setFont(font);
gameOverText.setCharacterSize(120);
gameOverText.setFillColor(Color::Red);
gameOverText.setPosition(100.f, window.getSize().y / 2);
gameOverText.setString("Game Over!!!!");
Text youWin;
youWin.setFont(font);
youWin.setCharacterSize(120);
youWin.setFillColor(Color::Red);
youWin.setPosition(100.f, window.getSize().y / 2);
youWin.setString("You Win!!!!");
/*===========================================================//
Player init
//===========================================================*/
int score = 0;
Player player(&playerTex);
int shootTimer = 20;
// for hp 显示
RectangleShape hpBar;
hpBar.setFillColor(Color::Red);
// for mp 显示
RectangleShape mpBar;
mpBar.setFillColor(Color::Blue);
/*===========================================================//
Boss init
//===========================================================*/
Boss weirdFace(&humanBossTex);
weirdFace.shape.setPosition(window.getSize().x / 2, window.getSize().y / 2);
int bShootTimer = 15;
Text wHpText;
wHpText.setFont(font);
wHpText.setCharacterSize(12);
wHpText.setFillColor(Color::White);
RectangleShape bHpBar;
bHpBar.setFillColor(Color::Red);
/*===========================================================//
Bullet init
//===========================================================*/
Bullet b1(&bulletTex);
Bullet b2(&bossBulletTex);
vector<Bullet> pBullets;
vector<Bullet> bBullets;
Vector2f playerCenter;
Vector2f mousePosWindow;
Vector2f aimDir;
Vector2f aimDirNorm;
Vector2f rotateOrigin = Vector2f(1.f, 1.f);
Vector2f bossCenter;
Vector2f bAimDir;
Vector2f bAimDirNorm;
//cout << aimDirNorm.x << " " << aimDirNorm.y << endl;
while (window.isOpen())
{
Event event;
while (window.pollEvent(event))
{
if (event.type == Event::Closed)
window.close();
if (Keyboard::isKeyPressed(Keyboard::Escape))
window.close();
}
if (player.HP >= 0 && weirdFace.HP >= 0)
{
/*===========================================================//
【Update】 player
//===========================================================*/
// movement
if (Keyboard::isKeyPressed(Keyboard::W))
player.shape.move(0.f, -3.f);
if (Keyboard::isKeyPressed(Keyboard::S))
player.shape.move(0.f, 3.f);
if (Keyboard::isKeyPressed(Keyboard::D))
player.shape.move(3.f, 0.f);
if (Keyboard::isKeyPressed(Keyboard::A))
player.shape.move(-3.f, 0.f);
// collision with window
if (player.shape.getPosition().x <= 0) // left
player.shape.setPosition(0.f, player.shape.getPosition().y);
if (player.shape.getPosition().x >= window.getSize().x - player.shape.getGlobalBounds().width) // right
player.shape.setPosition(window.getSize().x - player.shape.getGlobalBounds().width, player.shape.getPosition().y);
if (player.shape.getPosition().y <= 0) // Top
player.shape.setPosition(player.shape.getPosition().x, 0.f);
if (player.shape.getPosition().y >= window.getSize().y - player.shape.getGlobalBounds().height) // bottom
player.shape.setPosition(player.shape.getPosition().x, window.getSize().y - player.shape.getGlobalBounds().height);
// hp & mp Bars and Text set
hpBar.setPosition(player.shape.getPosition().x + 10, player.shape.getPosition().y - 25.f);
mpBar.setPosition(player.shape.getPosition().x + 9, player.shape.getPosition().y - 15.f);
// HP & MP set
/*===========================================================//
Update】 controls
//===========================================================*/
if (shootTimer < 20)
shootTimer++;
/*===========================================================//
【Update】 Bullet
//===========================================================*/
playerCenter = Vector2f(player.shape.getPosition().x + 100.f, player.shape.getPosition().y - 15.f);
mousePosWindow = Vector2f(Mouse::getPosition(window));
aimDir = mousePosWindow - playerCenter;
aimDirNorm = Vector2f(aimDir.x / sqrt(pow(aimDir.x, 2) + pow(aimDir.y, 2)), aimDir.y / sqrt(pow(aimDir.x, 2) + pow(aimDir.y, 2)));
if (Mouse::isButtonPressed(Mouse::Left) && shootTimer >= 20)
{
b1.shape.setPosition(playerCenter);
b1.currVelocity = aimDirNorm;
pBullets.push_back(Bullet(b1));
shootTimer = 0; // reset timer
}
for (size_t i = 0; i < pBullets.size(); i++)
{
pBullets[i].shape.move(pBullets[i].currVelocity);
//Out of bounds
if (pBullets[i].shape.getPosition().x < 0 || pBullets[i].shape.getPosition().x > window.getSize().x
|| pBullets[i].shape.getPosition().y < 0 || pBullets[i].shape.getPosition().y > window.getSize().y)
{
pBullets.erase(pBullets.begin() + i);
}
else
{
//Enemy collision
if (pBullets[i].shape.getGlobalBounds().intersects(weirdFace.shape.getGlobalBounds()))
{
if (weirdFace.HP < 1)
{
weirdFace.shape.setTexture(deadHumanBossTex);
}
else
weirdFace.HP -= 5.3;
pBullets.erase(pBullets.begin() + i);
}
}
}
/*===========================================================//
【Update】 Enemy
//===========================================================*/
// Enemy bullets
Vector2f bossCenter = Vector2f(weirdFace.shape.getPosition().x + 100.f, weirdFace.shape.getPosition().y + 100.f);
bAimDir = playerCenter - bossCenter;
Vector2f bAimDirNorm = Vector2f(bAimDir.x / sqrt(pow(bAimDir.x, 2) + pow(bAimDir.y, 2)), bAimDir.y / sqrt(pow(bAimDir.x, 2) + pow(bAimDir.y, 2)));
if (bShootTimer >= 15)
{
b2.shape.setPosition(bossCenter);
b2.currVelocity = bAimDirNorm;
bBullets.push_back(Bullet(b2));
bShootTimer = 0; // reset timer
weirdFace.shape.move(bAirDirNorm * 10.f);
}
else
bShootTimer++;
for (size_t i = 0; i < bBullets.size(); i++)
{
bBullets[i].shape.move(bBullets[i].currVelocity);
//Out of bounds
if (bBullets[i].shape.getPosition().x < 0 || bBullets[i].shape.getPosition().x > window.getSize().x
|| bBullets[i].shape.getPosition().y < 0 || bBullets[i].shape.getPosition().y > window.getSize().y)
{
bBullets.erase(bBullets.begin() + i);
}
else
{
//Enemy collision
if (bBullets[i].shape.getGlobalBounds().intersects(player.shape.getGlobalBounds()))
{
player.HP -= 0.7;
bBullets.erase(bBullets.begin() + i);
}
}
}
// for enemy collision with player
if (weirdFace.shape.getGlobalBounds().intersects(player.shape.getGlobalBounds()))
{
player.HP -= 1.5;
player.shape.move(bAirDirNorm * 150.f);
}
bHpBar.setPosition(weirdFace.shape.getPosition().x + 5.f, weirdFace.shape.getPosition().y - 25.f);
/*===========================================================//
【Update】 UI
//===========================================================*/
hpBar.setSize(Vector2f((float)player.HP * 0.45f, 10.f));
mpBar.setSize(Vector2f((float)player.MP * 0.45f, 10.f));
bHpBar.setSize(Vector2f((float)weirdFace.HP * 0.45f, 10.f));
}
/*===========================================================//
【Draw】
//===========================================================*/
window.clear();
/*===========================================================//
【Draw】 player
//===========================================================*/
window.draw(player.shape);
window.draw(hpBar);
window.draw(mpBar);
/*===========================================================//
【Draw】 bullets
//===========================================================*/
for (size_t i = 0; i < pBullets.size(); i++)
{
window.draw(pBullets[i].shape);
}
for (size_t i = 0; i < bBullets.size(); i++)
{
window.draw(bBullets[i].shape);
}
/*===========================================================//
【Draw】 Boss
//===========================================================*/
window.draw(weirdFace.shape);
window.draw(bHpBar);
/*===========================================================//
【Draw】 UI
//===========================================================*/
if (player.HP <= 0)
{
window.draw(gameOverText);
}
if (weirdFace.HP <= 0)
{
window.draw(youWin);
}
window.draw(player.shape);
window.display();
}
}
最後真的成功做了出来!
其实我非常感动,因为我用到了一些我原本完全看不懂的东西,真的是从零开始慢慢学会的。
真的非常感谢 Sen 还有 Alu 找我参加这次的活动,没有他们就没有现在的我! 也谢谢他们在这几个月的帮助与解惑(还有杰哥的解惑!) ! 大大大感谢 !
在这段时间,我很明显发现到自己的成长,原本甚麽东西都看不懂,但是忍住一看到不懂就马上想要问人的冲动,自己去 google,最後找到自己喜欢的答案,其实这段过程也会深深刻在脑海里面,有时候也会在写其他东西的时候突然想起来,真的是受益良多 !
虽然跟别人相比,我现在顶多只是 新手 + lvl.1(大概就是刚出新手村,要去弓箭手村解任务吧)(包含写文章还有写 code,还有表达能力QQ),但是我相信继续紮实的训练,也会成为一个厉害的人的!
希望看到这篇文章的人也可以成为你们想成为的人ㄉ,共勉之。
希望我未来看到我现在写的东西会哭出来,这就代表我变强很多了><
还记得我们是个 team 吧,其他人写的文章也都很强 ! 这边推爆 !!!!!
【团队成员】
Name | 标题 | Tags |
---|---|---|
ALu | NFT 网站与 MetaMask 连动的 Owners 登入系统 | BlockChain,Modern Web |
Cooksuhr | 1995到2021,php到react网站开发历程 | Modern Web |
ExcitedMail | 杰哥的考研纪录 | Computer Science |
foodchain | 三十天内用C++写出一个小游戏 | Software Development |
momojn | C++ 三十天学习纪录 | Software Development |
chen_yanlong | 学密码学也猜不到你的手机密码 | Cryptography |
yywoli | 从资料库到资料分析视觉化 | Data Analysis |
>>: [Day 27] 阿嬷都看得懂的 JavaScript 怎麽写
.外键(Foreign key)强制引用完整性。 .主键(Primary key)可增强实体的完整性...
本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...
在前一篇文章中,我们完成了一个 Coroutine 的程序,并且在最後我们发现了两个特点: 用 Co...
成功要选人少的路走,套件要选人多的来用 如何选择 Node.js 中发出 Request 的套件?...
今天预计讲解下面两个 (也就是下图的步骤 5) API 的 JSON 内容 把内容加上 Nonce ...