引言
昨天完成了讓遊戲能播放開頭BGM,
今天的目標是完成遊戲開始的引導畫面,
也就是像早期掌上型遊戲機都會有個開始畫面,
下面有什麼copyright 1998之類的,
然後有個Press start的提示~
這個畫面目的是,讓玩家有個心理準備開始遊戲的緩衝,
同時也讓遊戲有個形象的畫面。
我們今天的設計流程大概是:
1. 建立儲存地圖的資料結構(開頭畫面我們當作遊戲地圖來實作)
2. 讀取地圖檔案(自己設計的文字檔)
3. 畫面繪製地圖檔案
4. 等待玩家按鍵前往下一步
5. 播放按下按鍵的音效(筆者使用的音效如規格表)
那這邊我再把今天會用到的規格列在底下:
項目 | 內容 |
---|---|
遊戲地圖大小 | 高:寬 = 30:59 |
遊戲確認音效 | 魔王魂システム49(請大家下載.wav檔) |
遊戲開頭畫面文字檔 | titleMap.txt |
地圖儲存的資料結構
既然是2D遊戲的地圖,我們需要一個二維的資料結構來儲存它,
我想最好用也最常見的,就是二維陣列了~
/* File: LoadMap.h */
#ifndef __LOADMAP_H__
#define __LOADMAP_H__
#include <stdio.h> // 等等會用到輸入、輸出
#include <stdlib.h> // 等等會用到讀取檔案
// 我大部分的慣例是,.c檔需要的標頭檔都給.h囊括,.c檔只要負責引入自己的.h就好
#endif // __LOADMAP_H__
/* File: LoadMap.c */
#include "LoadMap.h" // 只要引入LoadMap.h就好,裡面包含了stdio.h, stdlib.h
/* File: LoadMap.h */
#ifndef __LOADMAP_H__
#define __LOADMAP_H__
#include <stdio.h>
#include <stdlib.h>
// ------------新增部分-------------------
#include "SystemSetting.h" // 為了取得GAME_HEIGHT與GAME_WIDTH
#define MAP_HEIGHT (GAME_HEIGHT-10) // 高度減10預留狀態欄
#define MAP_WIDTH (GAME_WIDTH) // 寬度一樣,但地圖檔設計上須將寬度-1(因為有換行符)
// 舉例:視窗高度GAME_HEIGHT=40,則地圖高度MAP_HEIGHT會=30
// 視窗寬度GAME_WIDTH=60 ,則地圖寬度MAP_WIDTH 會=59
//
// 所以地圖檔就會是30 * 59(不包括換行,應該說表面看起來30 * 59),如規格表所列
char game_map[MAP_HEIGHT][MAP_WIDTH]; // 由 char型態二維陣列 儲存地圖!
// ---------------------------------------
#endif // __LOADMAP_H__
/* File: LoadMap.h */
// 寫在 char game_map[MAP_HEIGHT][MAP_WIDTH]; 之下
void initMap(); // 用來初始化game_map,定義寫在LoadMap.c檔
/* File: LoadMap.c */
#include "LoadMap.h"
void initMap() // 初始化game_map二維陣列
{
int i = 0, j = 0;
for(i = 0; i < MAP_HEIGHT; i++)
{
for(j = 0; j < MAP_WIDTH; j++) // 雙層迴圈依序初始化
{
if(j == MAP_WIDTH - 1) // 每"列"最後一個字元需填入換行符,方能順利換行
{
game_map[i][j] = '\n';
}
else // 其餘都填入空格
{
game_map[i][j] = ' ';
}
}
}
}
設計地圖檔案
接下來我們來設計開頭畫面吧,首先在專案中新增一個maps資料夾:
筆者設計的開頭畫面,我取名為titleMap.txt,因為要用文字檔畫很麻煩QQ,筆者體諒大家將連結附在底下,檔案下載:titleMap.txt
大家下載後將檔案放在maps資料夾中:
讀取地圖檔案
/* File: LoadMap.h */
#ifndef __LOADMAP_H__
#define __LOADMAP_H__
#include <stdio.h>
#include <stdlib.h>
#include "SystemSetting.h"
// ------------新增部分-------------------
// 地圖定義
#define TITLE_MAP "maps/titleMap.txt" // 稍後開檔案直接填入TITLE_MAP即可
// --------------------------------------
#define MAP_HEIGHT (GAME_HEIGHT-10)
#define MAP_WIDTH (GAME_WIDTH)
char game_map[MAP_HEIGHT][MAP_WIDTH];
void initMap();
// ------------新增部分-------------------
void loadMap(char *mapPath); // 載入地圖函數,參數將填入地圖路徑,
// 而我們會實作將檔案讀進二維陣列
// --------------------------------------
#endif // __LOADMAP_H__
/* File: LoadMap.c */
// 寫在initMap下
void loadMap(char *mapPath) // 載入地圖檔,填入路徑
{
int i = 0, j = 0;
FILE *map_file = NULL; // 宣告FILE指標,並初始化為NULL
if((map_file = fopen(TITLE_MAP, "r")) != NULL) // 如果開檔成功
{
for(i = 0; i < MAP_HEIGHT; i++)
{
for(j = 0; j < MAP_WIDTH; j++)
{
fscanf(map_file, "%c", &game_map[i][j]); // 將檔案中所有字元存入game_map中
}
}
fclose(map_file); // 記得關檔
}
else // 如果開檔失敗
{
printf("地圖檔不存在或損壞...\n"); // 印出失敗訊息
system("pause"); // 呼叫cmd的指令—暫停,等使用者按下任意鍵
exit(1); // 退出程式
}
}
顯示地圖畫面
/* File: LoadMap.h */
#ifndef __LOADMAP_H__
#define __LOADMAP_H__
#include <stdio.h>
#include <stdlib.h>
#include "SystemSetting.h"
#define TITLE_MAP "maps/titleMap.txt"
#define MAP_HEIGHT (GAME_HEIGHT-10)
#define MAP_WIDTH (GAME_WIDTH)
char game_map[MAP_HEIGHT][MAP_WIDTH];
void initMap();
void loadMap(char *mapPath);
// ------------新增部分-------------------
void showMap();
// --------------------------------------
#endif // __LOADMAP_H__
/* File: LoadMap.c */
// 寫在loadMap函數下
void showMap() // 顯示地圖在畫面上
{
int i = 0, j = 0;
for(i = 0; i < MAP_HEIGHT; i++)
{
for(j = 0; j < MAP_WIDTH; j++) // 雙重迴圈依序印出整個地圖
{
printf("%c", game_map[i][j]);
}
}
}
主函數呼叫
我們回到main.c函數,來依序呼叫所需函數吧,先引入LoadMap.h:
/* File: main.c */
#include "SystemSetting.h" // 設定標題、視窗、音效、錯誤處理、遊戲初始化等
// ------------新增部分-------------------
#include "LoadMap.h" // 載入地圖、頁面
// --------------------------------------
int main(int argc, char *argv[])
{
playMusic(BGM, BGM_MODE);
setGameTitle(GAME_TITLE);
setGameWindow(GAME_WIDTH, GAME_HEIGHT);
// ------------新增部分-------------------
initMap(); // 初始化game_map二維陣列
loadMap(TITLE_MAP); // 讀取TITLE_MAP定義的路徑中的地圖檔,將其存入game_map二維陣列中
showMap(); // 顯示地圖
// --------------------------------------
system("pause"); // 等待使用者按下任意鍵進入下一幕(進入遊戲)
// 之後從這邊開始寫遊戲本體
return 0;
}
執行
執行看看吧!