ゼロから始める音ゲーノーツツール作成　その2/3（機能面の実現の仕方）

#こんな人におすすめ

Unityのツール作成に興味がある人
音ゲーのツールをEditorWindowを使った拡張で作りたい
音ゲーのツールを自分で作って見たいがどうしたらよいかわからん。

#開発環境
Unity2017.4.8.1f
VisualStudio2017Community


#お品書き（今回の内容）
・配置を行えるスクロールの作成。（過去記事あり）
・BPMとLPB等の線をスクロール上に引く場合引かない場合の仕方
・マウスイベントからのノーツの配置を行う
・配置したノーツを修正した際の位置調整
・（音を鳴らす）まだ出来てないので今回はなし

# 配置を行えるスクロールの作成。（過去記事あり）

この内容に関しては、すでに書いてある記事の通りです。

スクロールの中で後付けのデータを追加できるものを作る。　小芝居付き　UnityEditor拡張
https://qiita.com/herieru/items/f527ccea790226fda0b6

ざっくりというならば
スクロールを自動配置で行った場合、
スクロールの中のコンテンツの大きさに依存してしまうため、
文字を入れてないラベルを入れてそれの横幅を欲しいだけ設定するというものです。

ただ、この横幅、あちこちで、この横幅の情報が必要になってくるので
設計を交える場合は、それを念頭に置くといいと思います。



# BPMとLPB等の線をスクロール上に引く場合引かない場合の仕方

スクロールの上に「ノーツ」を置いていくわけですが、
音ゲーに置いて、必要なのがBPMとLPB
どちらも大変重要な要素です。
※BPM…テンポの事で、1分間当たりの回数
※LPB…BPM間の間隔

これらを目安として表示していく表現として使用される線ですが
スクロールの中に配置していくためには、スクロールの中で線分を描画しなければいけません。

以下の感じです。

``` 線を引くサンプル.cs
Handles.DrawLine(開始位置、終了位置);
```

しかしながら、この状態だと、白い線しか描画されないので、色を付けてみます
以下サンプル

```線を引くサンプル2.cs

Color _base_color = Handles.color;
Handles.color = _color;
Handles.DrawLine(開始位置、終了位置);
Handles.color = _base_color;

```
最初の部分で
Color _base_color = Handles.color;をしているのは、このHandlesクラスは、共通で使いまわされる仕様っぽく
色を変更してしまうと、以降のHandleでの色が全てそれになってしまうため、それを防ぐようになっています。

ここで問題になってくるのは、開始位置の横幅ですが、
単純に、スクロールの横幅から、それぞれのBPMとLPBの数値を使用して、計算することが出来ます。


####線分に関してのおまけ
今回の場合は、スクロールでの中の話なので、
単純に、スクロールの領域を保持して、それを使用することで、線が引けるのですが

問題は外側から引く場合は、さらに問題があります。
Handlesで今回みたいに(0,0))から適当な数値をHandles.DrawLineに入れた場合。
表示される線分の開始地点は、Windowの0，0地点からになってしまいます。

TODO:写真



なので、スクロールにかぶせる感じに表示を行おうと思うと

```　スクロール画面の位置を取得する方法.cs

Rect _rect = EditorGUILayout.BeginHorizontal();
{
      //TODO:もろもろの処理・・・・
}
EditorGUILayout.EndHorizontal();

```
とする必要があります。

またさらに注意が必要なのが、このRectの値は
Endhorizontalを終えるまで、まともな数値が入らない上に、デバッカでは確認出来ない場合があります。



# マウスイベントからのノーツの配置を行う
よくあるのが、EventSystemの機能として動く

``` よくあるマウスのインプット.cs

if(Input.GetMouseButton(ほにゃらら))
{
 //このボタンが押されたときの処理
}


```

しかし、残念ながら、この方法だと、自分が作成したウィンドウ上では、マウスイベントを取得することができません。
理由として単純なことで、EventSystem自身はUIBehaviourを継承しており、UIBehaviourはMonoBehaviorを継承しているため、UnityのUpdateサイクルに入らないと基本的には動きません（であってるよね？）

そのため、Editor拡張では、別の視点でのマウスのイベントを取得しなければなりません。

``` 　エディター拡張状でマウスの状態を取得する方法
if(Event.current.type != EventType.MouseDown)
{
}
int _mouse_button = Event.current.button;

```

この方法で取得できます。
current部分にイベントとしてのデータが存在しますが、
この中身は、舞ううすのイベント限らず、キーボードのキーを押した際にも
保存されます。

そのため、事前にそれがマウスイベントであるか？といった情報の確認が必要になってくるのです。


また、今回のこのマウスイベントを使う際には、スクロールの中身だけという制約をつける必要があります。
どうすればいいか？

スクロール画面の位置を取得する方法

この題名のサンプルがあると思いますので、それのRect以外の範囲がマウスポジションならはじくようにすると基本的にはじくことができます、



# 配置するノーツの表示位置の計算

ノーツの配置をする上で注意をしなければいけないことは以下の２点です。

1.ノーツがおける範囲の制限
2.スクロール上の位置情報の取得

１に関しては、一つ前の項目のマウスの話になってきますが、マウスでとれるポジションは、あくまでも、画面内での位置情報しかとることができません。
そのため

マウスをクリックー＞その場所にノーツを置く　　という形にしてしまっては、スクロール外の場所に情報を持ってしまい
実質表示されない状態になってしまいます。
この１．ノーツがおける範囲の制限を行うためには
何パターンかあると思いますが、スクロール内での位置情報へ加工する方法でやっていきます。

基本的にマウスのクリックの位置＝画面での位置情報
なので、それをそのままの位置に、スクロールの内での位置情報に置いた場合
スクロールのオブジェクトの位置からの位置情報になるので、
実際に置かれる場所は、スクロールの位置分ずれた場所に配置されることになります。

なので、スクロールでの見えている範囲に配置をしようと思うと以下のような情報の作成の仕方になります。

``` スクロールの中にほぼ正確に配置するためのもの

var _mouse_pos = Event.current.mousePosition- スクロールでの位置情報;

```
となります。
なお、スクロールでの位置情報は、最初の項目の記事を参考にしてください。

しかし、この状態だと、スクロールを行おうが、その位置情報は、スクロールの先頭の位置情報となるので、
マウスの位置を現在表示しているスクロール領域に合わせなければいけません。
図で表すと以下のようになります。

![Untitled Diagram.jpg](https://qiita-image-store.s3.amazonaws.com/0/101366/fd7e8e91-0fdd-34c2-de26-0db8cfd6d646.jpeg)


そのためスクロールの際に使用するスクロール位置であるVector2を足します。
そうすることで、常に、表示部分の、左上からの位置になり、正しい配置へとなります。




#音を再生を行わずに再生するためには？
これに関しては、どうしてもGameObjectの存在が必要になってきますが再生は可能です。

再生するデータであるAudioClip
再生する機器であるAudioSource

AudioSourceをつけるためのGameObjectが必要になってきます。


なのでやることとしては
AudioClipでの音楽データの参照を持っている。
AudioSourceをAddComponentしたGameObject（画面を閉じたら消えるように設計する必要はあり）
となります。

ちなみに、この方法以外の鳴らし方はたぶんあると思うのですが、私は知りませんので、知っていましたら、教えて下さい。