【Unity】【初心者向け】実践風Unityアプリ開発問題 その5

はじめに

次のような方向けにUnityの基礎力向上を目的とした課題を作成しています。

  • Unityの入門書を2~3冊読了済みの人
  • Unityの基礎力に自身がない人
  • Unityの勉強をしたいけど何をすればよいか分からない人

課題の実装例も用意していますので、少しでも当てはまる方は是非取り組んでみてください。

課題

次に示す内容をUnityを用いて開発する。

【作るもの】
利用規約のスクロールビュー

【仕様】 ※ここに記載されていない部分はどのように実装しても構いません。

  • 利用規約は適当(50行以上)なテキストを保持し、縦スクロールのみ可能とする。
  • スクロール量に対応するスクロールバーを利用規約の右側に表示する。
  • 利用規約を一番下までスクロールすると、『同意する』ボタンを表示する。
  • 『同意する』ボタンを押下すると利用規約および『同意する』ボタンを非表示にし、『戻る』ボタンを表示する。
  • 『戻る』ボタンを押下すると利用規約をスクロールが初期位置の状態で表示し、『戻る』ボタンを非表示にする。なお、その時の『同意する』ボタンは非表示とする。

【イメージ図】

実装例

仕様に基づいた実装の一例をGitHubに公開しています。
実装方法が分からなかったり、他の人の実装が気になる方は確認してみてください。

github.com   ・Assets/Practice5

【Unity】【初心者向け】実践風Unityアプリ開発問題 その4

はじめに

次のような方向けにUnityの基礎力向上を目的とした課題を作成しています。

  • Unityの入門書を2~3冊読了済みの人
  • Unityの基礎力に自身がない人
  • Unityの勉強をしたいけど何をすればよいか分からない人

課題の実装例も用意していますので、少しでも当てはまる方は是非取り組んでみてください。

課題

次に示す内容をUnityを用いて開発する。

【作るもの】
打ち上げ花火のエフェクト

【仕様】 ※ここに記載されていない部分はどのように実装しても構いません。

  • Spaceキーを押すことで打ち上げ花火を発射する。
  • 打ち上げ花火は打ち上げ途中の『上昇フェーズ』と球状に爆発する『爆発フェーズ』を有する。
  • 『上昇フェーズ』では2~3秒のランダムな時間花火がY軸正方向に上昇する。
  • 『上昇フェーズ』終了後、即座に『爆発フェーズ』に移行する。
  • 『爆発フェーズ』では中心から外向き(法線方向)に移動する1000個の火花を発生させる。
  • 火花は重力に従う。
  • 火花は1~2秒のランダムな時間経過後に消失する。

【イメージ図】

実装例

仕様に基づいた実装の一例をGitHubに公開しています。
実装方法が分からなかったり、他の人の実装が気になる方は確認してみてください。

github.com   ・Assets/Practice4

【Unity】【初心者向け】実践風Unityアプリ開発問題 その3

はじめに

次のような方向けにUnityの基礎力向上を目的とした課題を作成しています。

  • Unityの入門書を2~3冊読了済みの人
  • Unityの基礎力に自身がない人
  • Unityの勉強をしたいけど何をすればよいか分からない人

課題の実装例も用意していますので、少しでも当てはまる方は是非取り組んでみてください。

課題

次に示す内容をUnityを用いて開発する。

【作るもの】
キャラクターが壁オブジェクトに隠れた場合に壁にシルエットを描画する機能

【仕様】 ※ここに記載されていない部分はどのように実装しても構いません。

  • キャラクターはUnity標準モデルの『Capsule』とする。
  • キャラクターは壁オブジェクトに隠れていない場合は白色、
    隠れている場合は黄色でシルエットを表示する。
  • キャラクターは左右方向キー(←→)での左右移動のみ可能とする。
  • 壁オブジェクトはUnity標準モデルの『Cube』とする。
  • 壁オブジェクトはキャラクターとカメラの間に配置する。

【イメージ図】

実装例

仕様に基づいた実装の一例をGitHubに公開しています。
実装方法が分からなかったり、他の人の実装が気になる方は確認してみてください。

github.com   ・Assets/Practice3

【Unity】【初心者向け】実践風Unityアプリ開発問題 その2

はじめに

