太鼓さん次郎をつくってみる 2日目

前回の記事では,プログラムの骨格となる部分をInput,Game,Graphicの3クラスに分け,メインループをWinMain関数に作成しました.今回は,ゲーム中の音符データの構造を作成していきます.

音符クラスの作成

音符を表すためのデータ構造は複数考えられます.音符の種類だけでも,

  • 音符の種類を表すenumを作成し音符クラスのメンバ変数にする
  • 音符クラスから面クラス,縁クラス等の子クラスを作成する

等の方法があります.今回は,管理が楽で,tja形式とも相性のいいenumを用いることにします.なお,内部的な音符として,BPMやHSの変化を表したり,小節線を表す音符も用います.これらの処理は譜面中に埋め込まれるので,一つの音符として扱えます.

また,それぞれの音符には叩くべき時間(判定枠と重なる時間)があります.これもメンバ変数としましょう1

それから,音符が流れる速さはBPMとHSの値から計算できますが,これらの値もメンバ変数とした方が描画プログラムが簡単に書けるでしょう.

最後に,それぞれの音符にパラメータを一つ持たせることにします.これが表すのは,

  • 通常音符ならその判定(良,不可,まだ叩いていない,など)
  • 黄色連打では連打した数
  • 風船およびくすだまでは残りの連打数

とします.

というわけで,Noteクラスの構成はこんな感じ.

class Note{
    NoteName type;
    int time;
    double bpm;
    double scroll;
}

enum class NoteName{
    NOTHING,DON,KATSU,LDON,LKATSU,ROLL,LROLL,BALLON,ROLLEND,IMO,BARLINE,CHANGEBPM,CHANGESCROLL,GOGOSTART,GOGOEND
};

NoteNameは仮に作成したものなので今後変更があるかもしれません, で,tja読み取り部分から作りやすいようにコンストラクタを作り,描画用のgetterを作成します.

Note::Note(int type,int time,double bpm,double scroll,int param):type(static_cast<NoteName>(type)),time(time),bpm(bpm),scroll(scroll),param(param){}

NoteName Note::getType(){
    return type;
}
double Note::getBPM(){
    return bpm;
}
double Note::getHS(){
    return scroll;
}

次回は,tjaファイルを読み取って譜面データに変換するプログラムを作成します.

参考サイト

  1. http://dxlib.o.oo7.jp/ DXライブラリ公式サイト
  2. http://dixq.net/g/ DXライブラリでのゲーム制作について基本的なことから詳細に書かれています.
このプログラムは自学用に制作するものであり,バンダイナムコエンターテインメント様の権利の侵害を目的としたものではありません.もし問題がありましたらすぐに本記事およびソースコードを削除いたします.

  1. プログラム内部では,DXライブラリに合わせint型のミリ秒単位で時間を扱います.

太鼓さん次郎をつくってみる 1日目

はじめまして. めいてると申します. 大学でプログラミングを学んだのですが実際に使う場面がなかなかない,というわけで太鼓さん次郎のプログラムを1から作ってみます.

使用言語はC++で,グラフィック,サウンドにDXライブラリを使用します.ただし私はC++に関してはまだ入門者です.

ソースコードGitHubで随時公開します.アドバイス批判マサカリご自由にどうぞ.

この記事では,プログラムを作成しつつ考えたことや悩んでいることを書いていく予定です.

目標

このプログラムでは本家太鼓の達人の再現を目標にしています.そのため,本家未実装のHBSCROLL等には対応しません1.また,リプレイ機能と特訓モードの実装も考えています.

DXライブラリとは

DXライブラリはWindowsでゲーム制作をする際に使用するDirectXのラッパーライブラリです.C/C++での個人制作のゲームでは結構な割合で使われてるらしいです.

実際に書くプログラムはこんな感じ.(公式サイトのサンプルより)

#include "DxLib.h"

// プログラムは WinMain から始まります
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
    if( DxLib_Init() == -1 )     // DXライブラリ初期化処理
    {
        return -1;           // エラーが起きたら直ちに終了
    }

    DrawPixel( 320 , 240 , GetColor( 255,255,255 ) ) ; // 点を打つ
    WaitKey();              // キー入力待ち
    DxLib_End();                // DXライブラリ使用の終了処理
    return 0;                // ソフトの終了 
}

WinMainを使ってるあたりはWin32APIが見え隠れしますが,これだけでウィンドウを作成してその中に点を打てます.かなり便利.

詳しくは公式サイトのリファレンスを参照してください.

準備

環境構築とプロジェクトの設定は公式サイトの通りのため省略します.ここではDXライブラリを使用するためにプログラム中に必要な記述を書いていきます.

まず,DXライブラリを使用するとデフォルトではフルスクリーンでプログラムが起動します.これではデバッグが非常にやりにくい.というわけで,ウィンドウモードに変更します.ウィンドウサイズは1280*720とします.

    ChangeWindowMode(TRUE);
    SetGraphMode(1280,720,32);

これで起動時に真っ黒なウィンドウが表示されます.

それから,画面の描画にも工夫が必要です.DXライブラリでは画像を読み込んでハンドラ形式で簡単に扱うことができるのですが,普通にやるとプレイヤーに見せるべきではない作成途中の画面が映ってしまいます.そのためDXライブラリでは「裏画面」という仕組みを導入してこれを避けています.詳しくは参考サイト2.を参照してください.

    SetDrawScreen(DX_SCREEN_BACK);

この1文を追加することで描画先が裏画面になります.

DXライブラリ上の操作はどこで使用しても同じなので,このあたりの記述は全てinitialize()関数に分けます.

とりあえず骨格を書いてみる

基本となる部分から書いていきましょう.一般的なゲームの動作サイクルでは,

  • コントローラーやキーボードの入力を取得する
  • 入力に従ってゲームの内部状態を更新する
  • 更新内容に従って画面を描画する

これを繰り返し行います2.というわけで,WinMain関数の中心はこう書けるでしょう.

     while(ProcessMessage() == 0){
         getInput();
         update();
         draw();
     }

ProcessMessage()はDXライブラリの関数で詳細は割愛しますが,ここではウィンドウ右上の☓ボタンがクリックされるまで繰り返す,という意味です.

せっかくC++を使っているのでこれらの機能はそれぞれクラスにしましょう.また,先の動作サイクルでの依存関係からそれぞれが参照すべきクラスも考えて,

     Input input;
     Game game(&input);
     Graphic graphic(&game);

     while(ProcessMessage() == 0){
         input.getInput();
         game.update();
         graphic.draw();
     }

本質的には骨格はこれで完成で,以降はInput,Game,Graphicの3クラスを作成します.

参考サイト

  1. http://dxlib.o.oo7.jp/ DXライブラリ公式サイト
  2. http://dixq.net/g/ DXライブラリでのゲーム制作について基本的なことから詳細に書かれています.
このプログラムは自学用に制作するものであり,バンダイナムコエンターテインメント様の権利の侵害を目的としたものではありません.もし問題がありましたらすぐに本記事およびソースコードを削除いたします.

  1. 個人的にBMSCROLLやHBSCROLLはあまり好きじゃなかったりする.

  2. 本当は音を出す操作も必要ですが,それほど込み入ったことはしないのでupdate()中に行います.