初心者がUnity2dでドット絵ゲーム制作する上で気をつけること

この記事のターゲット

Unity2dに初めて触る人、Unity2dでゲーム制作してるがPixcelPerUnitなどがよく分かってない人に向けて 画像サイズ・PixcelPerUnit・CameraSize・Texture2Dの設定について話していきます

画像サイズについて

ゲーム内で使う画像のサイズは2・4の倍数にするよう心掛けてください、これをしないとゲームのデータ容量が大幅に増えることになって今しまいます。 実際に2・4の倍数以外の大きさの画像を使っていると警告文が出されます。

PixcelPerUnitとは

Unityでの大きさの単位は基本的にメートルになっています。 PixcelPerUnitは1m当たりに何pixcel入れるかを表しています。(単位で表すとpixcel/m) たとえばPixcelPerUnitが100だとしたら1pixcelは0.01mということになります。

CameraのSizeについて

UnityだとCameraのコンポーネントからSizeをいじくれます。 このSizeは大きいほど写す範囲が大きくなります。ではこのSizeはいくつにするべきでしょう? 答えは Size=(画面の縦の大きさ)/(2×PixcelPerUnit) にするとよいとされています。 たとえば画面の大きさが400×400である場合はPixcelPerUnitをデフォルトの100だとするとCameraのSizeは2にすると Cameraが写す大きさがちょうど4m×4mと同じになります。

Texture2Dの設定について

使うドット絵のTexture2d(Sprite)はすべて FilterModeはPoint(no filter)に設定する CompressionはNoneにする この2つをおこないましょう。これをおこなわないとドット絵が滲んだりしてしまいます。

結局どうすればいいのか

これに関しては完全に僕個人の意見ですがまずドットの絵のサイズが全部同じならPPUをそれに設定すれば良いが多分無理なので PPUは統一した値にする(デフォルトの100がいいよ) 画面サイズを確定させる 画面の縦Size/ ( 2 * PixcelPerUnit) からカメラのサイズも決定させる Texture2Dの設定は忘れずに… この4つをおこないます。もっといい方法があればコメントで教えてくださると光栄です。

参考にしたサイト

【間違えやすい】Unityの正しい画像サイズとは - 渋谷ほととぎす通信

ドット絵ゲームをunityで作るときに押さえておきたいポイント - Qiita

Unityでゲームを作ろう ~カメラのサイズ設定について~ | かれいどブログ

【Unity】ドット絵をボヤけさせないSpriteアセットの設定 | ゲーム開発65535 Ver2

UnirxでのObserverパターンを身近な例で例えてみる

0 始めに

この記事ではUnityの外部ライブラリあるUnirxでのObserverパターンを身近な例に例えてみようといった記事です。 今回はピザの宅配サービスに例えてみたいと思います 実際にコードと図を交えて説明いたします。また当ブログ内にUnirxの記事が他にもあるのでそちらも 参考にしていただけると嬉しいです。

1 現実世界の流れ

実際の現実世界の流れを確認します。

1

まずピザ屋が回転されてWeb上などで登録サービスを公開します。

2

ユーザーはそのピザ屋を調べ、Web上で自分のデータ(住所や氏名)を登録します。

3

その後ピザ屋は登録された先に一定の決められたタイミングでピザを送ります。 届けられたピザをユーザーが食べたり、保存できたりします。

4

最後に一定期間たったら店はユーザーに届けるのを中止出来たり、逆にユーザーが 届けられるのを中止したりすることが出来ます。

2 Unirxに置き換えてみる

これをUnirxに置き換えて考えてみるとSubjectがピザ屋、Observerがユーザー、IobservableがWebページに 当たります。これを実際のコードに置き換えてみます。 ここで大切な考え方はSubjectは値を発行(ここではピザを配達する)ことしかせず、実際の処理内容は Observer側に書かれているということです。

3 実際のコード

まずはピザの種類を生成します

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//送るピザの種類
 public enum PizzaType
{
    SeafoodPizza,
    MeatPizza,
    VegetablePizza,
    SweetPizza
}

