iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 21
1

引言

昨天完成了讓遊戲能播放開頭BGM,
今天的目標是完成遊戲開始的引導畫面
也就是像早期掌上型遊戲機都會有個開始畫面,
下面有什麼copyright 1998之類的,
然後有個Press start的提示~
這個畫面目的是,讓玩家有個心理準備開始遊戲的緩衝,
同時也讓遊戲有個形象的畫面。

我們今天的設計流程大概是:

1. 建立儲存地圖的資料結構(開頭畫面我們當作遊戲地圖來實作)
2. 讀取地圖檔案(自己設計的文字檔)
3. 畫面繪製地圖檔案
4. 等待玩家按鍵前往下一步
5. 播放按下按鍵的音效(筆者使用的音效如規格表)

那這邊我再把今天會用到的規格列在底下:

項目 內容
遊戲地圖大小 高:寬 = 30:59
遊戲確認音效 魔王魂システム49(請大家下載.wav檔)
遊戲開頭畫面文字檔 titleMap.txt

地圖儲存的資料結構

既然是2D遊戲的地圖,我們需要一個二維的資料結構來儲存它,
我想最好用也最常見的,就是二維陣列了~

  1. 在我們建立二維陣列之前,我們先建立一組新檔案LoadMap.h、LoadMap.c:
/* 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
  1. 我們可以開始設計儲存地圖結構的二維陣列了:
/* 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__
  1. 有了儲存的資料結構,永遠別忘了初始化它。
/* 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] = ' ';
            }
        }
    }
}

設計地圖檔案

  1. 接下來我們來設計開頭畫面吧,首先在專案中新增一個maps資料夾:
    https://ithelp.ithome.com.tw/upload/images/20191005/201114292CCqBRtPKS.png

  2. 筆者設計的開頭畫面,我取名為titleMap.txt,因為要用文字檔畫很麻煩QQ,筆者體諒大家將連結附在底下,檔案下載:titleMap.txt
    https://ithelp.ithome.com.tw/upload/images/20191005/20111429CuZOewGQXU.png

  3. 大家下載後將檔案放在maps資料夾中:
    https://ithelp.ithome.com.tw/upload/images/20191005/20111429g2sVg73q8v.png


讀取地圖檔案

  1. 幫地圖檔案寫個定義,以及宣告一個loadMap函數:
/* 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__
  1. 實作loadMap函數,會使用C語言的檔案處理(若沒接觸過可參考這裡):
/* 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);  // 退出程式
    }
}

顯示地圖畫面

  1. 將地圖讀入記憶體後,再來就是顯示它啦,宣告顯示地圖函數showMap
/* 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__
  1. 實作showMap函數,這邊很簡單,就是把二維陣列內容照格式印出來即可:
/* 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;
}

執行

執行看看吧!
https://ithelp.ithome.com.tw/upload/images/20191005/20111429KTn3p4L4MU.jpg


上一篇
[11屆鐵人賽Day20] 2D遊戲—BGM、視窗設定
下一篇
[11屆鐵人賽Day22] 2D遊戲—人物控制
系列文
若沒有遊戲引擎、合作夥伴...做得出遊戲嗎? 不試試看不知道吧? [使用C語言]30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言