【Bevy】VSCodeのデバッグで、アセットを読み込めない(見つけられない)問題を治す方法【Rust】

# はじめに
[Bevy](https://bevyengine.org/)では、ゲームの画像や音楽ファイル(=アセット)の読み込みのための[AssetServer](https://docs.rs/bevy/0.9.1/bevy/asset/struct.AssetServer.html)モジュールが用意されており、これを用いることで相対パスからのアセット読み込みを簡易にしてくれます。

```rust:main.rs
// AssetServerを用いた読み込みの例.rs（説明のため一部のみ載せています）
…略
fn spawn_player(
    mut commands: Commands,
    window_query: Query<&Window, With<PrimaryWindow>>,
    asset_server: Res<AssetServer>,
) {
    // Playerを生成するためのシステム

    let window = window_query.get_single().unwrap();
    commands.spawn((
        SpriteBundle {
            …略
            texture: asset_server.load("sprites/ball.png"),
            …略
        },
        Player {},
    ));
}
…略
```

デフォルトでは「assets」フォルダから探して読み込むことになっているので、
上の例では、以下のディレクトリ構造の「assets」フォルダ内のspritesフォルダにあるball.pngという画像をスプライトのテクスチャとして読み込もうとしています。

```
"ワークスペースのルートディレクトリ"
├─.vscode
│  ├─launch.json
├─assets
│  ├─audio
│    ├─ その他音声ファイル
│  └─sprites
│    ├─ball.png
├─src
│  ├─main.rs
```

これは、`cargo run`を直接打って実行すると問題なくball.pngの画像が読み込まれます。

しかし、VSCodeでF5キーを押して実行できる、生成された.vscode/launch.jsonを元にしたデバッグでは画像を見つけることができず、以下のように警告が表示されます。

```
2023-06-13T02:56:32.059970Z  WARN bevy_asset::asset_server: encountered an error while reading an asset: path not found: ワークスペースのディレクトリ/target/debug/assets/sprites/ball.png
```

# 原因
- [AssetServerのソースコードのコメント](https://github.com/bevyengine/bevy/blob/main/crates/bevy_asset/src/asset_server.rs)
- [Unofficial Bevy Cheat Book/Load Assets from Files with AssetServer](https://bevy-cheatbook.github.io/assets/assetserver.html)

上のリンク先によると、AssetServerがファイルを読み込む場所の指定は`ROOT/ASSET_FOLDER_NAME/path`という形のファイルパスで設定されています。

先程の例では、
- `ASSET_FOLDER_NAME` = 「assets」
- `path` = 「sprites/ball.png」
になることが分かります。

`ROOT`はデフォルトではアプリケーションの実行場所のディレクトリを指しており
- `BEVY_ASSET_ROOT`
- `CARGO_MANIFEST_DIR`
いずれかの環境変数で上書きすることができます。

cargoを用いでコードをコンパイル・実行する際、`target/debug`フォルダが生成され、そこにバイナリが置かれて実行されます。
`cargo run`経由の実行では、`CARGO_MANIFEST_DIR`が設定されるので、この際の`ROOT/ASSET_FOLDER_NAME/path`は`ワークスペースのルートディレクトリ/assets/sprites/ball.png`となるのですが、
VSCodeからのCodeLLDBによるデバッグでは、`CARGO_MANIFEST_DIR`が設定されずにバイナリを直接実行するので、`ROOT`がアプリケーションの実行場所のディレクトリ、つまり`target/debug`に設定されるので、「ball.png」を見つけることが出来なかったのです。

# 解決策

前述の通り、`ROOT`は
- `BEVY_ASSET_ROOT`
- `CARGO_MANIFEST_DIR`

この環境変数で上書きできるので、その通りにすればよいです。
つまり、launch.jsonをデバッグ実行時に上記いずれかの環境変数を設定するように書き加えます。

```json:launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug executable 'bevy-ball-game'",
            "cargo": {
                "args": [
                    "build",
                    "--bin=bevy-ball-game",
                    "--package=bevy-ball-game"
                ],
                "filter": {
                    "name": "bevy-ball-game",
                    "kind": "bin"
                }
            },
            "args": [],
            "cwd": "${workspaceFolder}",
            "env": {"BEVY_ASSET_ROOT": "${workspaceFolder}"} // ← 新しく書き加えた部分
        },
        {
            "type": "lldb",
            "request": "launch",
            "name": "Debug unit tests in executable 'bevy-ball-game'",
            "cargo": {
                "args": [
                    "test",
                    "--no-run",
                    "--bin=bevy-ball-game",
                    "--package=bevy-ball-game"
                ],
                "filter": {
                    "name": "bevy-ball-game",
                    "kind": "bin"
                }
            },
            "args": [],
            "cwd": "${workspaceFolder}",
            "env": {"BEVY_ASSET_ROOT": "${workspaceFolder}/assets"} // ← 新しく書き加えた部分
        }
    ]
}
```