20200207のUnityに関する記事は6件です。

UnityAcceleratorをLinux上に立ててサービス化する

Unity2019.3からアセットのキャッシュ管理にUnityAcceleratorの使用が推奨されており、
サーバに立てたときの備忘録

UnityAccelerator: v1.0.90+gd82184f
OS: AmazonLinux2

インストール

インストールスクリプトを落として実行する

curl https://unity-accelerator-prd.storage.googleapis.com/unity-accelerator-linux-installer.run --output unity-accelerator-linux-installer.run

sudo ./unity-accelerator-linux-installer.run --mode unattended

※ 「--mode unattended」を付与しない場合は対話式で設定変更が可能
 一度試した場合は入力項目が多く面倒だったので付与してデフォルトインストールにした

サーバ再起動時の自動起動化

インストールスクリプト実行時にサービス登録されてるので有効化しておく

/sbin/chkconfig unity-accelerator on

対象ポートの変更

設定ファイルは/root/.config/unity-accelerator/に展開されている

vi /root/.config/unity-accelerator/unity-accelerator.cfg
→ProtobufPort、LastUsedProtobufPortを任意のポートに変更
service unity-accelerator restart

参考サイト

https://docs.unity3d.com/2019.3/Documentation/Manual/UnityAccelerator.html
https://forum.unity.com/threads/accelerator-options.784514/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity で SQLite を使う基本的な使い方まとめ

Unity で SQLite を使う基本的な使い方まとめ

Unity の更新がはやいのと Android が x64 対策でいろいろと設定方法が変わっているように思いました。
困ったのは、今でも .so ファイル形式をインポートして設定する方法がよく検索にあがることです。

Windows 環境だと .so ファイルをコンパイルして用意するのは、なかなか困難ですが、現在は AAR 形式を公式の SQLite.org からダウンロードして、そのままインポートすれば OK になってました。

記事にまとめたので、ショートカットをメモ。

Android の 64 ビット対策

Unity はビギナーなので、間違いがあったらすいません。(おしえてください)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】独自コンポーネントをCreate/AddComponentの既存カテゴリ階層に追加する

Feb-07-2020 01-19-36.gif

はじめに

以前書いた『描画負荷がかからない透明なuGUI Imageを作る【Unity】』の中で紹介しているNoRenderImageというコンポーネントをHierarchyのCreate/UI以下から追加できるようにしたり、AddComponentのUI以下から追加できるようにしました。

新しく追加するだけなら簡単ですが既存のカテゴリに追加する方法が少しだけややこしかったので、簡単に解説します。

AddComponentの既存カテゴリ階層に追加する

こっちの方が簡単なので先に紹介します。

https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_55365_729374a6-515b-712f-f717-697624aff0f3.png

クラスの先頭に[AddComponentMenu()]をつけるだけです。既存カテゴリ以下にしたければ/で区切って指定してください。第二引数は表示順ですが、コンポーネントについているAddComponentメニューの方では反映されなくて、メニューバーのComponentの方のみに適用されます。

[AddComponentMenu("UI/NonRenderImage", 14)]
public class NoRenderImage : Graphic
{
}

例えばRectMask2Dの下に追加したい場合はRectMask2Dの定義を調べます(コードエディタから辿れます)。

(抜粋)RectMask2D.cs
namespace UnityEngine.UI
{
    [AddComponentMenu("UI/Rect Mask 2D", 13)]
    [DisallowMultipleComponent]
    [ExecuteAlways]
    [RequireComponent(typeof(RectTransform))]
    public class RectMask2D : UIBehaviour, IClipper, ICanvasRaycastFilter
    {
    }
}

13が指定されていることが確認できるため、14を指定してその直後に表示させることができました。

スクリーンショット 2020-02-07 0.47.42.png

ちなみに表示順指定はint型なので、連番の中に挟む際の細かい表示順は指定できなさそうです。(RawImage12MaskRectMask2D13なので、その間は多分辞書順とかでしか制御できない)

Createの既存カテゴリ階層に追加する

HierarchyのCreate/UI以下などに追加する方法です。Canvasの扱いについても簡単に紹介します。

https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_55365_def184c7-72b3-bc0a-5b16-07910cde11e0.png

こちらはコンポーネント自体の指定ではなく、生成するメソッドが登録されているメニューになります。以下のようなstaticメソッドを用意し、[MenuItem()]アトリビュートを追加します。

