color×2

自分なりに学んだ事を記すところ

unimgpicker-plusでプレイヤーにとっての課題を作れるようにする(その2)

その1でやろうと思ったことを進めていきます。

実際に出てくる時のサイズで画像を表示

AddImage.csにssImage(表示するimage)をもう一個追加する形で解決。

本来の敵のサイズとここで表示してるサイズ、微妙に違うんです。
UI側とオブジェクト側では参考にする寸法みたいなのが変わるのか…?

この微妙な違いは大して影響はないだろうと判断。特に調整はしないです。

読み込んだ画像を保存する

これをどうするか悩んでいましたが、やっと思いつきました。

取り込んだ画像を改めてpngとして保存して、自由に扱えるようにします。
これで端末から画像を消しちゃっても大丈夫。

取り込んだ画像はAddImage.csのTexture(Texture2D), Texture2(Sprite)に格納されているらしいです。

新しく保存ボタンを用意しました。押下すれば画像を保存するようにします。

Texture2の方を利用して画像を保存します。事前準備としてTexture2をstaticにして他のところでも使えるようにします。

public static Sprite texture2;

 

ボタンに適用するスクリプトを用意するため、TaskMade.csを新規作成。

こちらのサイトを参考にして、課題のpngファイルを作成、保存するように書いていきます。

