Day 30 - 故事的最後不是句点,是开始

我成功了吗

经过了这段特别长的暑假,我好像学会了蛮多的东西的!我想对於一个有严重拖延症的患者而言,我看起来好似成功了!(吗?)

好啦其实有些东西跟原本计画的不太一样,原本我想要把去年程序设计的功课全部都写过一遍,但是後来发现写题目的速度太慢,只好改成把上课的影片全部看过一遍,并把他的例子都看一遍这样。

这样的缺点其实显而易见,因为像是在最後我写的游戏里面,想要制作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,但是後来发现他会这样跑....

https://youtu.be/H_PZ9adqqfc

其实还蛮好笑的,但是真的不知道怎麽解决他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

<<:  Dat 27 Transformer

>>:  [Day 27] 阿嬷都看得懂的 JavaScript 怎麽写

增强关联式资料库的参照完整性(enforce the referential integrity of the relational database)

.外键(Foreign key)强制引用完整性。 .主键(Primary key)可增强实体的完整性...

Day 3:Kotlin 程序设计基础入门 (2)

本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...

Day4:Coroutine 的四大特点

在前一篇文章中,我们完成了一个 Coroutine 的程序,并且在最後我们发现了两个特点: 用 Co...

【Day28】为爬虫加上通知 - 用 axios 发出 LINE 通知

成功要选人少的路走,套件要选人多的来用 如何选择 Node.js 中发出 Request 的套件?...

Day03 - 随意玩之 API 讯息内文以及 Sign

今天预计讲解下面两个 (也就是下图的步骤 5) API 的 JSON 内容 把内容加上 Nonce ...