ラストのまほう　第15話『ベクトル演算ライブラリを作る』

# ↗ベクトル演算ライブラリを作る

２Dアクションゲームには二次元線形代数ライブラリが必要です。Rustの既存のライブラリ(クレート？)を持ってきてもいいのですが、Rustのウォーミングアップとしてちょうどいいので、自力で作ってしまうことにします（とかいいつつ、あとでライブラリを差し替えたりしそう……）。

`Vector2`構造体を作って、`impl`でゴリゴリとメソッドを定義していきます。この辺は私はこれまで何度も作ったことがあってお手のものです。なにしろ**何度もゲーム開発に挫折している**ので。

```rust:vector2.rs
#[derive(Clone, Copy, PartialEq, Default)]
pub struct Vector2 {
    pub x: f32,
    pub y: f32,
}

impl Vector2 {
    pub fn new(x: f32, y: f32) -> Vector2 {
        Vector2 { x, y }
    }
}

impl ops::Add<Vector2> for Vector2 {
    type Output = Vector2;

    fn add(self, q: Vector2) -> Vector2 {
        Vector2 {
            x: self.x + q.x,
            y: self.y + q.y,
        }
    }
}
```

ゲームを作ってみたい高校生諸君は、ベクトルと行列は勉強しておきましょう。別に学生時代にマスターしなくてもいいですが、２Dアクションゲームを作りたくなったときにベクトルわからないとロクにプログラミングはできないと思ってください。逆に言えば**2Dアクションゲーム開発はベクトルと行列の勉強に最適**です。ついでに**高校物理の変位/速度/加速度、摩擦力、重力、弾性力などは２Dアクションゲーム開発にめちゃくちゃ役に立つ**のでおすすめです。

演算子のオーバーロードをするには、`impl ops::Add<Vector2> for Vector2`のようにして`add`関数を定義すればいいようです。つまり**Add型クラスのインスタンスを定義**しているわけですね(Haskell用語)。`#[derive(Clone, Copy, PartialEq, Default)]`とかも、**`Clone`型クラスや`PartialEq`型クラスのインスタンスを導出している**(Haskell用語)んだなと、なんとなく見ればわかります。筆者はHaskell脳なのでRustもHaskell用語で基本的に解釈しています。トレイトとかRustの用語はよくわかりませんが、**Haskellでいう型クラスのようなもの**だと思っておくことにします。Rustは素直な言語だと思います。

なんかRustの公式ドキュメントを見ると、現代のハードウェアでは `f32` と`f64`は速度はどちらもほとんど同じだから基本的に`f64`を使えばいいでしょ、みたいに書いてあったのですが、まあWASM-4は厳しい環境なのでケチるに越したことはありません（そのうち説明しますが、WASM-4では普通に作っているだけでスタックが足りなくなっていろいろ対応が必要になったりします）。しかも２Dゲームだと精度もとくに必要ありません。`f32`で十分でしょう。

`struct`で直積型を定義して、`#[derive(Clone, Copy, PartialEq, Default)]`で各種の型クラスインスタンスを導出(Rust用語では「トレイトの導出」というらしいですが、筆者の頭の中ではHaskell用語の型クラスインスタンスの導出とみなされている)。`impl Vector2 { ... }`の中で関数を定義すると、メソッドっぽくなるみたいです。演算子オーバーロードをするには、`impl ops::Add<Vector2> for Vector2 { ... }`の中で`add`という名前の関数を書けばいいらしい。`type Output = Vector2;`ってなんだろうと思いつつも、なんとなく雰囲気で書き進めます。


# ⏹AABBを定義する

ゲーム開発でベクトルや行列のほかに重要な概念として、**AABB**があります。AABBとは [Axis-Aligned Bounding Boxes](https://developer.mozilla.org/ja/docs/Games/Techniques/3D_collision_detection)のことで、つまり画面に対して傾いていない矩形の領域のことをいいます。２Dアクションゲームでは、地形やプレイヤーキャラクターの衝突の判定をこのAABBで考えると高速かつシンプルに処理することができます。ゲーム開発以外ではあまり馴染みのない概念かもしれませんが……。

AABBは要するに矩形なので、画面に対して左上の基準点と、幅、高さをあわせて、次のような構造体で表すことができます。

```rust
#[derive(Clone, Copy)]
pub struct AABB {
    pub x: f32,
    pub y: f32,
    pub w: f32,
    pub h: f32,
}
```

AABBはただの矩形(Rectangle)とは違って、傾いていないということがポイントです。そのため、矩形同士が斜めに交差するということがないので、次のようにしてシンプルに交差判定ができます。


```rust
pub fn collesion(&self, b: AABB) -> bool {
    (self.x < b.r() && self.r() > b.x) && (self.y < b.b() && self.b() > b.y)
}
```

これが、もし傾きを考慮しないといけない矩形だと交差判定が大変です。もちろんより厳密な物理演算が必要なゲームでは傾いた矩形を含む図形の交差を判定しなければなりませんが、今回作る２Dドット絵プラットフォーマーなら、AABBだけで判定したほうがずっとシンプルです。


# 左右方向のみを表す型

このほか、キャラクターが左向きか右向きかを表すデータ型を定義しておくと便利です。これはまあ左向きか右向きかの二つに一つなので `bool`型で表すこともできますし、`i32`の`1`と`-1`で表すようなこともできるのですが、Rustにはせっかく`enum`があるのでこれを使っておきます。

```rust
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
pub enum Direction {
    Left,
    Right,
}

impl Direction {
    pub fn delta(&self) -> i32 {
        if *self == Direction::Left {
            -1
        } else {
            1
        }
    }

    ...
```

このあたりは好みもあると思うのですが、筆者はなるべく不正な状態にならないようなデータ型にしたほうが堅牢になると信じるタイプの人なので、積極的に`enum`を使っていきます。代数的データ型最高！


# 🔜次回予告

WASM-4は非常に簡素なフレームワークなので、こんな感じで自力でゲーム開発に必要な基礎的な関数を定義したりすることもあるので、それはそれで勉強になります。次回はこのベクトル演算ライブラリを利用しつつ、プラットフォーマーに不可欠な「衝突判定」を実装していきます。

https://qiita.com/hiruberuto/private/c3a40731f44a986fdd8b