16
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

C++ゲーム開発録 - 1週間で音ゲー制作

はじめに

この記事は Aizu advent calendar 21日目の記事です。(大遅刻になってしまいました。ごめんなさい。)
前の日はslme_not_foundさん、次の日はmt-coffさんでした。

自己紹介

Shirotsuと申します。C++歴1年程度のゲームプログラマー志望の学生です。記事を公開する以上極力間違いの無いよう心がけますが、もしございましたらご指摘ください。GitHubのアカウントはこちら

概要

環境構築を含めて1週間で音ゲー制作にチャレンジしたことを綴る記事です。開発の記録を残すこととC++ゲーム制作入門者向けに私がどのように開発を進めたかということを参考にしていただくという目的を兼ねて書きつらねていきます。また、この記事ではVisual Studio, Siv3Dの使い方とC++については深く解説しません。

開発環境

Windows10 Visual Studio 2017 とC++用フレームワーク Siv3D を利用して開発しました。VS2017の環境構築についてはこちらをどうぞ。

Siv3D環境構築

Siv3Dリファレンスページのダウンロードとインストールのページを見て行います。
注意書きにもある通り、Siv3DはVS2015バージョンのプロジェクトファイルで扱う必要があります。

ハマったところ

Siv3Dのインストールも終わってさあ実行してみようとすると、こんなビルドエラーが。
builderror.PNG

これを解決するには、プロジェクトのプロパティを変更する必要があります。
debug_info.PNG

ソリューションエクスプローラー > プロジェクトを右クリック > プロパティ > C/C++ > 全般 > デバッグ情報の形式

このオプションをC7互換にする必要があります。
このオプションは、実行中のバイナリファイルとソースコードを結び付けてデバッグを可能にする機能関連のオプションです。詳細はこちら

開発の流れ

基本的な開発フローの話ですので、分かっている方は見出しで判断して読み飛ばしてください。

1. ゲームの流れと仕様を決める

環境構築を終えたら、簡単にゲームの仕様と「ゲームに必要なシーン」を考えます。この後にプログラムの構成を決めるため、おおまかにどんなものが必要か記しておく作業です。

私は音ゲーを作ろうと決め、このようにしました。
specification.PNG
trans.PNG

2. プログラムの構成を決める

次は大まかなクラス構成を決めます。中規模以上のプログラムになると、この構成をやらなければ後々プログラムが絡まりあってデバッグや機能追加で苦しむことになるでしょう。こちらの記事で紹介されているようにゲームプログラムに使える様々な設計パターンがありますので、積極的に利用しましょう。
Draw.ioなどを使ってUMLのクラス図 で決めていくのがおすすめです。

今回、私はこんな構成にしました。(※簡単のために省略したり、書いていない箇所があります。)
diagram.png

核となるGame::Coreクラスが各シーンの実体を格納するスタックを持ち、スタックの一番上にあるシーンを実行します。実行したいシーンのポインタを切り換えれば、ごく軽い処理でフレームとフレームの間にシーン遷移ができます。(参考プログラム)

main.cpp
int main(){
    Game::Core gamecore;
    while( !gamecore.IsGameEnd() ){
        gamecore.Update();
        gamecore.Draw();
    }
}
GameCore.cpp
void Game::Core::Update(){
    if( sceneStack.top()->NeedsTransition() ){
        std::unique_ptr<Base>&& nextScene = sceneStack.top()->TransitionToNext(); 
        if( nextScene ){
            sceneStack.push( std::move( nextScene ) );
        }
        else{
            sceneStack.pop();
        }
    }
    sceneStack.top()->Update();
}

void Game::Core::Draw() const{
    sceneStack.top->Draw();
}

3. プログラムを実装する

まずクラス図に沿ってヘッダファイルを書きます。その後、各ヘッダに合わせて何もしないメンバ関数の実装を書きます。この状態は、いわゆるモックと呼ばれるものです。

次に、核となるクラスから末端となるクラスの順に実際の動作を実装します。

プログラムを書いている時に、追加する必要のあるクラス/関数を思いつくでしょう。その都度、追加します。
モジュールの急な追加を繰り返すとプログラムが複雑になりやすいので、本来であればヘッダファイルを書き始める時に全ての構成要素が揃っていることが理想です。

音ゲーの実装

音ゲーの処理は、曲のBPMから1拍にかかる秒数を算出 -> n小節m拍の秒数 付近で特定のキーが叩かれたか、という処理で実装しました。実際のコードはこちら

プロトタイプの完成

なかなかいい感じできたもので、Twitterで狂喜乱舞していました(笑)。いろいろ調整&ビジュアル面を強化して近日中にリリースします。

蛇足な余談

本当は「1日でゲーム開発チャレンジ」と言っていたところ延びに延びて1週間かかり、結果Advent Calendar投稿に大遅刻するという事態になってしまいました。
どれだけ時間がかかるのかを把握するためにタスクを小さく分割し、逆算しておくことが大事だなあと感じました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
16
Help us understand the problem. What are the problem?