見出し画像

コウペンちゃんと写真を撮る コウペンちゃんランド#004


コウペンちゃんを写真に収めたい

こんにちは、ふにいちごです🍓
前回、歩き回るコウペンちゃんの間をお散歩するところまでの原型ができたので、今回はもう一つの必須機能を作っていきます。
それは写真撮影機能です。

私はぬい撮り(ぬいぐるみの写真を撮ること)が趣味です。と言っても歴は浅く、一年ちょっと前から始めました。
キレイな景色、あるいはおいしそうな料理、日常の何気ない一コマ。ぬいぐるみが見せる表情は多種多様で、何より撮っている時も後から眺める時間も癒される~。
という訳で、コウペンちゃんランドでも写真撮影機能は絶対搭載したい機能です。

複数カメラを用意して、操作で切り替える

プレイヤーを操作するときに利用しているメインカメラで撮影するのももちろん良いのですが、今回はプレイヤーキャラを正面に捉えた自撮り風のアングルから撮影を考えます。
そのため、シーン内にプレイヤーを背後から映すカメラと、プレイヤーを正面からとらえたカメラの2つを用意することにしました。
背後カメラは、前回の記事で紹介したスターターアセットで既に設定されています。
なので、新たにキャラクターを向いたカメラを配置し、プレイヤーの子に設定することで一緒に移動してくれるようにしました。

あとはスクリプトを書いて、キー操作(今回はCボタンにしました)で切り替えます。

using System;
using System.Collections;
using System.IO;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    public GameObject mainCamera;
    public GameObject photoCamera;
    
    private bool isPhotoMode;
    
    AudioSource audioSource;

    // Start is called before the first frame update
    void Start()
    {
    
        // サブカメラはデフォルトで無効にしておく
        isPhotoMode = false;
        photoCamera.SetActive(false);
    }

    // Update is called once per frame
    void Update()
    {
        //通常モードのとき
        if (!isPhotoMode)
        {
            //Cキーが押されたらフォトモードオン
            if (Input.GetKeyDown(KeyCode.C))
            {
                isPhotoMode = true;

                mainCamera.SetActive(false);
                photoCamera.SetActive(true);
            }
        }
        //フォトモードの時
        else
        {
            //ESCキーでフォトモードを抜ける
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                isPhotoMode = false;

                mainCamera.SetActive(true);
                photoCamera.SetActive(false);
            }
        }
        
    }
}

できた!
このコードは空のCameraControllerというオブジェクトを作りアタッチしてあります。
このコードの作成に当たっては、下記のサイト様を参考にしました。
【初心者Unity】複数のカメラの使い方(複数カメラ表示・カメラ切り替え)

書き漏れていましたが、写真を撮るときスターターアセットのままだとあまりに殺風景なので、Unity アセットストアで無料アセットをダウンロードしてきて仮の背景としています。

Free Stylized Nature Environment
Low poly European City Pack

スクリーンショットを画像として保存する

カメラの切り替えが無事にできたので、今度は画面を画像として保存する部分を作成していきます。
フォトモードの間、Pキーを押すと写真を撮れるような設定にしたいと思います。
ついでに、カメラのシャッター音を鳴らして処理が走ったことをわかりやすくしておきます。
(最初何も設定してない時ほんとに動いてるかまるで分らなかったので)

using System;
using System.Collections;
using System.IO;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    public GameObject mainCamera;
    public GameObject photoCamera;
    public AudioClip shutterSound;

    private bool isPhotoMode;
    private string folderName = "Screenshots";
    private bool isCreatingScreenShot = false;
    private string path;

    AudioSource audioSource;

    // Start is called before the first frame update
    void Start()
    {
        audioSource = GetComponent<AudioSource>();

        //保存先のパス
        path = Application.dataPath + "/" + folderName + "/";

        // サブカメラはデフォルトで無効にしておく
        isPhotoMode = false;
        photoCamera.SetActive(false);
    }

    // Update is called once per frame
    void Update()
    {
        //通常モードのとき
        if (!isPhotoMode)
        {
            //Cキーが押されたらフォトモードオン
            if (Input.GetKeyDown(KeyCode.C))
            {
                isPhotoMode = true;

                mainCamera.SetActive(false);
                photoCamera.SetActive(true);
            }
        }
        //フォトモードの時
        else
        {
            //ESCキーでフォトモードを抜ける
            if (Input.GetKeyDown(KeyCode.Escape))
            {
                isPhotoMode = false;

                mainCamera.SetActive(true);
                photoCamera.SetActive(false);
            }
            //Pキーで撮影
            if (Input.GetKeyDown(KeyCode.P))
            {
                audioSource.PlayOneShot(shutterSound);
                PrintScreen();
            }
        }
        
    }

    //写真撮影呼び出しメソッド
    public void PrintScreen()
    {
        StartCoroutine("PrintScreenInternal");
    }

    //写真撮影のコルーチン
    IEnumerator PrintScreenInternal()
    {
        //出力中だったらキャンセル
        if (isCreatingScreenShot)
        {
            yield break;
        }

        //出力中フラグオン
        isCreatingScreenShot = true;

        yield return null;

        //フォルダがなかったら作成
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }

        //撮影日付でファイル名設定
        string date = DateTime.Now.ToString("yy-MM-dd_HH-mm-ss");
        string fileName = path + date + ".png";

        //画像出力
        ScreenCapture.CaptureScreenshot(fileName);

        //画像が出来上がるまで待つ
        yield return new WaitUntil(() => File.Exists(fileName));

        //フラグリセット
        isCreatingScreenShot = false;
    }
}

こちらのコードは以下のサイト様を参考にさせていただきました。
【Unity】C#スクリプトからゲーム画面のスクリーンショットを撮影する方法

また、カメラ音はこちらのサイト様です
OtoLogic

ゲーム内で撮影した記念写真

うん!とりあえずいい感じ!
カメラ操作をUIからできるようにしたり、もっと撮影しました感があった方が良いなど、思う部分はあるのですがとりあえずやりたいことの根っこはできた気がします。
あと、全然違う問題としてコウペンちゃんの身体能力が高すぎて、飾りの傘に飛び乗ってますね(笑)
そもそも、全体的にアセットの大きさがプレイヤーに対して小さすぎるのですが、その辺は実際の遊園地を作りながら調整かなと思います。
また、スターターアセットの方で設定されているのか、特に何をしなくてもマウスで自撮りカメラのアングル調整ができてしまったので、この辺の制限をどうするかも考えなきゃいけないところです。
いざ作ってみると気になるところたくさん出てくる💦
でも進んでることが大事なはず!

まだまだ調整は必要ながら絶対に搭載すると決めていた2つの機能の原型ができました。
そろそろ遊園地のデザイン的な部分も考えていこうと思います(多分ここが一番苦手なところ)
アセットの力も借りつつ、コウペンちゃん要素もいっぱい入れたいな。
それでは、また!

おまけ

カメラのシャッター音を設定した時、スクリプトエラーは出ないのにまったく音が鳴らずめちゃめちゃハマりました。
よく考えたら、足音(アセット内で設定済)も出てないもんね!
Unityの設定とかめちゃくちゃ見たんですが、まったくどこもおかしくなく……。
なんで?と絶望してたら、Windowsの設定がおかしかったです。
サウンド設定の内のアプリの音量がミュートになってた。。。なぜ。
同様の事象をネットに載せてる方が見つけられなかったので
記録として残しておきます。