[MenuItem("GameObject/UI/NoRender Image", false, 2003)]
public static void CreateNoRenderImage()
{
    var go = new GameObject("NoRenderImage");
    go.AddComponent<NoRenderImage>();
}

^実行するとNoRenderImageがアタッチされたGameObjectが生成されるメソッド

こちらは第三引数で表示順の指定をします。既存のCreateメソッドはUnityEditor.UIinternalクラス内にありコードエディタからでは辿れないため、Bitbucket上で公開されているリポジトリから確認します。
Unity-Technologies / ui / UnityEditor.UI / UI / MenuOptions.cs — Bitbucket

(抜粋)MenuOptions.cs
[MenuItem("GameObject/UI/Raw Image", false, 2002)]
static public void AddRawImage(MenuCommand menuCommand)
{
}

例えばRawImage2002が指定されているため、直後に表示したい場合は2003などを指定すれば良いです。

また、生成時に他のコンポーネントと同様に選択中のGameObject以下に生成するようにしてみましょう。Canvas以下でなかった場合は生成する処理も書きました。

[MenuItem("GameObject/UI/NoRender Image", false, 2003)]
public static void CreateNoRenderImage()
{
    // 選択状態のGameObjectを取得する
    var parent = Selection.activeGameObject?.transform;
    // 親や祖先にCanvasが存在しない場合
    if (parent == null || parent.GetComponentInParent<Canvas>() == null)
    {
        // 新規Canvasの生成
        var canvas = new GameObject("Canvas");
        canvas.transform.SetParent(parent);
        // Canvasの初期化
        canvas.AddComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
        canvas.AddComponent<CanvasScaler>();
        canvas.AddComponent<GraphicRaycaster>();
        // 親の付け替え
        parent = canvas.transform;
    }
    var go = new GameObject("NoRenderImage");
    // RectTransformの初期化
    var rectTransform = go.AddComponent<RectTransform>();
    // 親コンポーネントの指定 (nullの場合はルートになるので問題ない)
    rectTransform.SetParent(parent);
    rectTransform.sizeDelta = s_ImageElementSize;
    rectTransform.anchoredPosition = Vector2.zero;
    // 生成したGameObjectを選択状態にする
    Selection.activeGameObject = go;
    // コンポーネントの追加
    go.AddComponent<NoRenderImage>();
}

簡易的ですが、これで他のUIコンポーネントと同様の振る舞いをするようになったと思います。

Feb-07-2020 01-19-36.gif
^生成後のGameObjectが選択状態になる / Canvas下でない場合は生成する

スクリプト全文

Gist: NoRenderImage.cs

NoRenderImage.cs
using UnityEditor;

namespace UnityEngine.UI
{
    /// <summary>
    /// 描画しない透明Imageコンポーネント
    /// </summary>
    [AddComponentMenu("UI/NonRenderImage", 14)]
    public class NoRenderImage : Graphic
    {
        protected override void OnPopulateMesh(VertexHelper vh) { vh.Clear(); }

#if UNITY_EDITOR
        [UnityEditor.CustomEditor(typeof(NoRenderImage))]
        class NonRenderImageEditor : UnityEditor.Editor
        {
            public override void OnInspectorGUI() { }

            private static Vector2 s_ImageElementSize = new Vector2(100f, 100f);

            [MenuItem("GameObject/UI/NoRender Image", false, 2003)]
            public static void CreateNoRenderImage()
            {
                // 選択状態のGameObjectを取得する
                var parent = Selection.activeGameObject?.transform;
                // 親や祖先にCanvasが存在しない場合
                if (parent == null || parent.GetComponentInParent<Canvas>() == null)
                {
                    // 新規Canvasの生成
                    var canvas = new GameObject("Canvas");
                    canvas.transform.SetParent(parent);
                    // Canvasの初期化
                    canvas.AddComponent<Canvas>().renderMode = RenderMode.ScreenSpaceOverlay;
                    canvas.AddComponent<CanvasScaler>();
                    canvas.AddComponent<GraphicRaycaster>();
                    // 親の付け替え
                    parent = canvas.transform;
                }
                var go = new GameObject("NoRenderImage");
                // RectTransformの初期化
                var rectTransform = go.AddComponent<RectTransform>();
                // 親コンポーネントの指定 (nullの場合はルートになるので問題ない)
                rectTransform.SetParent(parent);
                rectTransform.sizeDelta = s_ImageElementSize;
                rectTransform.anchoredPosition = Vector2.zero;
                // 生成したGameObjectを選択状態にする
                Selection.activeGameObject = go;
                // コンポーネントの追加
                go.AddComponent<NoRenderImage>();
            }
        }
#endif
    }
}

