20200112のUnityに関する記事は8件です。

[Unity] ビルド関連処理を自分なりに基盤化し始めました

目的

  • アプリビルドのCIなどで要求される機能を実装

現在の機能

  • 設定ファイルおよびSchemeに応じたビルド設定の反映
    • ライブラリの追加を避けつつデシリアライズ出来るようXMLに記述
    • が、今後やりたい事を踏まえるとスクリプトでも扱いやすい形式にすべきか悩み中
  • KeystoreやAppleDeveloperTeamIdなども設定ファイルから切り替え
  • ログを詳細と簡易で出し分け
  • AndroidでExport Projectしつつapk出力まで対応

実行

  • macOSでもWindowsでもbashから以下のコマンドで実行可
sh Batch/AppBuild.sh -p [プラットホーム] -c [設定名] -s [scheme] -e [実行メソッド名]

成果物

追加でやりたい事

  • アプリアイコンの差し替え
  • バージョン変更(BuildNumberのインクリメント)
  • テスト公開用の各ストアへのアップロード
  • Deploygateへのアップロード
  • Build And Run対応

今後

  • 自作アプリ開発と合わせて機能追加や改修が入り次第フィードバックしていきます
  • Scriptable Build Pipeline を使えばもっと簡易化できるかもです
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityで単語暗記アプリを作っていますが、うまくいきません。

現在、Unityを使って単語暗記アプリを作っています。
構成は、以下の通りです。
 ①一番上に日本語が出てくる。
 ②その日本語を英語に訳し、InputFieldに書き込む。
 ③もしInputFieldのテキストと模範解答が一緒なら、正解数を+1,違うなら次の問題へ。
 ④全部問題を出し終わったら、最終結果として正解数を表示する。
これらのようなアプリを作ろうと、以下のようにプログラムを書き込みました。


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

public class test : MonoBehaviour
{
public InputField i_p;
public Text t_x;
public Text seikaisuu;
public Text t_t;
int QN = 0;
int RN = 0;
string[] ET = new string[2];
string[] EA = new string[2];

// Start is called before the first frame update
void Start()
{
    //ETの単語を記述:問題
    ET[0] = "あ";
    ET[1] = "い";
    //EAの単語を記述:答え
    EA[0] = "a";
    EA[1] = "i";
    //コンポーネントを扱えるようにする
    i_p = i_p.GetComponent<InputField>();
    t_x = t_x.GetComponent<Text>();
    //seikaisuu = seikaisuu.GetComponent<Seikaisuu>();
    //t_t = t_t.GetComponent<t_t>();
    NS();

}

private void NS()
{
    t_x.text = "どういう意味?:" + ET[QN];

}

public void IT()
{
    //テキストにi_pの内容を反映
        t_x.text = i_p.text;
    //解答が模範解答と同じだった時の処理
    if (EA[QN] == i_p.text){
        RN++;
    }
    if (QN + 1 < ET.Length)
    {
        QN++;
        Invoke("NS", 1);
        i_p.text = "";
        //NS();
        Debug.Log("Read OK");
    }else{
        //終了合図
        t_x.text = "正解数は、" + RN;
    }

}

// Update is called once per frame
void Update()
{
    seikaisuu.text = RN + "/12";
}

}


その後、これを実行して、文字を入力し、Enterを押しても、何も起こりません。
説明1.png
どうすればよいでしょうか。お願いいたします。
※ちなみに、
    if(Input.GetKey(KeyCode.return)){
        プログラム
    }
という条件をつけ足しても、ダメでした。

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

UnityでParticleSystemをInstantiateしてStartRotationを設定する話

UnityでParticleSystemのSizeを軸ごとに変えてその向きをスクリプトから変えたかった。
その時に引っかかった所のメモ。

Prefab化したParticleSystemのGameObjectをRotateしても変わらない

        Instantiate(p, Vector3.up , transform.rotation).Play();

とか、

        ParticleSystem pa = Instantiate(p, Vector3.up , Quaternion.identity);
        pa.transform.Rotate(transform.eularAngles.z);

みたいなのはエディタから見ると回転しているように見えますが、Size over LifetimeのX, Yには影響がありません。
ParticleSystemのstartRotationを変えます。

直接startRotationを設定する方法はObsolete

        pa.startColor = c.color;
        pa.startRotation = transform.eulerAngles.z;

ではなく、一度mainを持ってから設定します。

        var ma = pa.main;
        ma.startColor = c.color;
        ma.startRotation = transform.eulerAngles.z;

