MATLAB でゲームを作る ～0. グラフィックス オブジェクト編～

MATLAB でゲーム制作シリーズ
- 0 章：グラフィックスオブジェクト（この記事）
- [1 章：コールバック](https://qiita.com/macht/items/5853875dce0381e33c3a)
- [2 章：メインループ](https://qiita.com/macht/items/de86b46a22f4109df0c1)
- [3 章：アクションゲームでジャンプ](https://qiita.com/macht/items/357ad3201deb1683f010)

# はじめに

人間はプログラミング言語を見るとゲームを作りたくなります。

「MATLAB ゲーム」と調べると MATLAB ~~（Simulink で作ってるよくわからない人もいる）~~ で作られたゲームが何個かヒットするので、MATLAB も例外ではありません。

ということで、MATLAB でゲームを作りたいという~~狂人~~至って正常な方々のために、MATLAB でどうやってゲームを作るのかについてまとめていきたいと思います。

　
今回は初めということで、準備編として「グラフィックス オブジェクト」に関する基礎知識をまとめていきたいと思います。


#グラフィックス オブジェクトとは
　読んで字のごとく、グラフィックスを表示するためのオブジェクトのことです。
`figure`、`axes`、`plot`、`surf`、`image` などなど、Figure ウィンドウ上に何かを描画する関数を使うと、
対応するグラフィックス オブジェクトが作成されます。

　グラフィックス オブジェクトを作成する関数は、基本的に返り値として作成したグラフィックス オブジェクトを指すハンドル（ポインタのようなもの）を返します。
例えば `plot` 関数だとこんな感じ。

```MATLAB:
>> t = 0:0.1:10;
>> p = plot(t,sin(t))

p = 

  Line のプロパティ:

              Color: [0 0.4470 0.7410]
          LineStyle: '-'
          LineWidth: 0.5000
             Marker: 'none'
         MarkerSize: 6
    MarkerFaceColor: 'none'
              XData: [1×101 double]
              YData: [1×101 double]
              ZData: [1×0 double]

  すべてのプロパティ を表示
```

この場合は "Line" という種類のグラフィックス オブジェクトが作成され、p という変数にそのハンドルが格納されています。
グラフィックス オブジェクトに関する詳しい情報は[このドキュメント](https://jp.mathworks.com/help/matlab/graphics-objects.html)に載っています。

　このようにして変数に格納したグラフィックス オブジェクトのハンドルをうまく使うと、MATLAB でもゲームっぽい動作を作れます。




#グラフィックス オブジェクトのプロパティ
　グラフィックスオブジェクトは、色や位置などの情報をプロパティとして保持しています。上で plot 関数を実行したときに表示されていた "Color" や "LineWidth" などもプロパティです。

　グラフィックスオブジェクトの情報を取得したい、あるいは変更を加えたいときは、基本的に変数に格納したハンドルからプロパティにアクセスします。

### プロパティ値の取得
　特定のプロパティ値を取得したい場合は、`get` 関数またはドット（.）を用います。例えば、上でプロットした Line オブジェクト p の線の太さを知りたい場合は以下の通りです。

```MATLAB:
>> width = get(p,'LineWidth')

width =

    0.5000
```

または

```MATLAB:
>> width = p.LineWidth
width =

    0.5000
```
私はプロパティを取得するときはほとんどドットを使用しています（こっちの方がシンプルに書けるので）。

### プロパティ値の変更
　特定のプロパティ値を変更したい場合は、`set` 関数またはドットを用います。
例えば、Line オブジェクト p の色を赤に変更したい場合は以下の通りです。

```MATLAB:
>> set(p,'Color','r');
```

または

```MATLAB:
>> p.Color = 'r';
```

プロパティを変更するときもドットを使う場合が多いですが、
複数のプロパティを一度に変更したい場合は、set 関数を用いると 1 行でかけて便利です。

```MATLAB:
>> set(p,'LineWidth',2,'Color','r'); % 太さと色を一度に変更
```


#よく使うグラフィックス オブジェクトまとめ
　ゲーム作りでよく使うグラフィックス オブジェクトをまとめておきます。各グラフィックス オブジェクトのプロパティ一覧は、「オブジェクト名 + プロパティ」で検索すれば、ドキュメントが出てきます。

###[Figure](https://jp.mathworks.com/help/matlab/ref/figure.html?)
　言わずもがな。ゲームウィンドウそのものになります。ゲームを作るときは、ゲームタイトルを付けたうえで、メニューバーや figure の番号などいらないものを消すことが多いです。

```MATLAB:
fig = figure('Name','My Game','MenuBar','none','ToolBar','none','NumberTitle','off');
```

~~どうでもいいですけど、タピオカミルクティーと Figure のプロパティって語感が似てますよね。~~

###[Axes](https://jp.mathworks.com/help/matlab/ref/axes.html)
　座標軸です。ゲーム作りにおいてはゲーム内の世界そのもので、ここに他のオブジェクトをゲームのコンポーネントとして配置していきます。ゲーム作りでは Y 軸の向きを反対にすることが多いです（理由は次回以降の記事で説明するはずです）。ちなみに見出しは Axes ですが、[`axis` コマンド](https://jp.mathworks.com/help/matlab/ref/axis.html?s_tid=doc_ta)が便利なので私は `axes` 関数はあまり使っていません。

```MATLAB:
ax = gca;
axis equal; %x 軸と　y 軸の比率を合わせる
axis ij; %Y軸の向きを反転
axis([0 10 0 10]); %座標軸の範囲を指定
ax.Toolbar.Visible = 'off'; % 右上にマウスをかざすと出てくるメニューバーを非表示
set(ax,'XTIck',[],'YTick',[]); % 目盛りの非表示
```

~~個人的には目盛りを表示したままの方が MATLAB っぽくて好きです。~~

###[Image](https://jp.mathworks.com/help/matlab/ref/image.html?s_tid=doc_ta)
　画像を表示します。すでに存在する figure 上に画像を表示するときは、XData, YData, CData を指定する必要があります。

```MATLAB:
imdata = imread('myImage.png');
im = image('XData',[0 1],'YData',[0 1],'CData',imdata);
```

###[Rectangle](https://jp.mathworks.com/help/matlab/ref/rectangle.html?s_tid=doc_ta)
　四角や丸を表示します。Position プロパティの指定の仕方が少し特殊なので注意

```MATLAB:
rec = rectangle('Position',[0 0 1 1]); % Position は [左下の点の x 座標, y 座標, 幅, 高さ] で指定
rec = rectangle('Position',[0 0 1 1]','Curvature',[1 1]) % 丸を作るときは Curvature プロパティを[1 1]に指定
```

###[Text](https://jp.mathworks.com/help/matlab/ref/text.html?s_tid=doc_ta)
　文字を表示します。注意点として、デフォルトではフォントサイズは絶対サイズ（Figure のサイズによらない）扱いになっています。FontUnits プロパティを normalized に設定することで、Figure の大きさの変化に合わせて文字の大きさも変化するようになります。


```MATLAB:
text(1,1,'MATLAB','FontUnits','normalized','FontSize',0.1)
```
　
　
　とりあえずこれらのグラフィックス オブジェクトを使えば、マ〇オくらいだったら作れます。


#便利なグラフィックス オブジェクト関連の関数
　グラフィックス オブジェクト用の便利な関数の紹介です。

### `gcf`, `gca` コマンド
　それぞれアクティブになっている figure および axes のオブジェクトのハンドルを取得できます。

```MATLAB:
>> fig = gcf

fig = 

  Figure (1) のプロパティ:

      Number: 1
        Name: ''
       Color: [0.9400 0.9400 0.9400]
    Position: [680 678 560 420]
       Units: 'pixels'

  すべてのプロパティ を表示
```

```MATLAB:
>> ax = gca

ax = 

  Axes のプロパティ:

             XLim: [0 1]
             YLim: [0 1]
           XScale: 'linear'
           YScale: 'linear'
    GridLineStyle: '-'
         Position: [0.1300 0.1100 0.7750 0.8150]
            Units: 'normalized'

  すべてのプロパティ を表示
```

ゲーム起動中にうっかり別の Figure をクリックするととんでもないことになるので、
私はゲームのコード内では初期化処理以外で極力使わないようにしています。


###`delete` 関数
　グラフィックス オブジェクト自体は変数を clear しても消えないので、消したい場合は `delete` 関数を使います。

```MATLAB:
>> delete(p);
```

当たり前ですが、一度 delete したグラフィックス オブジェクトのプロパティにはアクセスできません。

```MATLAB:
>> delete(p);
>> width = p.LineWidth
無効であるか削除されたオブジェクトです。
```

削除されたオブジェクトのハンドルが変数に残留思念のように残っていてそのプロパティを参照してしまう、
というのはゲームプログラムにおいて頻繁に生じるバグですので注意しましょう。


###`isgraphcs` 関数
　グラフィックス オブジェクトが delete されているかを判別する関数です。残留思念のように変数に残っているオブジェクトから身を守ります。

```MATLAB:
>> fig = figure;
>> isgraphics(fig)

ans =

  logical

   1

>> delete(fig);
>> isgraphics(fig)

ans =

  logical

   0
```

途中で figure が閉じられたら処理を終了する、などの処理に使えます。

### `gobjects` 関数
　グラフィックス オブジェクト配列の事前割り当ての関数です。マップチップのように同じタイプのオブジェクトを何個も作って行列や配列として保存しておく場合に便利です~~（セル配列でいい）~~。

```MATLAB:
>> garray = gobjects(1,4);
for i = 1:4
garray(i) = rectangle('Position',[i 1 1 1]);
end
axis([0 5 0 5])
garray

garray = 

  1×4 Rectangle 配列:

    Rectangle    Rectangle    Rectangle    Rectangle
```

### `findobj` 関数
　プロパティが特定の値となっているグラフィックス オブジェクトを検索できます。特定のオブジェクトにのみ何か操作を行いたい場合に非常に便利です。

```MATLAB:
>> objs = findobj('Type','Line','Color','r'); % 赤い Line オブジェクトのみを取得
```

# まとめ
- グラフィックス オブジェクトを作成する関数は返り値としてそのオブジェクトのハンドルを返す
- グラフィックス オブジェクトの取得や変更を行う場合は、ハンドルに対してget,set,ドットなどを用いてプロパティにアクセスする
- ゲーム作りに使えそうなオブジェクトは基本的な使い方を覚えておこう
- ゲーム作りで便利な関数は存在だけでも抑えておこう

次回から本格的にゲームっぽい挙動を作っていく予定です。

　
　「いいね」が増えると次回の記事が豪華になるかも