最後に

CreateやAddComponentに追加する記事はいくつかありましたが、既存のカテゴリ階層に追加する方法は見当たらなかったので簡単にまとめてみました。

もし参考になったら「いいね」やTwitterのフォローよろしくお願いします!
Twitter: @nkjzm

参考

【Unity】AddComponentMenuでスクリプトを整理して表示 │ エクスプラボ
https://ekulabo.com/add-component-menu

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unity ARkitのFaceTrackingでシーン遷移するとクラッシュする

どんな問題か

UnityでFaceTrackingのアプリを作ったら起こった問題
FaceTrackingシーンから他のシーンに遷移するとき、IOS実機だと落ちる

libc++abi.dylib: terminating with uncaught exception of type Il2CppExceptionWrapper
(lldb)

こんなのを残してさよなら

解決方法

ios - Unity Switch between ARKit Face Tracking and Rear Camera? - Stack Overflow

これで治った。
ExampleのUnityARFaceAnchorManager.cs を改変した人は注意

永遠悩んでた。海外質問フォームって偉大だなぁ、

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Unity】カレンダーの作成【Android/ios】

はじめに

ある日、アプリの制作にカレンダーを使用したくなりました。
「Unity カレンダー」で先生に尋ねてもあまり自分の用途に合った記事が出てこない…
あまりというかほぼ出てこない…なんで?カレンダーになんか恨みあるの?

というわけで適当にパパっと作ってみました。
意外に詰まったので同じ境遇の方がいれば参考にしていただければ幸いです。

aaa.gif

こんな感じのです。

ボタンを並べる

カレンダー自体は、GameObjectにプレハブのButtonを7*6の42個配置していてそこに数字を入れている感じなのでまずはButtonのプレハブを作成します。
作成方法はこちらなど参考にしてください。
大きさなどはGameObjectでそろえるので適当で大丈夫ですがデフォルトの画像だと集合体恐怖症さんが発狂してしまうので無地の画像を適当に作成し、使用したほうがいいと思います。
背景(白).png
作るのめんどい人はどうぞ。

そしてPanelを新規作成し好みの大きさに合わせて、その子として新規オブジェクトを配置します。
背景(白).png
このGameObjectにグリットレイアウトグループコンポーネントを追加します。背景(白).png

これをすることでこのオブジェクトに配置されたボタンがサイズを合わせて並ぶようになります。
そして、オブジェクトを配置するスクリプトを書いていきます。

Calendar.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;
public class Calender : MonoBehaviour
{
    public GameObject canvas;//エディタから指定
    public GameObject prefab;//エディタから指定

    void Start()
    {
        for (int i = 0; i < 42; i++)
        {
            GameObject button = Instantiate(prefab, canvas.transform);
            button.GetComponent<Button>();
        }
    }
}

これをGameObjectに追加し、プレハブにはボタンのプレハブをCanvasにはGameObjectを追加してください。この状態で一度再生してみます。
aaa4.gif
ボタンが白のため死ぬほど見づらいですが42個配置されました。ちゃんと確認したい場合はプレハブのボタンの画像を変更してみてください。GameObjectの幅が狭いと横に7個配置されない場合があるので適宜調整してください。

日付を入れる

このままでは白いボタンが42個配置されただけなのでここに日付を入力していきます。先ほど作ったCalender.csに以下を追加してみてください。

