スクリーンショット_2020-01-21_0

クリックされたセルを知る(Dig The Shape!の作り方)

 これはDig The Shape!の制作の中で個人的に取り上げたいトピックを抜き出して紹介する記事です。

- プログラマ向け
- 汎用的なノウハウというよりは練習問題的なやつ
- この記事内のコードのライセンスはCC0(引用や外部リンクを除く)

https://nariakiiwatani.itch.io/digtheshape

 プログラミング作業って、小さな問題を解くことの連続で、ひとつひとつの問題はまあそんなに難易度高くないし、場当たり的にでも解けるんです。でもそうやってるとだんだん変更に弱くなったりデバッグしづらくなったりしてきちゃうので、

ひとつひとつの問題を、全体を見通しつつ解く

つまり、

「なぜその方法で解くのか」に自覚的になる

ということがとても大事だと思っています。

 このシリーズでは比較的簡単な問題を扱います。解答も相応に簡単なものになると思います。が、主題は解き方そのものではなく、その裏にある理由や意図の方ですのでそのつもりで読んでいただけるとありがたいです。

 前置きが長くなりました。それではどうぞ。前回の記事の設計を前提にするので、何を言っているのかわからなかったら戻ってみるとわかるかもしれません。

クリック判定

 「クリックしたセルが消える」をやるには、どのセルがクリックされたかを知る必要があります。改めて言うまでもなく当然のことですね。

 クリック判定自体の処理は、開発環境次第でそれ用のイベントリスナーが用意されていたり、そうじゃなくてもそれ的なものを自作してやることになるんじゃないかと思います。プレイヤーは画面に表示されているセルをめがけてクリックするので、論理位置でなく表示位置で判定することになります。

 余談ですが、プレイヤーがガンガン先読みして、連打に近いくらい素早く操作するようなことを期待したゲームなら、あえて論理位置(実際にそこにアニメーションが到達してなくても先にクリックできる)を使うこともありそうです。

 で、めでたく `Cell.OnClick()' 的なメソッドを呼べるようになったとして、その先を考えます。

クリックされたセルを知る

 これで消えるセルが自分自身だけだったら何かしら自己完結してしまう方法もありそうですが、今回のゲームでは隣接した同じ色のセルは同時に消えるというルールがあるので、それではうまくいきません。

 しかも、消えるセル群(グループと呼ぶことにします)の形も知らなくてはいけないので、消したり形を見たりする処理はCell自身ではなくてもっと広い視野を持った何かに任せた方が良さそうです。

 各Cellの隣接関係(論理位置)を決めているのはFieldなので、Fieldにやってもらいましょう。

 まず考えるのは、FieldがCellの参照を全て持っていて、クリック時に検索する方法です。こんな感じ

class Cell {
public:
    void OnClick() {
        field.OnCellClick(*this);
    }
};
class Field {
public:
    void OnCellClick(Cell &cell) {
        Cell &clicked = find(cells, cell);
    }
private:
    Cell cells[];
};

 しかし、こうするとクリックのたびにcellsを検索(O(n))してしまい、無駄が大きいです。まあセルが数百とか数千とかになることはまずないんでこれでもいいんですが。

 それよりは、CellがFieldにおける自分自身のインデックスを知っていて、コールバックの際に合わせて知らせてあげる作りの方がスマートかな、と思います。好みの問題レベルではありますが。ただし、FieldとCellとでインデックスに不整合が起きる可能性が生まれたと言うことでもあるので、今後はそこに目を光らせることになります。

 今回は、xy論理位置をそのままインデックスとして使用しました。

class Cell {
public:
    void OnClick() {
        field.OnCellClick(x_index, y_index);
    }
};
class Field {
public:
    void OnCellClick(int x, int y) {
        Cell &clicked = cells[y][x];
    }
private:
    Cell cells[][];
};

終わりに

 今回は、取り上げてみたら最終的には好みの問題だというところに着地してしまいました。しかしそういう判断こそ、なぜそうするのかを意識する格好の練習材料なのではないかと思います。

サポートしていただけたら、書く勢いになります!