ma.startRotationへの書き込みはラジアン

        ma.startRotation = transform.eulerAngles.z;
        Debug.Log(transform.eulerAngles.z + " : " + pa.startRotation);

これで見ると一見一致しているように見えますが、InspectorでstartRotationを見ると5桁になります。

        ma.startRotation = transform.eularAngles.z / 180f * Mathf.PI;
        ma.startRotation = transform.eulerAngles.z / 57.29578f;

transform.eularAnglesの回転方向と逆

反転します。

        ma.startRotation = -transform.eulerAngles.z / 57.29578f;

結局

        ParticleSystem pa = Instantiate(p, transform.rotation * Vector3.up * rat , Quaternion.identity);
        var ma = pa.main;
        ma.startColor = c.color;
        ma.startRotation = -transform.eulerAngles.z / 57.29578f;
        pa.Play();

Unityバージョン

2019.2.17f1
2020.1.0a18

参考にした記事

https://qiita.com/lucifuges/items/e08388a77748168b3b78
https://qiita.com/UnagiHuman/items/caaa1585f7ee201dca7b

公式リファレンス

https://docs.unity3d.com/ja/2017.4/ScriptReference/ParticleSystem.html
https://docs.unity3d.com/ja/2017.4/ScriptReference/ParticleSystem.MainModule.html
https://docs.unity3d.com/ScriptReference/ParticleSystem.MainModule-startRotation.html

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

【Unity】ToggleGroup内のToggleを取得するには?

はじめに

Unityでラジオボタンを作るときに活躍するToggleGroup
複数のToggleをグルーピングして、選択Toggleを択一(排他)にする機能を提供してくれます。

ところがこのToggleGroup、少し曲者です。
というのも、管理しているすべてのToggleを知る手段を提供していないのです。1

これは特に問題にならないことも多いですが、例えば、ToggleGroupから選択肢一覧を知りたいときなどに困ります。(結局自分で別管理することになったり…。)
今回はそんなときにどうするのがよいか、考えてみます。

主に2つの方法が考えられます。

1. Toggle側からアプローチする

Toggleはgroupという自身が所属するToggleGroupを表すプロパティをもっています。
それならば、シーンにあるToggleを集めてそのgroupを調べればいい…。例として下記のようなコードで実現できます。

// using System.Linq;が必要

    /// <summary>
    /// ToggleGroupに所属するToggleを取得
    /// </summary>
    /// <param name="toggleGroup"></param>
    /// <returns></returns>
    private IEnumerable<Toggle> GetTogglesOf(ToggleGroup toggleGroup)
    {
        var toggles = GameObject.FindObjectsOfType<Toggle>();
        return toggles.Where(x => x.group == toggleGroup);
    }

この取り方はToggleGroupからのアプローチでない故の分かりにくさが欠点かもしれません。
あとは検索コストがかかるため少し無駄を感じます。

2. リフレクションで取り出す

無理やり何とかしたいときの常套、リフレクションです。
実はuGUIのソースコードはBitbucketで公開されているため、内部でどうToggleをもっているかを知ることができます。
該当のソースコードを見てみるとList<Toggle>型のm_Togglesという名前でprivateフィールドでもっていることが分かりました。

フィールド名が分かってしまえば、下記のような拡張メソッドを作ることでいけます。2

ToggleGroupExtensions.cs
using System.Collections.Generic;
using System.Reflection;
using UnityEngine.UI;

/// <summary>
/// トグルグループ拡張
/// </summary>
public static class ToggleGroupExtensions
{
    /// <summary>
    /// ToggleGroupがもつToggleのFieldInfo
    /// </summary>
    private static FieldInfo _togglesFieldInfo = null;


    static ToggleGroupExtensions()
    {
        _togglesFieldInfo = typeof(ToggleGroup).GetField("m_Toggles", BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic);

        if (_togglesFieldInfo == null)
        {
            throw new System.Exception("Not compatible with the current version of ToggleGroup.");
        }
    }

    /// <summary>
    /// トグル一覧を取得
    /// </summary>
    /// <param name="self"></param>
    /// <returns></returns>
    public static IEnumerable<Toggle> GetToggles(this ToggleGroup self)
    {
        return (_togglesFieldInfo.GetValue(self) as List<Toggle>);
    }
}

使うときはこんな感じになります。

    foreach (var item in _toggleGroup.GetToggles())
    {
        Debug.Log(item.name);
    }

なお、注意点として、リフレクションの性質上ToggleGroupの内部実装が変わると互換性を失う可能性があります。

おわりに