Calendar.cs
public static DateTime SelectDate;
private DateTime D_Date;
private int startday;

 private void CalendarController()
    {
        int days = 1;
        int overday = 1;

        D_Date = new DateTime(SelectDate.Year, SelectDate.Month, 1);  //SelectDateの月の最初の日付
        int year = SelectDate.Year; //年
        int month = SelectDate.Month; //月
        int day = SelectDate.Day; //日
        //最初の日付の曜日を取得
        DayOfWeek firstDate = D_Date.DayOfWeek;
        //何日まであるか
        int monthEnd = DateTime.DaysInMonth(year, month);
        //前月が何日まであるか
        SelectDate = SelectDate.AddMonths(-1);
        month = SelectDate.Month;
        SelectDate = SelectDate.AddMonths(1);
        int lastmonth = DateTime.DaysInMonth(year, month);
        switch (firstDate)
        {
            case DayOfWeek.Sunday:
                startday = 0;
                break;
            case DayOfWeek.Monday:
                startday = 1;
                break;
            case DayOfWeek.Tuesday:
                startday = 2;
                break;
            case DayOfWeek.Wednesday:
                startday = 3;
                break;
            case DayOfWeek.Thursday:
                startday = 4;
                break;
            case DayOfWeek.Friday:
                startday = 5;
                break;
            case DayOfWeek.Saturday:
                startday = 6;
                break;
        }
        int lastmonthdays = lastmonth - startday + 1;

        for (int i = 0; i < 42; i++)
        {
            if (i >= startday)
            {
                if (days <= monthEnd)
                {
                    //文字を入れる
                    Transform DAY = GameObject.Find("GameObject").transform.GetChild(i);
                    DateTime tmp = D_Date;//一時変数
                    DayOfWeek num = tmp.DayOfWeek;
                    //土曜日青・日曜日赤
                    switch (num)
                    {
                        case DayOfWeek.Sunday:
                            DAY.GetChild(0).GetComponent<Text>().color = Color.red;
                            break;
                        case DayOfWeek.Saturday:
                            DAY.GetChild(0).GetComponent<Text>().color = Color.blue;
                            break;
                        default:
                            DAY.GetChild(0).GetComponent<Text>().color = Color.black;
                            break;

                    }
                    DAY.GetChild(0).GetComponent<Text>().text = D_Date.Day.ToString();
                    D_Date = D_Date.AddDays(1);
                    days++;
                }
                else
                {
                    Transform DAY = GameObject.Find("GameObject").transform.GetChild(i);
                    DAY.GetChild(0).GetComponent<Text>().color = Color.gray;
                    DAY.GetChild(0).GetComponent<Text>().text = overday.ToString();
                    GameObject button = GameObject.Find("GameObject").transform.GetChild(i).gameObject;
                    button.GetComponent<Button>().onClick.RemoveAllListeners();
                    overday++;
                }
            }
            else
            {
                Transform DAY = GameObject.Find("GameObject").transform.GetChild(i);
                DAY.GetChild(0).GetComponent<Text>().color = Color.gray;
                DAY.GetChild(0).GetComponent<Text>().text = lastmonthdays.ToString();
                GameObject button = GameObject.Find("GameObject").transform.GetChild(i).gameObject;
                button.GetComponent<Button>().onClick.RemoveAllListeners();
                lastmonthdays++;
            }
        }
    }

死ぬほど見づらいコードだしなんか気持ち悪い箇所もあるかと思うのですが備忘録として書いているのものなのでお手柔らかにお願いします。(白目)
そしてvoid Start()

SelectDate = DateTime.Now;
CalendarController();

をさらに追記し実行してみます。
aaa44.gif

はい、日付が登録されました。SelectDateをDateTime.Nowにしているので実行した月のカレンダーができていると思います。ここを変更すれば変更した月のカレンダーが表示されます。
カレンダーを表示したいだけの方はこれにて完了になります。

ボタン押下時に値を保存する

自分はカレンダーで選択した値を使いたかったのでボタンを押した際の処理を追記していきます。
上のコードのFor分を以下に変更し、関数も追加してください。