次のような方向けにUnityの基礎力向上を目的とした課題を作成しています。

  • Unityの入門書を2~3冊読了済みの人
  • Unityの基礎力に自身がない人
  • Unityの勉強をしたいけど何をすればよいか分からない人

課題の実装例も用意していますので、少しでも当てはまる方は是非取り組んでみてください。

課題

次に示す内容をUnityを用いて開発する。

【作るもの】
スクリーンショットを撮影する機能

【仕様】 ※ここに記載されていない部分はどのように実装しても構いません。

  • ゲーム画面はUI(Canvas)と3Dシーンで構成する。
  • スクリーンショットボタンはUIに配置する。
  • スクリーンショットボタンを押すとUIを除くゲーム画面をスクリーンショット画像として取得する。
  • 3Dシーンには撮影したスクリーンショット画像を表示する3Dオブジェクトを配置する。

【イメージ図】

実装例

仕様に基づいた実装の一例をGitHubに公開しています。
実装方法が分からなかったり、他の人の実装が気になる方は確認してみてください。

github.com   ・Assets/Practice2

【Unity】【初心者向け】実践風Unityアプリ開発問題 その1

はじめに

次のような方向けにUnityの基礎力向上を目的とした課題を作成しています。

  • Unityの入門書を2~3冊読了済みの人
  • Unityの基礎力に自身がない人
  • Unityの勉強をしたいけど何をすればよいか分からない人

課題の実装例も用意していますので、少しでも当てはまる方は是非取り組んでみてください。

課題

次に示す内容をUnityを用いて開発する。

【作るもの】
同じ色の点を線でつなぎ、全ての点をつなぐゲーム

【仕様】 ※ここに記載されていない部分はどのように実装しても構いません。

  • 色は赤、青、黄、緑の計4種類
  • 色の点は各色2つずつ
  • 線はマウスのドラッグアンドドロップでつなぐ
  • ドラッグ中は始点となる色の点に応じた線を [色の点]-[マウス]間で表示
  • ドラッグ中にもう一方の同じ色の点上でドロップすると線がつながる
  • キーボードの"Esc"キーを押すと、すべての線を消し初期状態に戻す

【イメージ図】

実装例

仕様に基づいた実装の一例をGitHubに公開しています。
実装方法が分からなかったり、他の人の実装が気になる方は確認してみてください。

github.com   ・Assets/Practice1

【Unity】ピンチ操作でUIをズームイン/ズームアウトする

初めに

ピンチ操作でUIをズームするコードを紹介している記事が少なく、表現したい動きがなかなか作れなかったので色々試して一番しっくりくる動きをしたコードを紹介します。

参考サイト

次のサイトのUIの拡縮処理を参考(ベース)にさせていただきました。

kohki.hatenablog.jp

スクリプト

参考サイトのスクリプトから、意図しない移動や拡縮を極力削除したスクリプトになります。

using UnityEngine;
using UnityEngine.UI;

public class PinchScalingManager : MonoBehaviour {

    [SerializeField]
    private ScrollRect scrollRect;    //拡大縮小するコンテンツ
    [SerializeField]
    private RectTransform contentRect;  //拡大縮小するコンテンツ

    //コンテンツのRectTransformの参照
    [SerializeField]
    private float scale;    //現在の拡大率

    [System.Serializable]
    struct RangeClass
    {
        public float min, max;
    }

    [SerializeField]
    private RangeClass RangeScale;          //拡大縮小の範囲

    [SerializeField]
    private float TweenSecond;      //収束するまでにかかる時間

    private bool isPinch = false;       //ピンチ中であればtrue
    private Vector3 center;             //現在の中心座標

#if UNITY_EDITOR
#elif UNITY_IOS || UNITY_ANDROID
    private float max_distance = 0;     //ピンチ開始時の指間の距離
#endif


    void Start () {
        center = contentRect.localPosition / scale;

        //状態の初期化
        UpdateScaling ();

        //表示されている画面の中心を拡大率に合わせて調整する
        contentRect.anchoredPosition *= scale;
    }