【Unity(C#)】テクスチャを画像データに変換して端末に保存、読み込み - Qiita

using System.IO; //ファイル保存用

//『保存ボタン』をタップしたら実行
public void PushTaskImage()
{
    Debug.Log("課題を保存しました");

    //読み込んだ画像をpngに変換
    byte[] bytes = AddImage.texture2.texture.EncodeToPNG();
    //保存
    File.WriteAllBytes("Assets/Images/a_test.png", bytes);
}

回りくどい事してんな…と思いつつ、このスクリプトをMainCameraにつけて、ボタンにイベントを割り当てて実行してみる。

保存した時は何も出てきませんが、Ctrl+Rで読み込み直せば…

やったぜ!!!

あとは画像の保存場所を考え直したり、複数の課題の画像を保存出来るように(今のままだと一枚だけしか保存されない)して実際に敵として倒せるようにしていきます。

複数の画像を保存出来るようにする

a_test.pngとして画像を保存する、としていたので一枚の画像しか生成されない状態になっています。

ファイル名に番号を含ませ、同じ番号のファイル名がある場合は次の番号で生成できるか確認する、という流れで複数の画像を保存出来るようにします。(いわゆる連番?)

コードとしてはこんな感じになりました。参考にしたサイト↓

C# フォルダ作成時、同名フォルダがあれば連番を振る - Qiita

using System.IO; //ファイル保存用

//『保存ボタン』をタップしたら実行
public void PushTaskImage()
{
    Debug.Log("課題を保存しました");

    //画像ファイル名に使う変数
    int i = 1;
    string path = "Assets/Images";

    //読み込んだ画像をpngに変換
    byte[] bytes = AddImage.texture2.texture.EncodeToPNG();

    //重複しない画像ファイル名を探す
    while (File.Exists(path + "/task" + i + ".png"))
    {
         i++;
    }
    //(重複しないファイル名を見つけたら)保存
    File.WriteAllBytes(path + "/task" + i + ".png", bytes);
}

これで保存ボタンを5回押してCtrl+Rしたら5個同じ画像が保存されます。

ちなみに、どれか一枚を削除してから、また画像を保存すると存在しない番号の中で最も若い番号が割り振られたファイル名で保存されます。
task2.pngを削除してからまた画像を保存するとtask2.pngとして新しく保存されました。

画像の保存場所作成(editor)

現在、生成した画像をImagesフォルダに保存しています。このフォルダには元々用意している課題の画像などがあるので、混じると面倒そうです。

まずは新しく自作課題専用のフォルダを作りたいと思います。
ImagesフォルダにYourTaskフォルダを作り、その中に画像を作成するように変更します。
以下のようにパスを変更しました。

string path = "Assets/Images/YourTask";

自作課題を閲覧できるようにする

TaskMuseumシーンを新規作成し、生み出した課題を見れるようにします。
見た目はこんな感じにしました。

→を押せばタイトル画面に戻るようにします。
謎の幅広いテキストは、画像までのパスと何枚画像があるかを表示するために用意しました。(android端末で動作確認する時はDebug.Logが見えなくなるので…)

そしてcreate emptyでYourTaskparentを作成。子として自作課題画像を入れます。

以下、TaskMuseum.csのコードです。参考にしたサイト↓

PNGファイルを読み込んでTextureとして使う方法 | My note

using UnityEngine.SceneManagement; //シーン移動用
using System.IO;      //画像ファイル検索用
using UnityEngine.UI; //テキスト用(画像ファイルパス表示)

public class TaskMuseum : MonoBehaviour
{
    string[] yourimages; //画像ファイルを格納
    List<Sprite> YourEnemyTypeList = new List<Sprite>(); //自作課題の種類を格納するリスト
    public GameObject PrefabObj;   //並べる敵オブジェクト
    public Transform ParentEnemy;  //画像を並べるところ
    SpriteRenderer YourTaskSpriteRenderer; //敵の見た目を変更するための変数
    public Text Checktxt;//ファイルパス確認用テキスト

    void Start()
    {
        ImportYourTask();
        YourTaskParade();
    }

    //戻るボタン押下でタイトル画面に戻る
    public void TitleBack()
    {
        SceneManager.LoadScene("Title");
    }

    //画像を読み込む
    void ImportYourTask()
    {
        //画像パス取得
        yourimages = Directory.GetFiles(@"Assets/Images/YourTask", "*.png");
        int tmp = 1;

        //画像を使える形に変える
        foreach (string path in yourimages)
        {
            //Texture2Dに変換
            byte[] bytes = File.ReadAllBytes(path);
            Texture2D texture = new Texture2D(2, 2);
            texture.LoadImage(bytes);

            //spriteに変換
            Rect rect = new Rect(0f, 0f, texture.width, texture.height);
            Sprite sprite = Sprite.Create(texture, rect, Vector2.zero);

            //spriteを格納
            YourEnemyTypeList.Add(sprite);

            Checktxt.text += ", " + tmp + ": ";
            Checktxt.text += path;
            tmp++;            
        }
        Checktxt.text += "画像は" + YourEnemyTypeList.Count + "枚あるよ!";
    }

    //自作課題を表示
    void YourTaskParade()
    {
        int column = 2; //横
        float xOffset = 2f;
        float yOffset = 1.7f;

        for (int i = 0; i < yourimages.Length; i++)
        {
            //自作課題生成
            GameObject obj = Instantiate(PrefabObj, Vector3.zero, Quaternion.identity);
            //自作課題の名前変更(cloneだと判別出来ないので)
            obj.name = "enemy_" + (i + 1);
            //敵を格納する親オブジェクト設定
            obj.transform.SetParent(ParentEnemy);

            //自作課題の位置設定
            float xPos = -3.4f + (i % column) * xOffset;
            float yPos = -1.3f - (i / column) * yOffset;
            obj.transform.localPosition = new Vector3(xPos, yPos, 0f);

            //自作課題見た目変更
            YourTaskSpriteRenderer = obj.GetComponent<SpriteRenderer>();
            YourTaskSpriteRenderer.sprite = YourEnemyTypeList[i];
        }
    }
}

YourTaskParadeという関数は実際のゲームで課題を表示する時とほぼ同じことをしているので、それをほぼコピーしています。Checktxt関連はパス表示のためです。

実行するとこんな感じになりました。

画像でかくね??ルンバがピーマンを食べてるみたいになりましたが、ちゃんと表示は出来ました。パスが一部変な表示になっていますが、とりあえずは問題なさそうだと確認。

画像の保存場所作成続き(android)、画像表示

このままでもandroid端末で動くんじゃないかと思ってBuild and Runして実機で動かしてみたんですがダメでした。

表示されない原因はパスが上手く通っていないからだろうと仮定し、ググっているとこんなサイトを発見。

【Unity(C#)】テクスチャを画像データに変換して端末に保存、読み込み - Qiita

したい事と似てる!保存しているところを引用すると、

string directoryPath = Application.persistentDataPath + "/" + folderName + "/";

Application.persistentDataPath??こちらのサイトにも記載されていましたが、永続性のあるデータを保存するためのパスをこれで得られるみたいです。

こいつを組み込んでやってみよう。

追記した部分だけ抜き出したTaskMuseum.csのコードです。

//画像を読み込む
void ImportYourTask()
{
    #if UNITY_EDITOR
    //画像パス取得
    yourimages = Directory.GetFiles(@"Assets/Images/YourTask", "*.png");
    #elif !UNITY_EDITOR && UNITY_ANDROID //androidのみ
    yourimages = Directory.GetFiles(UnityEngine.Application.persistentDataPath, "*.png");
    #endif
    int tmp = 1;

    //以下略           
}

#ifとか見慣れないやつも入れてみました。
これにより、エディタで動かしている場合の動き、androidで動かしている時の動き、のように条件付きで操作を変えられます。

UNITY_ANDROIDだけで条件分けしていない理由はこちらのサイトを見たためです。

【解決】#if UNITY_ANDROIDがPCでも実行される | ゲーム制作の骨(Tips)

引用すると、

Build SettingsでTarget PlatformをAndroidに切り替えている場合、エディタでの実行でも「UNITY_EDITOR」と「UNITY_ANDROID」2つのプラットフォーム情報を持つのを確認。

エディタとandroid端末は別の動きをしてほしいので、このように書いています。

画像を作成するシーンもこんな感じに追記してandroid端末で動かしてみると…

パスが表示されてるぞ!

画像も表示されてる!成功です。

次回やることリスト

次回はこのあたりをしようと思います。

  • 自作画像のトリミング、リサイズ
  • 敵として自作課題を登場、破壊する(ゲームに組み込む)

その3はこちら↓

unimgpicker-plusでプレイヤーにとっての課題を作れるようにする(その3) - color×2