おことわり
頭悪い(且つ,ちょっと精神状態が弱っているかもしれない)初心者の日記…というか,戯言です.
概要
趣味と仕事は違う.
→だったら,やり方が盛大に違っていてもよいのではないか?
なんかわからんけども,趣味だと 強制力 とか 期限 とかいうのが無いせいか,どうにも無駄にうだうだと考えてしまい,何も進まなくなってしまうことが多い.
そういう場合は「後先のことを何も考えなかったコード」をとにかく書いて勢いを付けるのが良さそうかな,みたいな.
日記
DRPGのようなもの(いわゆる Wizardry みたいなのを,自分でも作れそうなレベルにまでひどく簡略化したような何か)を作ろうとか思った.
さて,その「DRPGのようなもの」を作るとして,最初は何から作っていけば良いのだろうか?
最初に必要になるものとは何か?
作る物の内容を想像してみると……
- 「タイトル画面」というのを用意するかどうかわからないが,あるとしたら,そこには{はじめから,つづきから}みたいな選択肢(メニュー)が表示されることになるであろう.
- 「街」の画面とは{宿屋,店,ダンジョン}とかの中から行き先を選択するだけの画面になる.つまりメニューが1つあるだけだ.
- 「店」に行けば{買う,売る}的なメニューがあり,そこで「買う」を選んだら売り物の一覧表がメニュー表示されて,買いたい品を選んだならば「それは100Gだけど本当に買うのか? →はい/いいえ」みたいな確認が出たりとかするのだろう.
- 戦闘中には{殴る,防御,逃げる}みたいな行動選択メニューがあり,「殴る」なら誰を殴るのかを選んで……
- 手持ちのポーションを使う場合,それ用の画面に入って「アイテム」を選び→「ポーション」を選び→使用対象を選び……
とにかくゲームの進行はことごとくメニュー操作により成される様子ではないか.
↓
なので,この「メニュー」の実装から着手することにした.
※本稿内における「メニュー」という語とは:
「何か選択肢が並んでいる中からユーザが所望の項目を選ぶためのUI」を指す. 矢印キーとかでカーソルを動かして→何らかのキーで「じゃあこれを」と決定するようなやつだ.……で,この「メニュー」とかいう物は,どんな形に実装するべきであろうか?
前記したように,メニューにはいろいろと種類がありそうだから
- 項目が選択されたら→何が起こるというのか(=何の処理をするのか)
- キャンセル(項目を選ばずにそのメニューを開く前の状態に戻る)は可能なのか
- etc
というのは,メニューごとに異なってくるハズ.
そういうのはどう実装すればいいんだろう?
上記のような話から瞬間的に思いつくのはこんなやつだ:
//いろんな「メニュー」の基底
class MenuBase
{
//(※メニューの項目とかのデータにはどうにかしてアクセスできるのだとして)
public:
virtual ~MenuBase() = default;
public:
//(※各メソッドの引数とか戻り値は何かしら適切な形になるのだとして)
virtual void OnSelectOP() = 0; //項目選択操作が成されたときの処理
virtual void OnCancelOP() = 0; //キャンセル操作が成されたときの処理
virtual void OnCursorMoved() = 0; //カーソルが移動ときの処理
public:
void HandleInput( /*入力情報*/ )
{ /*入力操作に対応したメソッドを呼ぶ*/ }
};
各操作が行われたときに何をするのかは個々の具体的なメニュークラスの方で実装する,と.うん.
しかしこういうのだと,「複数個のメニューがあってさー」みたいな話のときに,
MenuBase MenuArray[3]; //そしたら配列で
とか素直に書けないのが何故かなんとなく嫌だ.
仮想関数になってる所を別のclassに分離すれば,とりあえず「メニュー」に関してはそれが可能になる気もする(「嫌」な場所がどこかに移動するだけの話だろうが):
//virtualな部分だけ取り出して別のclassにした
class IMenuEventHandler
{
public:
virtual ~IMenuEventHandler() = default;
public:
virtual void OnSelectOP() = 0;
virtual void OnCancelOP() = 0;
virtual void OnCursorMoved() = 0;
};
//メニュー
class Menu
{
//(※メニューの項目とかのデータにはどうにかしてアクセスできるのだとして)
private:
IMenuEventHandler &m_Handler;
public:
Menu( IMenuEventHandler &IMEH ) : m_Handler{IMEH} {}
public:
void HandleInput( /*入力情報*/ )
{ /*入力操作に対応した m_Handler のメソッドを呼ぶ*/ }
};
うーん,何か無駄に複雑ではないか?
処理結果に応じて何かしたいならば,その処理結果というのを戻り値で返すのが素直なのではないのか:
//結果
enum class HandleInputResult
{
None, //有効な操作が行われなかった(メニュー的には何も変化無し)
SelectOP, //項目選択操作が成された
CancelOP, //キャンセル操作が成された
CursorMoved, //カーソル位置が変化した
};
//関数でいいよねっていう気がする
HandleInputResult HandleInputForMenu( /*入力情報, メニューのデータ*/ )
{ /*入力操作に対応した HandleInputResult 型の値を返す*/ }
//何かclassにするとしても↑の関数を使って書けばいいか
class Menu
{
//(※メニューの項目とかのデータにはどうにかしてアクセスできるのだとして)
public:
HandleInputResult HandleInput( /*入力情報*/ )
{ return HandleInputForMenu( /*入力情報, メニュー項目とかのデータ*/ ); }
};
とかなんとか……いくつかやり方が思い浮かんだりするが,どれが良いのであろうか?
このゲームで必要になる様々なメニューを実装するのに最適な方法とは…?
(=== そして数週間が経過した ===)
なんということか.
最適な方法とは…?
とかなんとかいう空想の世界に入り込んでしまって時間を無駄にしてしまうのが(私の)最もダメなパターンだ.
結構な時間を無益な脳内シミュレーション(←出口すら明確でない無限ループ的な)に費やしてしまった.まったくダメな奴だな.
「良いコードは オレンジの香りがして 牛が喜んで食べる」
みたいな話をどこかで見たり聞いたりしたことがあると,
何故か(自分の 知識/経験/能力 の具合を鑑みずに)「オレンジの香りがするコードを最初から求められないだろうか?」みたいな方向に脱線してしまう.
「馬鹿には無理」というありがたい言葉をもっと強く胸に刻んでおく必要がある.
どうすればいいのか?
何もかも嫌になって全てをおしまいにしたくなる前に,とにかく作業に実際に着手することだ.
まずは必要な「具体的なメニュー」の1つをさっさと実装!
プログラムを実行するといきなり「街」にほっぽり出されるのだとしたら,まずは「街」のメニューを書くんだ!
こんなの↓を出す,っていう,そのことだけを考えるんだ.
このメニューの項目の表示は特定のサイズのアイコンと文字列から成る → ならば,特定のサイズのアイコンと文字列を表示するという処理の実装を書く.
コツは「でも他のメニューの場合だと文字列だけかもしれないじゃん,あと他にも……」みたいなことを一切考えないことだ.
「オレンジの香りがする気配は微塵も感じないコードであるが,動く」みたいなのを書く.
目安としては「職場で見せたら月給が30%くらい下がりそうなコード」という感じだ.そのくらいで丁度いい.
1つができたら2個目を,それができたら3個目を… と,何個かを同様にやる.
途中で「似て非なるもの」な感じのが出てきたらとりあえずコピペからの改造でもいい.
中途半端なタイミングでまた「オレンジがどうの…」と考え出さないように.ここは勢いが大切.
(コードの内情はひどいものだろうが,それはそれとして)「相応に動作させられるものが目の前にある」という状況になるとモチベーションもわいてくる.
「こんな感じだと……こういう形に纏めると良いかな」だとか「ここは無理して纏めることは無いかな」といったことはそうなってから考えればいい.
それで必要ならば必要なだけ書き直せばいい.
すごく回り道な気がしないでもないが,1文字もタイプせずに数週間が経過するよりはマシだ.
おまけ
時に 命名 が勢いの大敵となり得る.
「この メソッド/メンバ変数 の名前はどうしようか…?」←ここで手が止まる
脳死的に勢いコードを書くべきときに,そんなことで手が止まってはまずいのだ.
そもそも勢いだけで書いたコードがその後ずっと残るとは限らないのだから,最初から「良い名前」とか考えるだけ無駄だ.
そういう場合は仮の名前としておき, TTT_
を先頭に付けておく.ハンガリアン(?)である.
例えば「今は xyz
という名前が思いつくがこれだとイマイチだよなー」みたいなのは TTT_xyz
としておく.
TTT
の由来は tentative
という語から何故か t
3つだけを取り出したものだ.
タイプしやすく,正式な名称とはまず被らない.
長期間残っている場合には,適当なタイミングで TTT_
で検索して,良い名前に一括置換すればいい.
(※「命名規則」とかいうくだらない物は「俺一人の世界」には存在しないのだ)