Rapid-Roll
A classical game in Nokia, which is implemented by SDL2 & C/C++
項目地址:https://github.com/Joke-Lin/Rapid-Roll
遊戲介紹
一個經典的諾基亞小遊戲 --------- 綵球滑梯
- 通過 A/D 控制小球左右移動,接觸到尖刺失去一條生命;吃到紅色小球增加一條生命;生命上限爲5條
- 難度隨分數的增加越來越大,分數達到10000難度封頂 (通過加大障礙物移動速度增加難度)
- 開始和結束界面均設置按鈕,開始界面爲開始遊戲,結束界面爲重新開始,不單獨設置退出,直接點擊關閉窗口即可退出
- P鍵即可暫停遊戲,在按 A/D 繼續遊戲
Demo:
1、開始界面
2、運行界面
3、遊戲結束界面
文件目錄
源代碼只有一個main.cpp在Rapid-Roll工程目錄下
├─EXE # 項目最後編譯結果,exe所在目錄
│ └─src # 資源文件
│ ├─Audio # 音效文件
│ └─TTF # 字體文件
└─Rapid-Roll # 工程目錄 Visual Studio 結構
├─Debug # Debug文件夾
│ └─src
│ ├─Audio
│ └─TTF
└─Rapid-Roll # 工程文件
├─Debug
│ └─Rapid-Roll.tlog
├─Release
│ └─Rapid-Roll.tlog
├─Audio
└─TTF
項目環境
SDL2 + Visual Studio 2017 開發,代碼編碼格式爲 GB2312
- 外部鏈接庫:SDL2.lib & SDL2_ttf.lib & SDL2_mixer.lib
- 包含目錄:SDL2相關庫的include所在目錄
- 庫目錄:SDL2相關庫libs所在目錄
- 常規:取消SDL檢查
- 鏈接器
- 附加依賴項:
- SDL2main.lib
- SDL2.lib
- SDL2_ttf.lib
- SDL2_mixer.lib
- 子系統:
- 窗口 (/SUBSYSTEM:WINDOWS)
- 高級:
- 入口點:mainCRTStartup
- 附加依賴項:
代碼解釋
#define SDL_MAIN_HANDLED
重定義main函數入口,SDL將main重定義,參考 SDL_main(...)
class BackGround; // 背景圖 以及遊戲的一些環境參數
class Ball; // 球類
class Board; // 板/障礙物
class BoardManager; // 板管理器:控制障礙物的出現以及運動
class Game; // 遊戲流程總控(開始動畫,主循環,結束動畫)以及音效,圖片資源的加載
class Life; // 獲取額外生命系統
class BoardThorn; // 含刺的障礙物
遊戲未特別設置幀率,採用SDL_RENDERER_PRESENTVSYNC
默認爲 60 fps
SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
init(): 初始化環境
bool init()
{
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
return false;
}
if (TTF_Init() == -1) {
cout << TTF_GetError() << endl;
return false;
}
if (Mix_Init(MIX_INIT_MP3) != 0) {
cout << Mix_GetError() << endl;
return false;
}
window = SDL_CreateWindow(BackGround::windowName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, WIDTH, HEIGHT, SDL_WINDOW_SHOWN);
render = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
font = TTF_OpenFont(BackGround::fontPath, 100);
Mix_OpenAudio(22050, MIX_DEFAULT_FORMAT, 2, 4096);
if (window == NULL || render == NULL || font == NULL) {
cout << SDL_GetError() << endl;
return false;
}
return true;
}
Game類:遊戲總控制,開始,運行,結束
class Game {
private:
SDL_Texture *title; // 標題紋理
SDL_Texture *startGame; // 開始按鈕紋理
SDL_Texture *authorInfo; // 開發者信息紋理
SDL_Texture *score; // 分數紋理 --- 在GameOver中初始化
SDL_Texture *rePlay; // 重新開始紋理
SDL_Texture *gameOverTitle; // 結束標題
void drawStartGame(SDL_Color color);// 繪製開始遊戲按鈕,鼠標在上改變顏色
void drawGameOver(SDL_Color color); // 同上
bool isInStart(int x, int y); // 判斷是否點擊開始鍵
bool GameOver(); // 和welcome差不多
public:
Game();
bool welcome(); // 歡迎界面
void run(); // 遊戲運行
void quit();
Mix_Music *bgm; // 背景音樂
static Mix_Chunk *takeOff; // 球碰到障礙物音效
static Mix_Chunk *bump; // 球破裂(損失生命)音效
static Mix_Chunk *gameOver; // 遊戲結束音效
static bool isBump; // 判斷是否撞到
};
BackGround類:運行時背景繪製,遊戲運行環境參數
class BackGround {
private:
SDL_Color bkColor;
SDL_Rect scoreTextPos;
void drawTranigle(int st_, int edgePos_, bool flag_);
void drawFence();
public:
const static int tranigleSize = 10; // 障礙組成的小三角形的底邊大小
const static int up = 12; // 上尖刺底邊
const static int down = HEIGHT; // 下尖刺底邊
const static int ballSize = 15; // 球大小
const static int boardWidth = 80; // 障礙物寬
const static int maxLife = 5; // 最多大生命值
const static float ballSpeedV;
const static float ballSpeedH;
const static char *windowName;
const static char *fontPath; // 以下,導入外部資源的路徑
const static char *bumpPath;
const static char *takeOffPath;
const static char *bgmPath;
const static char *gameOverPath;
const static char *catImgPath;
static int boardHeight;
static float boardSpeed;
static int life;
static int score;
static bool isDie;
BackGround(SDL_Color bkColor_);
void draw();
};
Ball類:移動,碰撞判斷
// 由於SDL沒有畫圓函數所以由兩個矩形和一個正方形模擬
class Ball {
private:
int size; // 球的大小
SDL_Point pos; // 位置
float speedV;
float speedH;
public:
friend Life;
Ball(int size_, SDL_Point pos_, float speedV_ = 0, float speedH_ = 0);
bool isBump(Board &board_); // 判斷是否與板相撞
void move(BoardManager &board_, int type, bool isMusicOn = true);
void draw(SDL_Color color = { 0,0,0,0xff });
};
Board類:障礙物
class Board {
private:
float speedV;
int width;
int height;
SDL_Point pos; // 中心點位置
SDL_Color color;// 顏色
public:
friend Ball;
friend BoardManager;
friend Life;
friend BoardThorn;
Board(SDL_Point pos_, int width_, int height_, float speedV_ = 0, SDL_Color color_ = { 0,0,0,0xff });
void move();
virtual void draw();
};
BoardThorn類:尖刺障礙物,繼承與Board
class BoardThorn :public Board {
public:
BoardThorn(SDL_Point pos_, int width_, int height_, float speedV_ = 0, SDL_Color color_ = { 0,0,0,0xff });
void draw();
};
BoardManager類:管理障礙物的出現及消失
class BoardManager {
private:
vector<Board> boards; // 管理所有板
bool isOut(Board &board_); // 判斷是否出界
void clearInlegal(); // 清除非法板(即出界)
int GAP; // 下一個板生成的時間間隔
BoardThorn boardThorn;
bool isThornExist;
public:
friend Ball;
friend Life;
BoardManager();
void move();
void draw();
void creatABoard(int* last, int now); // 隨機產生一個板
};
Life類:生命球
class Life {
const int lifeSize = 10;
const SDL_Color lifeColor = { 0xff,0,0,0xff };
Ball ball;
bool isCreat;
public:
Life();
void reSet(); // 配合重新開始遊戲
void creatALife(int clocks, BoardManager boards); // 生成一個生命,生命球移動也在此,每一次主循環均要調用
bool isEatALife(Ball ball_); // 判斷是否吃到
};