    void Update () {

#if UNITY_EDITOR
        bool isZoom = Input.GetAxisRaw("Vertical") != 0;
#elif UNITY_IOS || UNITY_ANDROID
        bool isZoom = Input.touchCount == 2;
#endif

        //タッチ中の処理
        if (isPinch)
        {
            //タッチ終了を感知し、終了処理をする
            if (!isZoom)
            {
                isPinch = false;
                return;
            }

#if UNITY_EDITOR
            float newScale = scale + Input.GetAxisRaw("Vertical") * Time.deltaTime;
#elif UNITY_IOS || UNITY_ANDROID
            float distance = Vector2.Distance (Input.touches [0].position, Input.touches [1].position);
            float newScale = distance / max_distance;
#endif

            SetNewScale(newScale);
            UpdateScaling();
            return;
        }
        else
        {
            scrollRect.enabled = true;
        }

        //タッチ開始時を感知し、初期化処理をする
        if (isZoom)
        {
            center = contentRect.localPosition / scale;
            isPinch = true;
            scrollRect.enabled = false;

#if UNITY_EDITOR
#elif UNITY_IOS || UNITY_ANDROID
            float distance = Vector2.Distance(Input.touches[0].position, Input.touches[1].position);
            max_distance = distance / scale;
#endif
        }
    }

    /// <summary>
    /// 新しい拡大率のバリデートと更新をする
    /// </summary>
    private void SetNewScale(float new_scale){
        // min < 新しい拡大率 < max に設定する
        new_scale = Mathf.Min (new_scale, RangeScale.max);
        new_scale = Mathf.Max (new_scale, RangeScale.min);

        scale = new_scale;
    }


    /// <summary>
    /// 設定された拡大率に基づいてオブジェクトの大きさを更新する
    /// </summary>
    private void UpdateScaling(){
        contentRect.localPosition = center * scale;
        contentRect.localScale = new Vector3(scale, scale, 1);
    }
}

Unity

参考サイトの構成から極力使用しないオブジェクトを削除しました。 ScrollViewのContent以下が拡縮対象になります。

【Unity】FindやGetChildを使用せずに子オブジェクトを取得する方法

初めに

Unityでは子オブジェクトを取得する方法がいくつかあります。

最も楽に実装できる方法にFindやGetChildなどがありますが、これらはHierarchy上のGameObjectの名前や並び順に依存しており、時間が経った後や別の人が編集するといきなりエラーが発生して処理を見直すといったことがあります。

そのためFindやGetChildの使用は保守性の観点からできるだけ避けた方が良いように思います。

そこで、本記事ではFindやGetChildを使用せずに指定の子オブジェクトを取得する方法を紹介します。

取得方法

結論としては、取得対象のオブジェクトに独自のenum型の変数を持つクラスをアタッチし、親オブジェクトはGetComponetsInChildrenによりそのクラスを全て取得するといった方法でオブジェクトを取得します。

実装例

以下のような構成で、"ModelManager"クラスは各子オブジェクトが何の形状をしているかを知る必要がある場合を考えます。



オブジェクト判別用に独自のenum型の変数を持つクラスを作成し、取得対象のオブジェクトにアタッチします。

ModelTag.cs
~~~~~~~~~

using UnityEngine;

public enum MTag
{
    Cube,
    Sphere,
    Capsule,
}

public class ModelTag : MonoBehaviour
{
    public MTag mTag;
}



つぎに"ModelManager"に以下の処理を実装します。

ModelManager.cs
~~~~~~~~~

using UnityEngine;

public class ModelManager : MonoBehaviour
{
    private ModelTag[] models; 

    void Start()
    {
        // 子階層に付与されているModelTagコンポーネントを全て取得
        models = FindObjectsByType<ModelTag>(FindObjectsSortMode.None);

        // ModelTagおよび、GameObjectの参照例
        foreach (var model in models)
        {
            Debug.Log(model.mTag);
            Debug.Log(model.gameObject.transform.position);
        }
    }
}


これにより"ModelManager"クラスは子オブジェクトを取得することができます。 Hierarchy上の各GameObjectの名前を変更したり、並び順が変わったとしてもエラーは生じません。

最後に

今回はモデルの形状をenumとして設定しましたが、enumの値を変えれば何に対しても使用できます。

また、GetComponentsInChilderenではなく、FindObjectsByTypeとすると親子関係に関係なくシーン上の全ての"ModelTag"を持つオブジェクトを取得することもできます。