ゲームを作りたい!

プログラミングをしているからには、いつかはゲームを作ってみたい。勉強したことを備忘録的に綴るBLOG。

SDL2でRPGゲームを作る 〜第18回 扉を開く〜

前回は宝箱を開ける方法を考えた。中身を保持することはまだできないので追々実装していく。
今回は開けるつながりで扉を開く方法を考えていく。

扉を開くには

まず、扉用の構造体を用意した。

typedef struct {
    int map_x;
    int map_y;
    int status;
} DOOR;

DOOR構造体が持っているのは扉の位置と状態(開いているか閉じているか)である。
状態は

  • 0: 閉じている
  • 1: 開いている

とした。
宝箱と違う点は、一回開いたものを開きっぱなしにする必要はないと思うので、フィールドを読み込むたびに閉まっている状態に戻る。

イベントファイルには以下のように記載し宝箱などと同様にフィールド切り替えのタイミングで読み込まれるようにした。

# DOOR, マスX座標, マスY座標
DOOR,9,10
DOOR,3,4
DOOR,3,12
DOOR,16,4
DOOR,16,12

イベントファイルの読み込み

扉の設置の方法が決まったところで、まず、イベントファイルを読み込みだ。
イベントファイルを読み込む方法は前回の宝箱と同じ方式なので、それをベースに扉用に作っていく。
状態として一旦初期値は9にして、イベントファイルで読み込んだ部分のみ閉じている状態つまり0にする。 これは、描画するときに配列の01のみを対象にするためである。

int load_door(SDL_Renderer *renderer) {
    char event_path[256] = {0};

    sprintf(event_path, "data/%s.evt", MAP_EVENT_NAME);

    FILE *fp;
    char event[256] = {0};
    int map_x;
    int map_y;

    char buf[256] = {0};
    int i;

    fp = fopen(event_path, "r");
    if (fp == NULL) {
        printf("file open error. %d\n", __LINE__);
        return 1;
    }

    for (i = 0;i < sizeof(door)/sizeof(door[0]);i++) {
        door[i].status = 9;
    }

    for (i = 0;fgets(buf, sizeof(buf), fp) != NULL;i++) {

        if (strncmp(buf, "#", 1) != 0){
            if (strncmp(buf, "DOOR", 4) == 0) {
                sscanf(buf,
                   "%[^,],%d,%d",
                       event, &map_x, &map_y);

                 door[i].map_x = map_x;
                 door[i].map_y = map_y;
                 door[i].status = 0;

            }
        }
    }

    fclose(fp);

    return 0;
}

扉の状態変更

次は、扉の状態を変える関数。目の前に扉があれば状態を「開く(status = 1)」に変化させる。

int open_door() {
    int i;
    char *se_file = "door.ogg";

    for(i = 0;i<sizeof(door)/sizeof(door[0]);i++){
        if (player.direction == UP) {
            if (door[i].map_x == player.map_x && door[i].map_y == player.map_y - 1) {
                door[i].status = 1;
                sound_se(se_file);
                return 0;
            }
        } else if (player.direction == DOWN) {
            if (door[i].map_x == player.map_x && door[i].map_y == player.map_y + 1) {
                door[i].status = 1;
                sound_se(se_file);
                return 0;
            }
        } else if (player.direction == RIGHT) {
            if (door[i].map_x == player.map_x + 1 && door[i].map_y == player.map_y) {
                door[i].status = 1;
                sound_se(se_file);
                return 0;
            }
        } else if (player.direction == LEFT) {
            if (door[i].map_x == player.map_x - 1 && door[i].map_y == player.map_y) {
                door[i].status = 1;
                sound_se(se_file);
                return 0;
            }
        }
    }

    message_window_status();
    message = DOOR_MESSAGE;

    return 0;
}

扉の描画

最後に状態を見て扉を描画する。

int draw_door(SDL_Renderer *renderer, SDL_Event e){

    int i;

    for(i = 0;i<sizeof(door)/sizeof(door[0]);i++){
        if (door[i].status != 9) {
            SDL_Rect imageRect=(SDL_Rect){0, 0, IMAGE_WIDTH, IMAGE_HEIGHT};
            SDL_Rect drawRect=(SDL_Rect){(door[i].map_x * GRID_SIZE) - player.offset_x,
                                         (door[i].map_y * GRID_SIZE) - player.offset_y,
                                         IMAGE_WIDTH*MAGNIFICATION, IMAGE_HEIGHT*MAGNIFICATION};

            if (door[i].status == 0){
                SDL_RenderCopy(renderer, mapchip[17].map_image, &imageRect, &drawRect);
            }
        }
    }

    return 0;
}

全コード表示

では、いつもの通り全コードを表示する。
扉が開くようになった

実行結果

扉を開けられるようになった。

f:id:K38:20200411232453g:plain
扉をひらく

終わりに

大体宝箱と同じ方法で扉を実装することができた。文章をまとめながらもうちょっとうまく作れたかなぁと思ったけどとりあえず実現できたから良しとする。気が向いたらリファクタリングする。
次回は、コマンドウィンドウあたりを作っていきたい。