今回紹介した方法はどちらも素直なやり方という感じはしませんね。
どうせ機能拡張などを見越しているなら、自分でToggleGroupに代わる実装するのがベストなのかもしれません。(中身見れるので参考にもできますしね…。)


  1. もちろん選択されているToggleは取得できます(ActiveToggles)。でもなんで戻り値が単一じゃなくコレクションなんだろう…? 

  2. 本当はToggleGroup.togglesのようにプロパティで書きたいところですが、現時点(C#7.3)には拡張プロパティはないらしいです。 

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

Unity開発用マシンを調達した話

はじめに

2019年の暮れ、思い切ってUnity開発用マシンを調達することにした。
これに至るまでに色々と調べたことをナレッジとして残す。

スペック選定がどのくらいの負荷に耐えられるのか算出しづらかったので
今後のために残した感じ。

最終的に購入したPC

マウスコンピュータ DAIV 5N(カスタマイズ)

金額

約22万円。

他に購入候補にしたPC

  • Dell ALIANWARE
  • MSI
  • ASUS

スペック

端末サイズ 15.6型
OS Windows 10 Pro
CPU Intel Core i7-9750H 2.60GHz
RAM 16GB (C4-19200/DDR4-2400)
CD/DVD-ROMドライブ なし
カードリーダ UHS-Ⅱ対応(SD/SDHC/SDXC/MMC)
Storage 1TB(NVM Express SSD - M.2.PCI Express)
Graphics NIDIA GeForce RTX2060 (6Gb)
スピーカー カスタマイズ(追加)なし
LAN 1000Base-T
無線LAN wifi6対応
画面解像度 フルHD(1920 x 1080)
Officeソフトウェア なし

ストレージ選定について

CPUの処理能力が向上したからなのか、ソフトウェアRAIDを採用しているPCが多かった。
この辺は好みになるかもしれないが、ディスク制御負荷をCPU負荷に加算したくなかった為、ソフトウェアRAIDタイプのモデルを採用しているメーカーは選定しなかった。また、M2 SSDならアクセス速度もそれなりに早いといううわさがあるのでソフトウェアRADは不要と判断。

ソフトウェアRAID

RAIDコントローラ(デバイス)を用いず、OSやアプリケーションでRAID制御するものを指す。専用のドライバーを使ってRAID制御しているものはハードウェアRAIDという。一般向けPCにハードウェアRAIDを採用したものは存在しない。

選定理由

スペック選定に至った理由をつらつらと書いてみる。

画面サイズ選定について

当面は4K描画が必要な開発をするつもりがない為、フルHDタイプを選択。

端末サイズ選定について

デモンストレーションマシンとして持ち運びたいため、15.6型を選択。
17型も検討したがデカい/重いを懸念し、お見送り。

グラフィックボード選定について

下記要件から1070Ti相当のスペックを提供するモデルとしてRTX2060を選定。

  • 2Dゲーム描画が快適に行える
  • 画面描画はFullHD ~ WQHDに適している

CPU選定について

1920 x 1080 をイメージしていた為、CPUはそんなに描画負荷のかからないものを選定。

メモリ選定について

8GBでもよかったんじゃないかなーと思っているが、開発環境として使う為、16GBを選定。

Officeソフトウェアについて

半分眠っているような状態のライセンスがあるため、今回は購入せず。

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

Unityでのメモリ管理

UnityとGC

Tech Academyのメンターさんからメモリ管理を気にして実装できたら中堅という風に言われた(やりたい処理を実装できるのは当たり前で)。
C#では基本的にガベージコレクション(GC)というやつがいらなくなったメモリをいい感じに解放しているらしい。
しかし、Unityでシーン再生中にGCが発生すると数フレーム飛ぶため、アクションゲームではシーン再生中にGCを発生させないようにしないといけないらしい。

GCを発生させる条件とアクションゲームのリアルタイム性を損なわない対策

上のリンク先の記事によると、主なGC発生条件は「メモリが許容されるしきい値を超える場合」であり、これを防げばよいみたい。
で、極論対策としてはそのシーンを開始時にすべてのメモリ領域の確保を終わらせることみたい。
いや、無理じゃね。

実用に耐えうる手段また調べよう・・・

メモリ利用状況の確認

メンターさんに聞いた話しだととりあえずProfilerというやつでやるらしい。
ただ、具体的にどの部分でめっちゃメモリ食ってるとかはわかんないので、
Profilerで確認しながら実装していかないとまずいらしい。
一通り実装し終わったからさぁメモリの負荷みますか、だと詰むらしい。
メモリの限界値としては、経験上システムメモリの半分くらいに押さえておいた方がよいらしい。iPhoneだと800MBくらいが目安か、というところ。

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

Unityで特定の日時にローカル通知する

はじめに

Unity Mobile Notifications Package
こちらのiOS/Androidでプッシュ通知を実装できるパッケージを使ってiOSのプッシュ通知を行います。
IMG_4691.jpg

インストール

『Package Manager』から『Mobile Notifications』をインストールします。
スクリーンショット 2020-01-11 23.31.25.png

使い方

今回は2020年1月1日20時20分に通知を送る設定にしてます。
特定の日時に送る場合は『iOSNotificationCalendarTrigger』を参照します。

PushTest.cs
using System.Collections;
using System.Collections.Generic;
using Unity.Notifications.iOS;
using UnityEngine;
using System;

public class PushScript : MonoBehaviour
{

    // Start is called before the first frame update
    void Start()
    {

    }

    IEnumerator RequestAuthorization()
    {
        using (var req = new AuthorizationRequest(AuthorizationOption.Alert | AuthorizationOption.Badge, true))
        {
            while (!req.IsFinished)
            {
                yield return null;
            }

            string res = "\n RequestAuthorization: \n";
            res += "\n finished: " + req.IsFinished;
            res += "\n granted :  " + req.Granted;
            res += "\n error:  " + req.Error;
            res += "\n deviceToken:  " + req.DeviceToken;
            Debug.Log(res);
        }

    }

    // ボタンが押された際に呼び出される関数
    public void OnClickBtn()
    {
        var calendarTrigger = new iOSNotificationCalendarTrigger()
        {
            Year = 2020,
            Month = 1,
            Day = 1,
            Hour = 20,
            Minute = 20,
            Repeats = false
        };

        var notification = new iOSNotification()
        {
            // You can optionally specify a custom identifier which can later be 
            // used to cancel the notification, if you don't set one, a unique 
            // string will be generated automatically.
            Identifier = "_notification_01",
            Title = "Title",
            Body = "Scheduled at: 2020年1月1日20時20分",
            Subtitle = "This is a subtitle, something, something important...",
            ShowInForeground = true,
            ForegroundPresentationOption = (PresentationOption.Alert | PresentationOption.Sound),
            CategoryIdentifier = "category_a",
            ThreadIdentifier = "thread1",
            Trigger = calendarTrigger,
        };

        iOSNotificationCenter.ScheduleNotification(notification);
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C++とC#のクラスの扱い方の違い

過去に実務でC++を触っていたときにクラスをnewでインスタンス化→要らなくなったらdeleteで削除というのを徹底していた。
で、最近Unity学習で触っているC#ではそういえばdeleteなんて書いたことねぇ・・・とふと思った。
※調べてみると、C#でのクラスインスタンスはclassの変数にnullをセットすると
C#のガベージコレクションという機能がもう使われてないと判断して削除してくれるらしい。

C++、C#のクラスにおけるインスタンス化、利用、削除の流れを書いたコードは以下。
やっぱり色々なんか使い方違う・・・

C++でのクラスインスタンス〜削除のイメージ
// クラスをインスタンス化し、クラスのポインタ型変数にインスタンスのポインタを格納
ClassA* classA = new ClassA();

// int型のmember_aをコンソールへ出力
printf("%d¥n", classA->member_a);

// インスタンスを削除
delete classA;
C#でのクラスインスタンス化→削除のイメージ
// クラスをインスタンス化し、クラスの変数(あれ、ポインタじゃない?)に格納
ClassA classA = new ClassA();

// int型のmember_aをUnityのコンソールへ出力
Debug.Log(classA.member_a);

// インスタンスを削除
classA = null;

一番の違和感は、C++ではクラスをnewするとそのインスタンスのポインタが返ってきて、それをクラスのポインタ型変数に代入して、アロー演算子とかいうやつでアクセスする、という形なのに、C#ではポインタとか使った記憶がない。ちょっとまって。C#ではnewしたときに何が返ってくるの・・・?

そもそもC#ではポインタを使うことが非推奨であるらしい(重大なバグにつながるかららしい。のっぴきならない事情があれば無理やり使うこともできるみたいだが)。・・・ということはそもそもnewしてもポインタなんかかえってきてるわけなさそう。

じゃあなにが返ってくるのか。それは・・・newした対象のデータ型によるらしく。C#の世界では、データの型に応じて、値型もしくは参照型に区分され、扱われるらしい。それはそのデータ型の変数を宣言したときも同等。

newしたときに値型で返ってくる newしたときに参照型で返ってくる
- 構造体
- 列挙型
- string
- object
- 配列
- クラス
- インターフェース
- デリゲート

クラスは参照型という扱いになるんですね。

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