天天看點

C++ 制作FlappyBirdC++ 制作FlappyBird

C++ 制作FlappyBird

Feb.04 UPDATE:

修複了記憶體洩漏問題

簡介

界面:TUI

界面庫: curses.h

git倉庫: https://github.com/EricEricEricJin/FlappyBird/tree/master

效果

C++ 制作FlappyBirdC++ 制作FlappyBird

設計

  • 隔一段距離有一堵牆,牆上開口位置随機
  • 鳥飛,

    j

    按鍵向下移動鳥,

    k

    按鍵向上移動鳥
  • 鳥不可以飛出螢幕外
  • 鳥撞到牆會死
  • 要顯示分數

實作

  • 頭檔案:
    • screen.h
    • map.h
    • mainloop.h
  • 源檔案:
    • screen.cpp
    • map.cpp
    • mainloop.cpp
    • main.cpp
  • 編譯Makefile
    • Makefile

screen.h

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>

#define WALL_PIX 42
#define BIRD_PIX 62

class Screen
{
public:
    Screen(int bird_x);
    void set_bird_y(int *bird_y);
    int get_width();
    int get_height();
    void set_map(int **map, int width, int height);
    void update(int score);
    void die();

private:
    int _bird_x;
    int *_bird_y;
    int **_map;
    int _map_w;
    int _map_h;
};
           

screen.cpp

#include "screen.h"

Screen::Screen(int bird_x)
{
    _bird_x = bird_x;
    initscr();
    cbreak();
    timeout(0);
    noecho();
}

void Screen::set_bird_y(int *bird_y)
{
    _bird_y = bird_y;
}

void Screen::set_map(int **map, int width, int height)
{
    _map = map;
    _map_w = width;
    _map_h = height;
}

void Screen::update(int score)
{
    clear();
    for (int row = 0; row < _map_h; row++)
    {
        for (int col = 0; col < _map_w; col++)
        {
            if (*(*(_map + row) + col) == 1)
            {
                move(row, col);
                addch(WALL_PIX);
            }
        }
    }

    move(*_bird_y, _bird_x);
    addch(BIRD_PIX);

    move(_map_h - 2, _map_w - 6);
    char score_str[5];
    sprintf(score_str, "%d", score);
    addstr(score_str);

    refresh();
}

void Screen::die()
{
    // printf("HAMA");
    clear();
    move(_map_h / 2, _map_w / 2);
    addstr("DIE");
    refresh();
}
           

map.h

#include <stdio.h>
#include <stdlib.h>
#include <ctime>
#include <unistd.h>

struct map_struct
{
    int **_map;
    int _map_h;
    int _map_w;
};

struct obstacle_struct
{
    int empty_y_0;
    int empty_y_1;
};

class Map
{
public:
    Map(int height, int width);
    void setup();
    void step_fwd();
    map_struct _map;

private:
    const int obstacle_num = 6;

    int obstacle_width;

    const int bird_height = 4;

    obstacle_struct *_obstacles;

    int x_shift;

    int first_obstacle_index;

    void create_obstacle(obstacle_struct *obstacle);

    void draw_line(int x, int y_0, int y_1);

    void clear_map();
};
           

map.cpp

#include "map.h"

int rand_seed = 0;

int _random_number(int low_b, int high_b)
{
    rand_seed += 1;
    srand(rand_seed);
    // printf("seed: %d", time(0));
    int ret = rand() % (high_b - low_b) + low_b;
    // printf("%d\n", ret);
    return ret;
}

Map::Map(int height, int width)
{
    _map._map = (int **)malloc(sizeof(int *) * height);

    for (int i = 0; i < height; i++)
    {
        *(_map._map + i) = (int *)malloc(sizeof(int) * width);
    }

    _map._map_h = height;
    _map._map_w = width;

    _obstacles = (obstacle_struct *)malloc(sizeof(obstacle_struct) * 10);

    obstacle_width = width / obstacle_num;
}

void Map::setup()
{
    clear_map();
    for (int i = 0; i < obstacle_num; i++)
    {
        create_obstacle(_obstacles + i);
    }
    x_shift = 0;
    first_obstacle_index = 0;
}

void Map::step_fwd()
{
    clear_map();

    for (int i = first_obstacle_index; i < first_obstacle_index + obstacle_num; i++)
    {
        int index = i % obstacle_num;
        draw_line((i - first_obstacle_index) * obstacle_width + (obstacle_width / 2) - x_shift, (_obstacles + index)->empty_y_0, (_obstacles + index)->empty_y_1);
    }

    x_shift += 1;
    if (x_shift >= obstacle_width)
    {
        create_obstacle(_obstacles + first_obstacle_index);
        first_obstacle_index += 1;
        x_shift = 0;
    }

    if (first_obstacle_index >= obstacle_num)
    {
        first_obstacle_index = 0;
    }
}

void Map::create_obstacle(obstacle_struct *obstacle)
{
    obstacle->empty_y_0 = _random_number(0, _map._map_h - bird_height);
    obstacle->empty_y_1 = _random_number(obstacle->empty_y_0 + bird_height, _map._map_h);
}

void Map::draw_line(int x, int y_0, int y_1)
{
    if (x >= 0 and x < _map._map_w)
    {
        for (int row = 0; row < y_0; row++)
        {
            *(*(_map._map + row) + x) = 1;
        }
        for (int row = y_1; row < _map._map_h; row++)
        {
            *(*(_map._map + row) + x) = 1;
        }
    }
}

void Map::clear_map()
{
    for (int row = 0; row < _map._map_h; row++)
    {
        for (int col = 0; col < _map._map_w; col++)
        {
            *(*(_map._map + row) + col) = 0;
        }
    }
}

           

mainloop.h

#include "map.h"
#include "screen.h"
#include <unistd.h>

#define KEY_UP 107
#define KEY_DOWN 106

#define WIN_W 80
#define WIN_H 24

void main_loop();
           

mainloop.cpp

#include "mainloop.h"

void main_loop()
{
    Map M(WIN_H, WIN_W);
    Screen S(10);

    int bird_y;
    bird_y = WIN_H / 2;
    S.set_bird_y(&bird_y);
    S.set_map(M._map._map, M._map._map_w, M._map._map_h);

    int score = 0;

    while (true)
    {
        M.setup();
        for (int i = 0;; i++)
        {
            char key = getch();
            switch (key)
            {
            case KEY_UP:
                if (bird_y > 0)
                    bird_y -= 1;
                break;
            case KEY_DOWN:
                if (bird_y < WIN_H - 1)
                    bird_y += 1;
                break;
            default:
                break;
            }

            if (i % 100 == 0)
                M.step_fwd();

            if (i % 10 == 0)
                score += 1;

            S.update(score);

            if (M._map._map[bird_y][10] == 1)
                break;

            usleep(1000);
        }

        S.die();
        sleep(1);

        // endwin();
    }
}
           

main.cpp

#include "mainloop.h"

int main()
{

    main_loop();
    return 0;
}
           

編譯Makefile

main:
	g++ main.cpp mainloop.cpp screen.cpp map.cpp -lcurses -o fb.out
           

繼續閱讀