Calendar.cs
for (int i = 0; i < 42; i++)
        {
            if (i >= startday)
            {
                if (days <= monthEnd)
                {
                    //文字を入れる
                    Transform DAY = GameObject.Find("GameObject").transform.GetChild(i);
                    DateTime tmp = D_Date;//一時変数
                    DayOfWeek num = tmp.DayOfWeek;
                    //土曜日青・日曜日赤
                    switch (num)
                    {
                        case DayOfWeek.Sunday:
                            DAY.GetChild(0).GetComponent<Text>().color = Color.red;
                            break;
                        case DayOfWeek.Saturday:
                            DAY.GetChild(0).GetComponent<Text>().color = Color.blue;
                            break;
                        default:
                            DAY.GetChild(0).GetComponent<Text>().color = Color.black;
                            break;

                    }
                    DAY.GetChild(0).GetComponent<Text>().text = D_Date.Day.ToString();
                    //以下3行追加
                    GameObject button = GameObject.Find("GameObject").transform.GetChild(i).gameObject;
                    button.GetComponent<Button>().onClick.RemoveAllListeners();
                    button.GetComponent<Button>().onClick.AddListener(() => { set_Date(tmp); });
                    D_Date = D_Date.AddDays(1);
                    days++;
                }
                else
                {
                    Transform DAY = GameObject.Find("GameObject").transform.GetChild(i);
                    DAY.GetChild(0).GetComponent<Text>().color = Color.gray;
                    DAY.GetChild(0).GetComponent<Text>().text = overday.ToString();
                    GameObject button = GameObject.Find("GameObject").transform.GetChild(i).gameObject;
                    button.GetComponent<Button>().onClick.RemoveAllListeners();
                    overday++;
                }
            }
            else
            {
                Transform DAY = GameObject.Find("GameObject").transform.GetChild(i);
                DAY.GetChild(0).GetComponent<Text>().color = Color.gray;
                DAY.GetChild(0).GetComponent<Text>().text = lastmonthdays.ToString();
                GameObject button = GameObject.Find("GameObject").transform.GetChild(i).gameObject;
                button.GetComponent<Button>().onClick.RemoveAllListeners();
                lastmonthdays++;
            }
        }

    void set_Date(DateTime date)
    {
        Debug.Log(date);
        //値を保存する処理など
    }

これで実行してみます。

aaa44k.gif

自分はわかりやすいようにテキストで表示していますが上のコードだとログで表示されるはずです。
以上になります。わかりづらいかもしれませんがお役に立てたら幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityでシューティングゲームを作る(4)

ここまでの進捗

  • 背景がループするようにした。
  • 普通の敵の動作を作成し、その敵が3秒ごとに生成される。
  • 瞬間移動する敵の動作を作成し、5秒ごとに生成する。
  • プレイヤーが画面の範囲外に行かないようにした。
  • 敵とプレイヤーが衝突したらプレイヤーが消滅する。
  • 分散攻撃の敵を実装する。
  • タイトルシーンとエンディングシーンを追加する。

今後やること

  • ボスキャラの動作を実装する。
  • エフェクトとBGMを追加する。
  • プレイヤーが横に移動すると機体が傾くアニメーションをつける
  • プレイヤーがダメージ受けると点滅して数秒だけ無敵状態になる

この記事では赤い部分を作成した。

プレイヤーがダメージを受けると点滅する

点滅するコルーチンを作成してプレイヤーの衝突判定の中でコルーチンを実行するようにした
コルーチンは関数内で時間を空けて処理をさせたいときに使われる

点滅するコルーチンの作成に関してはこのサイトがとても参考になった。
ftvlog/オブジェクトを点滅させるスクリプト

以下がコルーチンとなる

//ダメージを受けた時に点滅する
    IEnumerator Blink() {
        for(int i=0;i < 4; i++) {
            renderer.enabled = !renderer.enabled;

            yield return new WaitForSeconds(0.2f);
        }
    }

この中でオブジェクトの点滅を0.2秒間隔で4回行っている
これによってダメージを受けると以下のようになった
ezgif.com-video-to-gif (2).gif

プレイヤーがダメージを受けて点滅してる間は無敵になる

今回はプレイヤーが攻撃を受けてから点滅している間だけプレイヤーのレイヤーを変更することによって衝突判定を無効化した。
teratailに質問があったので参考にした。
teratail/衝突判定を一定時間無効化したいです

コメント 2020-02-07 033604.png

まずレイヤーを追加するために[Edit]→[Project Settings]を選択する。

コメント 2020-02-07 033643.png

この設定画面がでるので左の欄から[Tags and Layers]を選択し、Layersの中からUser Layerのどれかに名前を付ける
今回はUser Layer 9にInvisibleという名前を付けた。

コメント 2020-02-07 033725.png

最後に左の欄からPhysicsを選択し、衝突を無効化したいオブジェクトがあるレイヤーと先ほど作成したレイヤーのチェックを外す。
これによってInvisibleのレイヤにあるオブジェクトとDefaultにあるオブジェクトの衝突が無効化される。

ezgif.com-video-to-gif (3).gif

ちょっと見ずらいかもしれないけど、点滅時間が1.2秒で短いので一瞬しか無効にならない。
今後調整していこうと思う。

これで弾を受けたときの点滅と無敵時間を作ることができた。
難易度をあげるにつれて点滅時間の延長も検討していきたい。

次回はアニメーションをつけてボスを作成して完成させたい。
ちなみにここからこだわるつもり

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む