次にSubject側のクラスを生成します

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UniRx;

//ピザショップ(Subject)のクラス
public class PizzaShop : MonoBehaviour
{
    //Subjectを作ってIobservableだけ公開する・・・①
    private Subject<PizzaType> pizzaSubject = new Subject<PizzaType>();
    public IObservable<PizzaType> OnOrderObservable => pizzaSubject;

    int time;
    int counter;


    void Start()
    {
        time = 0;
        counter = 1;
        StartCoroutine(DayCoroutine());
    }

    IEnumerator DayCoroutine()
    {
        while (true)
        {
            //10回配達したら倒産する・・・④
            if (counter > 10)
            {
                pizzaSubject.OnCompleted();
                pizzaSubject?.Dispose();
                yield break;
            }

            //特定の時間になったらランダムにピザを送りつける・・・③
            if(time == 19)
            {
                int random = UnityEngine.Random.Range(0, 4);
                switch (random)
                {
                    case 0:
                        pizzaSubject.OnNext(PizzaType.MeatPizza);
                        break;
                    case 1:
                        pizzaSubject.OnNext(PizzaType.SeafoodPizza);
                        break;
                    case 2:
                        pizzaSubject.OnNext(PizzaType.VegetablePizza);
                        break;
                    case 3:
                        pizzaSubject.OnNext(PizzaType.SweetPizza);
                        break;
                }
                counter++;
            }

            //0.01秒待って1時間を勧める(0~23時を繰り返す)
            yield return new WaitForSeconds(0.01f);
            if (time < 24) { time++; }
            else { time = 0; }
        }
    }
}

最後に2つObserverを生成します

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UniRx;

public class UserA : MonoBehaviour,IObserver<PizzaType>
{
    //ピザショップをへの参照
    private PizzaShop pizzaShop;
    //購読終了用
    private IDisposable disposable;
    //ピザが届けられた回数
    private int counter;
    void Start()
    {
        //参照を持つようにして配達回数を0にする
        pizzaShop = GameObject.Find("PizzaShop").GetComponent<PizzaShop>();
        counter = 0;
        //公開されているIobservableを使って自身を登録する(AddTo()で自身が破壊されたときにDispose()されるようにする)・・・②
        disposable = pizzaShop.OnOrderObservable.Subscribe(this)
                                                .AddTo(this);
    }

    void Update()
    {
        //100回配達されたら自身を破壊する
        if(counter > 100)
        {
            Destroy(this.gameObject);
        }
    }
    private void OnDestroy()
    {
        disposable?.Dispose();
    }

    public void OnCompleted()
    {
        Debug.Log("Aが契約を解除しました");
    }

    public void OnError(Exception error)
    {
        Debug.Log("エラー");
    }

    //ピザが届けられた時の処理・・・④
    public void OnNext(PizzaType value)
    {
        Debug.Log(value.ToString() + "を食べます");
        counter++;
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using UniRx;

public class UserB : MonoBehaviour, IObserver<PizzaType>
{
    private PizzaShop pizzaShop;
    private IDisposable disposable;
    private int counter;

    void Start()
    {
        pizzaShop = GameObject.Find("PizzaShop").GetComponent<PizzaShop>();
        counter = 1;

        disposable = pizzaShop.OnOrderObservable.Subscribe(this)
                                                .AddTo(this);
    }

    void Update()
    {
        //回数がAと異なる
        if (counter > 3)
        {
            Destroy(this.gameObject);
        }
    }
    private void OnDestroy()
    {
        disposable?.Dispose();
    }

    public void OnCompleted()
    {
        Debug.Log("Bが契約を解除しました");
    }

    public void OnError(Exception error)
    {
        Debug.Log("エラー");
    }

    //ここがAと異なるので注意する
    public void OnNext(PizzaType value)
    {
        Debug.Log(value.ToString() + "を冷蔵庫に入れます");
        counter++;
    }
}

こんな感じになれば成功です!

4 最後に

今回はUnirxを身近な例で置き換えて考えてみました。 何か間違ったことなどを書いていればご指摘いただけたら光栄です。