Unity 2017.2からVector2Intなどの各種int版構造体が加わった

Unityには様々な構造体があります。代表的なものは、

* [Vector2](https://docs.unity3d.com/ScriptReference/Vector2.html)
* [Vector3](https://docs.unity3d.com/ScriptReference/Vector3.html)
* [Vector4](https://docs.unity3d.com/ScriptReference/Vector4.html)
* [Quaternion](https://docs.unity3d.com/ScriptReference/Quaternion.html)
* [Matrix4x4](https://docs.unity3d.com/ScriptReference/Matrix4x4.html)
* [Rect](https://docs.unity3d.com/ScriptReference/Rect.html)
* [Bounds](https://docs.unity3d.com/ScriptReference/Bounds.html)

などです。

ところで、Unity 2017.2からこれらうちのいくつかの構造体のint版が追加されました。

* [Vector2Int](https://docs.unity3d.com/ScriptReference/Vector2Int.html)
* [Vector3Int](https://docs.unity3d.com/ScriptReference/Vector3Int.html)
* [RangeInt](https://docs.unity3d.com/ScriptReference/RangeInt.html) (float版の対応する構造体なし)
* [RectInt](https://docs.unity3d.com/ScriptReference/RectInt.html)
* [BoundsInt](https://docs.unity3d.com/ScriptReference/BoundsInt.html)

Vector4Intは無いみたいですね。また、RangeIntに相当するfloat版はなく、int版のみのようです。

Vector2IntやVector3Intに関しては、みなさんそれぞれ同じようなコードを書かれていたのではないでしょうか？

やりましたね！Unityで共通で使える構造体が正式にリリースされました！！！

さて、これらはもともとTilemapで活用されていた構造体で2D Exprerimentalでは前から使えていました。Unity 2017.2でTilemapの正式導入と共に、これらの構造体もUnity正式版で使えるようになりました。

大体の用途・機能はもともとあったfloat版から想像できると思いますので、機能的に面白かったものを2点、こぼれ話を数点紹介します。

# 機能ピックアップ

面白いものを2点ほど。

## 生成系メソッド

Vector2からVector2Intを生成するメソッドがあります。

* [Vector2Int.CeilToInt](https://docs.unity3d.com/ScriptReference/Vector2Int.CeilToInt.html)
* [Vector2Int.FloorToInt](https://docs.unity3d.com/ScriptReference/Vector2Int.FloorToInt.html)
* [Vector2Int.RoundToInt](https://docs.unity3d.com/ScriptReference/Vector2Int.RoundToInt.html)

Ceil、Floor、Roundという名前から想像できるかもしれませんが、それぞれの要素をCeilToInt、FloorToInt、RoundToIntしたものを生成します。


```csharp
Assert.AreEqual(new Vector2Int(1, 1), Vector2Int.CeilToInt(new Vector2(0.1F, 0.1F)));
Assert.AreEqual(new Vector2Int(1, 1), Vector2Int.CeilToInt(new Vector2(0.6F, 0.4F)));

Assert.AreEqual(new Vector2Int(0, 0), Vector2Int.FloorToInt(new Vector2(0.1F, 0.1F)));
Assert.AreEqual(new Vector2Int(0, 0), Vector2Int.FloorToInt(new Vector2(0.6F, 0.4F)));

Assert.AreEqual(new Vector2Int(0, 0), Vector2Int.RoundToInt(new Vector2(0.1F, 0.1F)));
Assert.AreEqual(new Vector2Int(1, 0), Vector2Int.RoundToInt(new Vector2(0.6F, 0.4F)));
```

同様に、Vector3からVector3Intを生成するメソッドもあります。

* [Vector3Int.CeilToInt](https://docs.unity3d.com/ScriptReference/Vector3Int.CeilToInt.html)
* [Vector3Int.RoundToInt](https://docs.unity3d.com/ScriptReference/Vector3Int.RoundToInt.html)
* [Vector3Int.FloorToInt](https://docs.unity3d.com/ScriptReference/Vector3Int.FloorToInt.html)

## 範囲列挙

[RectInt](https://docs.unity3d.com/ScriptReference/RectInt-allPositionsWithin.html) と[BoundsInt](https://docs.unity3d.com/ScriptReference/RectInt-allPositionsWithin.html)にはallPositionsWithinというプロパティがあります。


これを用いることで、それぞれの範囲の内部の座標を列挙することができます。こんな感じで。

```csharp
RectInt rectInt = new RectInt(xMin: 0, yMin: 0, width: 3, height: 4);

foreach (Vector2Int position in rectInt.allPositionsWithin)
{
    Debug.Log(position);
}
```

これはTileｍapで結構便利です。

# こぼれ話ピックアップ


新たに追加されたint系構造体の内、Vector2IntとVector3IntはTilemapで使うので、自分はUnity 2D Experimental Previewの内から試して、フィードバックを送っていました。

それにまつわるこぼれ話をいくつか。

## 昔はあったVector3を引数にとるVector3Intのコンストラクタ

最終的には無くなったのだけれども、あるタイミングのUnity 2D Experimental Previewでは、Vector3を引数にとるVector3Intのコンストラクタがありました。

で、これは無いほうがいいコンストラクタ。その理由は、

コンストラクタの挙動（どんなVector3Intが生成されるか）、あいまいで明示的なファクトリーメソッドとして定義したほうがいいから。

コンストラクタの挙動は、

* 一部の人は、Vector3のそれぞれの要素が切り捨てられたVector3Intが生成されると思う
* 他の人は、Vector3のそれぞれの要素が四捨五入されたVector3Intが生成されると思う
* 他の多くの人は、↑のどっちかわかんないからドキュメント参照したりする
* もしかしたら、ごく一部の人は、Vector3のそれぞれの要素が切り上げされたVector3Intが生成されると思う

という具合でとりうる挙動が複数パターンあるから、それを使おうとする人が混乱する。

コンストラクタを無くして、ファクトリメソッドを作ったほうがベター。

で、これが、

* [Vector3Int.CeilToInt](https://docs.unity3d.com/ScriptReference/Vector3Int.CeilToInt.html)
* [Vector3Int.RoundToInt](https://docs.unity3d.com/ScriptReference/Vector3Int.RoundToInt.html)
* [Vector3Int.FloorToInt](https://docs.unity3d.com/ScriptReference/Vector3Int.FloorToInt.html)

こうなった。

フォーラムで「こうしようぜー」って言ったら、「それいいね」って感じでコメントをもらったり、何より次のバージョンで反映された。やったね。

https://forum.unity.com/threads/suggest-remove-vector3int-vector3-v-constructor-and-create-static-factroy-methods.440778/#post-2870457

ただ、「（2D Experimental Previwだけれども）破壊的な変更だから変更点ドキュメント書いてよー」ってフォーラムで言われていたみたい。

## マンハッタン距離が欲しいけどない

Vector2IntやVector3Intには、マンハッタン距離を計算するメソッドが欲しいと思うんですよ。

インスタンスメソッドでもスタティックメソッドの両方。

フォーラムで「追加しよーよ」って言ったけど、残念ながら追加されず。

使うと思うんだけどなー。

https://forum.unity.com/threads/suggest-add-vector3int-manhattandistance-vector3int-a-vector3int-b.444672/#post-2876207


## 直前までバグ

Unity 2017.2のかなりリリース直前のタイミングまで、RectIntのSetMinMaxメソッドにバグがあったみたい。

あまり呼ばれないメソッドだけど、内容的には明らかなバグ。

フォーラムに投稿しても無反応だったんだけど、Unity Technologies Japanさんに報告したら、すぐに伝えてくれて修正されてよかった。

Unity Technologies Japanの担当者さん、ありがとうございます。

ていうか、あまり呼ばれなそうなメソッドだから中の人も使っていなかったのかも。

https://forum.unity.com/threads/rectint-setminmax-method-may-be-wrong.497591/

もしかしたら、他にあるかも。

## なんか一部のメソッドやプロパティがない

Vector3Int、多分forwardとbackwardがないんですよ。

Vector2IntにはToString(String format)がないんですよ。(Vector2とVector3Intにはある)

多分、これら実装もれな気がします。

# まとめ

Unity 2017.2から、int系の構造体が追加されました。

Unityのベータ版やExperimental Preview版には、しっかり報告したりフィードバックを行うことで、採用されたり改善されます。みんなもどんどんしていきましょう！

バグを減らすためにも！！！！