Unityエディタ上でスクリーンショットを撮る

# はじめに
自分がUnityでゲームを作っている時には、ゲーム画面のスクリーンショットを撮りたい場面が結構あります。
ぱっと思いつくようなことでも、面白かった場面やバグが起きているところ、ストアにアップする用の写真、プロモーション用の絵など、撮影したいシチュエーション・用途は様々に考えられます。<br>画面全体を撮影したい場合はOSに組み込まれている機能(Windowsなら`Windows`+`PrintScreen`、macOSなら`command`+`shift`+`3`などで撮影できる)を使えばいいし、ゲーム画面を動画として撮影したい場合はUnity公式が提供しているパッケージ[Recorder](https://docs.unity3d.com/Packages/com.unity.recorder@4.0/manual/index.html)をインストールすれば簡単にできるのですが、ゲーム画面を写真として撮影するという比較的単純でニーズも多いと思われる機能は、意外とUnityデフォルト状態では提供されていなかったりします。<br>この記事では、このスクリーンショットを撮るという要求に対して取り得るアプローチを2つ紹介します。

# 方法1：スクリーンショット撮影用のエディタ拡張スクリプトを書く
1つ目は、自分で撮影用スクリプトを書いてしまう方法です。事前準備に多少時間はかかりますが、拡張性も高くプロジェクトを跨いで使い回せるのでベターな選択肢かなと思います。
一般的には`UnityEngine`名前空間で提供されている`ScreenCapture.CaptureScreenshot`を使って実装することになります。以下にはそのスクリプトの実装例を`ScreenshotUtil`として記載しました。
```CS:ScreenshotUtil.cs
#if UNITY_EDITOR
using System;
using System.IO;
using UnityEditor;
using UnityEngine;

public static class ScreenshotUtil
{
    private const string outputDirectory = "Screenshots/";
    private const string fileNamePrefix = "screenshot";

    // ctrl(macならcommand)+alt+Sをショートカットに設定
    [MenuItem("Tools/Screenshot %&S", false)]
    public static void CaptureScreenshot()
    {
        // 出力先ディレクトリがなければ作成する
        if (!Directory.Exists(outputDirectory))
        {
            Directory.CreateDirectory(outputDirectory);
        }

        var now = DateTime.Now;
        // 出力ファイル名を指定
        var fileName = $"{fileNamePrefix}_{now.Year}_{now.Month}_{now.Day}_{now.Hour}_{now.Minute}_{now.Second}.png";
        // 出力パスを指定
        var outputPath = Path.Combine(outputDirectory, fileName);
        ScreenCapture.CaptureScreenshot(outputPath);
        // 撮影したことをログで通知
        Debug.Log($"Captured a screenshot: {fileName}");
    }
}
#endif
```
このスクリプトをプロジェクト内の任意の場所に置くことで動作します。スクリプト全体を囲う条件付きコンパイルのシンボルに`UNITY_EDITOR`を指定しているので実際のビルドには含まれず、よくエディタ拡張を置くのに使われる`Editor`ディレクトリ下に置かなくても問題ありません。

いくつか注意点があるので少し解説します。

## 出力先のディレクトリ、Assets以下に出力する場合
```CS
private const string outputDirectory = "Screenshots/";
```
この部分で出力先の指定を行なっていますが、これはプロジェクトのルートディレクトリから見たパスです。上のコードでは`Screenshots/`を指定していますが、下の画像のようにAssets下に置いてUnityエディタ上から見たい場合は`Assets/Screenshots`などのように変更する必要があります。
また、Assets以下のディレクトリを指定した場合、上記のコードだけではスクリーンショット後自動でエディタ上に変更が反映されません。これは`AssetDatabase`のリフレッシュ処理などをコード上で行なっていないからですが、このままでも手動でリフレッシュを実行すると下の画像のようにファイルが見えるようになります。コード上でリフレッシュを行いたい場合はやや面倒で、自分が試したところスクリーンショットの撮影タイミングとファイルの保存タイミングにラグがあり、非同期的に保存を待ってからリフレッシュを行う必要がありそうです。
![スクリーンショット 2022-12-01 23.21.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987563/74e4cae4-5b30-aa27-284e-9caa075ce593.png)
## 出力される画像のサイズ
出力される画像のサイズは、ゲームビューでアスペクトを相対値やフリーに設定していた場合は実際今表示されている解像度になります。アスペクトを`1920x1080`などの固定値に設定していた場合はそのサイズで出力されます。

## ショートカットの指定
```CS
[MenuItem("Tools/Screenshot %&S", false)]
```
`MenuItem`属性でこのメソッドを実行するメニューの名前とショートカットを指定しています。上記の例ではメニュー名として`Tools/Screenshots`、ショートカットとしてctrl(macならcommand)+alt+Sを設定しました。ctrlまたはcommandは`%`、shiftは`#`、alt(option)は`&`などのように、文字列で使いたいショートカットを指定できます。
ショートカットの設定はUnityの`Shortcuts`設定からも可能ですが、プロジェクトによって導入するかどうかが変わるようなエディタ拡張に割り振るショートカットは、全体設定では行わない方が無難だと思います(ただし`MenuItem`で指定する方法も、ショートカット設定が局在化して見づらいと言う問題はあるかもしれません)。
![スクリーンショット 2022-12-01 23.33.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987563/7174b29b-8c38-4100-feef-8ead87fcb046.png)

# 方法2：Unityの開発者モードを利用する
自分が最近知ったのが、こちらの開発者モードを利用してスクリーンショットを撮る方法です。
最近アップロードされていたUnity公式のYoutube動画で紹介されていて知りました。
<iframe width="560" height="315" src="https://www.youtube.com/embed/mc0mHcnqu44" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

Unityの開発者モードには、About Unityのパネルを表示した状態で`internal`と入力することで入ることができます。
![スクリーンショット 2022-12-01 23.42.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987563/13133ccd-3845-fdc8-a598-91a0282967f7.png)
![スクリーンショット 2022-12-01 23.42.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987563/f3b1eaa0-91b1-3c2d-a602-0c6c26d85495.png)
入るとこのように各タブの左上に虹色に光る丸が追加されます。
開発者モードに入っている状態だと、`Window`タブに`Internal`メニューが追加され、その中の`Screenshot`からスクリーンショットを撮影できるようになります。
これで撮影できるならこれでいいと言う気もしますが、常時開発者モードで作業することは推奨されておらず、また保存場所も選べないので、事前に準備する時間があるならやはり自分でスクリプトを書いた方がいいと個人的には思います。
この方法でスクリーンショットを取った場合は、もう一度About Unityのパネルを表示した状態で`internal`と入力して開発者モードから抜けることを忘れないようにしましょう。
![スクリーンショット 2022-12-01 23.50.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987563/241e80ac-5299-0354-0545-e1a584fbe80b.png)

# さいごに
デフォルトでスクリーンショットを撮る機能はあってもいいような気がしますが、何か導入するに際して弊害があるのでしょうか。