經典諾基亞遊戲Rapid-Roll SDL2實現

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_);	// 判斷是否吃到
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章