ゲーム実装で身に付くプログラミング 10

色ブロックを表示する

色ブロックを表示する

「src\ColorBlock.c」ファイルを新規作成し、「Source Files」を右クリックして「Add」→「Existing Item」メニューでColorBlock.cファイルを追加します。

次に「include\ColorBlock.h」ファイルを新規作成し、「Header Files」を右クリックして「Add」→「Existing Item」メニューでColorBlock.hファイルを追加します。「ColorBlock」構造体は色ブロック1個ずつの設計図のようなものです。メインループで、この構造体を使って移動する色ブロックを表示します(図3)。

ここで「メインループ」とはゲーム全体のループを指しますが、本連載の他の言語ではメインループは「色ブロックが出ている間のゲームループ中」を指しているので混同するかもしれませんが、いつものように「MAIN_LOOP」という名前を使っています。

図3:色ブロックを表示

・サンプルコード「ColorBlock.h」ファイル

#ifndef COLORBLOCK_H
#define COLORBLOCK_H

#include "raylib.h"

typedef struct {
    float x;
    float y;
    float vx;
    float vy;
    int width;
    int height;
    int color;
} ColorBlock;

void ColorBlock_Init(ColorBlock* block, int c, int w, int h);
int ColorBlock_Draw(ColorBlock* block, Texture2D img[]);

#endif

【サンプルコードの解説】
「COLORBLOCK_H」で、このヘッダーファイルをコンパイルする際に重複しないようにします。
ColorBlock構造体を宣言し、(x,y)座標、幅高さ(width,height)、移動量(vx,vy)と色「color」変数を宣言します。初期化「ColorBlock_Init」関数と描画「ColorBlock_Draw」関数を宣言します。

・サンプルコード「ColorBlock.c」ファイル

#include "ColorBlock.h"
#include <stdlib.h>

void ColorBlock_Init(ColorBlock* block, int c, int w, int h) {
    block->x = rand() % 1700;
    block->y = rand() % 800;
    block->vx = (rand() % 401) / 1000.0f - 0.2f;
    block->vy = (rand() % 401) / 1000.0f - 0.2f;
    block->width = w;
    block->height = h;
    block->color = c;
}

int ColorBlock_Draw(ColorBlock* block, Texture2D img[]) {
    block->x += block->vx;
    block->y += block->vy;
    DrawTexture(img[block->color], (int)block->x, (int)block->y, WHITE);
    if (block->x < block->width ||
        block->y < block->height ||
        block->x > 1800 ||
        block->y > 900) {
        return 0;
    }
    return 1;
}

【サンプルコードの解説】
"ColorBlock.h"と、ランダム関数のために<stdlib.h>をインクルードします。
ColorBlock_Init関数でランダムな(x,y)と(vx,vy)をセットし、幅高さ色をセットします。
ColorBlock_Draw関数で色ブロックの座標を移動し、描画し、画面外に出たら戻り値として0を返し、それ以外は1を返します。

・サンプルコード「main.c」ファイル

#include "ColorBlock.h"
#include "resource_dir.h"

#define MAX_TEXTURES 6
#define MAX_SOUNDS 4
#define MAX_BLOCKS 300

typedef enum { TITLE,MAIN_LOOP,GAME_OVER,STAGE_CLEAR } GameState;
GameState game_state = TITLE;
Texture2D img[MAX_TEXTURES];
Sound snd[MAX_SOUNDS];
ColorBlock colors[MAX_BLOCKS];
int colorCount = 0;
int stage = 2;
Color bg = { 255,255,255,255 };

void init(void) {
    colorCount = stage * 3;
    for (int i = 0; i < colorCount; i++)
        ColorBlock_Init(&colors[i], i % 3, img[0].width, img[0].height);
}

void title(void) {
(中略)
}

void main_loop(void) {
    int flg = 0;
    for (int i = 0; i < colorCount; i++)
        flg += ColorBlock_Draw(&colors[i], img);
}

int main(void) {
    SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_HIGHDPI);
    InitWindow(1800, 900, "Color");
    SetTargetFPS(60);
    InitAudioDevice();
    SearchAndSetResourceDir("resources");
    img[0] = LoadTexture("0.png");
    img[1] = LoadTexture("1.png");
    img[2] = LoadTexture("2.png");
    img[3] = LoadTexture("Title.png");
    img[4] = LoadTexture("GameOver.png");
    img[5] = LoadTexture("StageClear.png");
    snd[0] = LoadSound("Mix.ogg");
    snd[1] = LoadSound("GameStart.ogg");
    snd[2] = LoadSound("GameOver.ogg");
    snd[3] = LoadSound("StageClear.ogg");
    while (!WindowShouldClose()) {
        BeginDrawing();
        ClearBackground(bg);
        switch (game_state) {
        case TITLE:
            title();
            break;
        case MAIN_LOOP:
            main_loop();
            break;
        }
        EndDrawing();
    }
    for (int i = 0; i < MAX_TEXTURES; i++)
        UnloadTexture(img[i]);
    for (int i = 0; i < MAX_SOUNDS; i++)
        UnloadSound(snd[i]);
    CloseAudioDevice();
    CloseWindow();
    return 0;
}

【サンプルコードの解説】
ColorBlock構造体の「colors」配列と「stage」変数を宣言します。最初のステージは2です。
「init」関数で色ブロックをstageの3倍(赤緑青3色)に初期化します。
ゲームループ中の「main_loop」関数で色ブロックを描画します。
「main」関数で、メインループ中のゲームループ(MAIN_LOOP)中にmain_loop関数を呼び出します。

ゲームオーバー画面を表示する

全ての色ブロックが画面外に出て1個もなくなったらゲームオーバー画面に遷移します(図4)。ゲームオーバー画像を中央に描画して、画面をどこでもクリックしたらタイトル画面に戻ります。

図4:ゲームオーバー画面の表示

・サンプルコード「main.c」ファイル

(前略)

void init(void) {
(中略)
}

void title(void) {
(中略)
}

void main_loop(void) {
    int flg = 0;
    for (int i = 0; i < colorCount; i++)
        flg += ColorBlock_Draw(&colors[i], img);
    if (flg == 0) {
        game_state = GAME_OVER;
        PlaySound(snd[2]);
    }
}

void game_over(void) {
    if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
        game_state = TITLE;
    DrawTexture(img[4],
        (1800 - img[4].width) / 2,
        (900 - img[4].height) / 2,
        WHITE);
}

int main(void) {
(中略)
    while (!WindowShouldClose()) {
        BeginDrawing();
        ClearBackground(bg);
        switch (game_state) {
            case TITLE:
                title();
                break;
            case MAIN_LOOP:
                main_loop();
                break;
            case GAME_OVER:
                game_over();
                break;
        }
        EndDrawing();
    }
(中略)
}

【サンプルコードの解説】
main_loop関数で色ブロックの数が0個になったら「game_state」変数をゲームオーバーにし、"GameOver.ogg"サウンドを再生します。
「game_over」関数で"GameOver.png"画像を描画します。マウスの左ボタンを押せばgame_state変数をタイトルにします。
main関数のメインループ中で、ゲームオーバー時にgame_over関数を呼び出します。

【コラム】Sora2

水の波紋が円ではなく他の何らかの形をしていたら、と3DCGアニメをテストで作ってみました。でも上手くデザインできませんでした。Xで公開してしまったけど、ちょっと見せたくありません。Sora2で上手く作れるかもしれませんが、もうSora2は使えないのかな?

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored