Unityな日々(Unity Geek)

Unityで可視化アプリを開発するための試行錯誤の覚書

iOSアプリの作成手順

UnityからiOSアプリを書き出す手順についてのメモ。

iOSアプリ開発の前提として、App IDやプロビジョニングファイルといった情報を取得・設定しておく必要がある。これらについては次の記事を参考に。

macdays.hatenablog.com

シミュレータで動かす場合

Unityでの作業

1. アプリ用のシーンを作成。

今回UIとして用いるCanvas

  • RenderMode: Screen Space - Overlay
  • Reference Resolution: 1136 x 640
  • Screen Match Mode: Expand

とし、GameViewのアスペクト比は16:9に設定。

f:id:yasuda0404:20150722092851p:plain

これらはiPhone5sの横モードに対応。

2. Build Settings

iOSを選択。「Player Settings..」をクリック。

f:id:yasuda0404:20150722093313p:plain

PlayerSettings共通

Campany Name Product Name を設定。

Icon画像は別途デバイスごとに設定するが、想定外のデバイスのためにDefault Iconも設定しておくとよい。

f:id:yasuda0404:20150723092137p:plain

Resolution and Presentationタブ
  • Default Orientation: Landscape Left (横長モード)
    f:id:yasuda0404:20150722093617p:plain
Iconタブ

各アイコン画像を登録

Splash Imageタブ

各デバイス用のSplashイメージを登録。各デバイスの画面解像度は、iOS - iPhone/iPad解像度(画面サイズ)早見表 - Qiita などを参考に。

Other Settingsタブ

f:id:yasuda0404:20150722100007p:plain

3. ビルド

Build Settings...ウィンドウでビルドする(現在のシーンを登録するのを忘れないよう)。
Xcodeのプロジェクトファイルができる。
f:id:yasuda0404:20150722100614p:plain

Xcodeでの作業

上で作ったxcodeprojファイルをクリックしてXCodeを起動。

シミュレータでの確認

  • トップメニューの再生・停止ボタンの右横にあるシミュレータ選択プルダウンで、適当なデバイスを選ぶ。
    f:id:yasuda0404:20150722101056p:plain

  • 再生ボタンをおしてシミュレータを起動。 iOSの画面が表示される。 f:id:yasuda0404:20150722101325p:plain

※シミュレータ起動時、デバッグプロセスの制御の確認画面が出た場合は、マシンのパスワードを入力し続行する。 f:id:yasuda0404:20150722101258p:plain

  • 必要に応じてデバイスを変更し、シミュレータでの確認をおこなう。

デバイスの変更はiOSシミュレータのトップメニュー、Hardware-Device-... でも行える。
f:id:yasuda0404:20150722102346p:plain

実機デバイスで動かす場合

Unityでの作業

UnityのPlayer Settings...のiOSタブで、SDK Versionを'DeviceSDK'にしてビルドする。   f:id:yasuda0404:20150722111932p:plain

Xcodeでの作業

Provisioning Fileの設定

ビルドしたxcodeprojを開く。トップバーに’iOS Device'と表示されているはず。
f:id:yasuda0404:20150722112309p:plain

サイドメニューで該当するプロジェクトを選択し、Build Settingsタブをクリック。スクロールして'Code Signing'をみつける。この項目の、

  • Code Signing Identity を iOS Developerにする
  • Provisioning Profile を Automaticにする

f:id:yasuda0404:20150722114122p:plain

実機デバイスの起動

iPhone/iPadをUSBでつなぐと、デバイス名が表示される。
f:id:yasuda0404:20150722112624p:plain

初めてのデバイスの場合は、Symbol Filesをデバイスにコピーするためしばらく時間がかかる。

終了後、XCodeの再生ボタンを押すとiOSデバイス上でアプリが起動する。

参考:

iOS開発ガイド-アプリケーションのビルドと実行

techacademy.jp

Unity5.1でOculus Riftを使う

Unity4.6でOculusRiftを使う場合は、ライブラリをインポートする必要があった。(ライブラリは4.6.3以降で利用可能)Oculus Riftの導入(DK2) - Unityな日々(Unity Geek)

Unity5.1以降では、OculusなどのVRデバイスの標準で対応している。

UnityとOculusを接続する手順は次のとおり。、

1) OculusRiftのRunTimeをインストールする。Unity5との接続には、V0.6.0.1以降が必要なようだ。 f:id:yasuda0404:20150717164030p:plain

f:id:yasuda0404:20150717163658p:plain

f:id:yasuda0404:20150717163648p:plain

2) Edut-Project Settings-Player で、'Virtual Reality Supported'をオンにする。最初、オブジェクトをリインポートする旨のメッセージがでる。

f:id:yasuda0404:20150717163719p:plain

以上で、Editorでも実行ファイルでもシーンのメインカメラの位置にOculusのカメラが自動的に設定される。(RiftのDirectModeを使っているため、PC上にはシングル画面が表示される)

メインカメラは、

1) 'MainCamera'のタグがついているもの

2) 同タグがない場合、または複数ある場合は、カメラDepthのもっとも大きなもの

の順で決定される。

Unity5でCharacterControllerを使う

方法1:CharacterControllerクラス(コンポーネント)を使う

キャラクターとして動かすGameObjectを作る f:id:yasuda0404:20150716145603p:plain

MainCameraを同GameObjectの子にする

f:id:yasuda0404:20150716150038p:plain

同GameObjectに、Physics-CharacterControllerをアタッチする

f:id:yasuda0404:20150716150230p:plain

キャラクター移動のUIクラスを作る。参考:Unity-API:CharacterController.Move()

これを同GameObjectにアタッチする。

方法2:標準アセットを使う

Assets-ImportPackages...-Characters を読み込む

f:id:yasuda0404:20150716155900p:plain

Assets-StandardAssets-Characters-FirstPersonCharacter-Prefabsの下の、

-FPSController -RigidBodyFPSController 

のどちらかをシーンに加える

FPSControllerには歩行をシミュレートする「ゆれ」とサウンドがついている。「ゆれ」をなくすには、Use Head Bobをオフにする

歩行時と走行時にカメラのFOVを変えるには、Use FOV Kickをオンにし、各パラメータを調整する

f:id:yasuda0404:20150716162227p:plain

覚えておくと便利な小技(Tips)

Unityの「ビギナーTips」の中に、結構便利そうなもの(で、知らなかったもの)があったのでメモ。

Snap

Ctrl(Macはコマンド)キーを押しながら、移動、拡大・縮小、回転をおこなうと、一定の増分ごとに「スナップ」されて移動、拡大・縮小、回転を行える。

各増分は、

Edit-Snap Settings...

で指定する。

f:id:yasuda0404:20150710183415p:plain

プレビューウィンドウの拡大

モデルなどのアセットを選択すると、インスペクターの下のほうにあるプレビューウィンドウで中身を見ることができる。が、エリアが小さいのでわかりにくい。

プレビューウィンドウを別ウィンドウとして拡大するには、インスペクターのプレビューエアリアの上枠部分を右クリックする。

f:id:yasuda0404:20150710184028p:plain

プレビューウィンドウが別ウィンドウで開かれ、任意のサイズに拡大縮小できる。閉じるときは右上の「×」をクリックする。

f:id:yasuda0404:20150710184036p:plain

フォーラムからAPIリファレンスへのリンク

forum.unity3d.comのサンプルスクリプトの一部は、APIリファレンスへのリンクが貼られている。たとえば次のようなスクリプトの、水色文字、赤文字の一部(すべてではないようだ)をクリックするだけで、該当するAPIリファレンスを開くことができる。

f:id:yasuda0404:20150710184707p:plain

カメラの位置・角度の調整

1) シーンビューの画面に、カメラの画角をあわせたい場合:

カメラを選択し、GameObject-Align with View を選択。(ゲームビューで確認できる)

f:id:yasuda0404:20150710185630p:plain

2) カメラの画角に、シーンビューの画面を合わせたい場合:

カメラを選択し、GameObject-Aligh View with Selected を選択。 シーンビューの画面が、選択したカメラと同一になる。

プレイモード・ティント

エディターでプレイモードを選択していることを忘れてしまうことがある。プレイモードで行った変更は停止すると元に戻るので、無駄な作業になってしまう。

プレイモードにあることを視覚的に明瞭にするために、'Play Mode Tint'というしかけがある。

Edit-Preferences... で Colors'を選択。

'Play mode tint'で任意の色を設定する。

f:id:yasuda0404:20150710190506p:plain

プレイモードではウィンドウの色が変わるので、よほど鈍感でなければプレイモードであることを忘れないだろう。

f:id:yasuda0404:20150710190606p:plain

インスペクタでスライダーを使う

スライダで値を設定するには、スクリプトのPublic Variableの定義の前に、

[Range(min, max)]

とかけばいい。たとえば、

[Range(0,1)] public float a;

とすれば、インスペクタ上に0-1の範囲のスライダが表示される。

f:id:yasuda0404:20150710191503p:plain

インスペクタの入力に数式を使う

インスペクタの入力エリアに、数式を打ち込んでもいい。たとえば、'3*5'と入力すると、15に変換される。

f:id:yasuda0404:20150710191815p:plain

Empty GameObjectをアイコン表示する

UnityシーンではEmpty GameObjectを使うことが多いが、シーンビュー上では透明のため、フォーカスが外れるとどこにあるかわからなくなる。

GameObjectにアイコン(ギズモ)を設定するには、インスペクタの左上にある「カラーキューブ」をクリック。

f:id:yasuda0404:20150710192231p:plain

さまざまなカラーのタグや小さな丸を選ぶことができる。

f:id:yasuda0404:20150710192552p:plain

Playモード中の変更を適用する

通常、Playモードで行った変更はPlayモードを終了すると、元の状態にリセットされる。

Playモード中の変更を適用するには、該当するコンポーネントの歯車アイコンをクリックし、'Copy Component'を選択する。

f:id:yasuda0404:20150710193108p:plain

Playモードを停止した後(変更した値はリセットされる)、該当コンポーネントで 'Paste Component Values'を選択すると、Playモード中の変更が適用される。

f:id:yasuda0404:20150710193220p:plain

複数コンポーネントに対する変更をPlayモード終了後に適用するには、Playモード中に、'Edit-Copy'

f:id:yasuda0404:20150710193425p:plain

Playモード終了後、該当オブジェクトをシーンから削除し、'Edit-Paste'.

インスペクタの値ごとペーストされる。

#

Asset Storeのダウンロードフォルダを変更する

AssetStoreからたくさんのアセットをダウンロードすると、いつの間にかCドライブがいっぱいになってしまう。僕の場合、もともとCドライブに空きが少ないので危険な状態になってしまっていた。

f:id:yasuda0404:20150605160010p:plain

Asset Storeで購入したアセットの保存先を変更しようと思ったのだが、Unityの設定ではできないようだ。

Unity Feedback - Ability to change the download directory of the Asset Storeを参考に、シンボリック・リンクを貼ることで対応した。

その手順は次のとおり。

  1. 既存のアセット保存フォルダをコピーする。 Asset Storeで購入したアセットはデフォルト状態では、 C:\Users\ユーザー名\AppData\Roaming\Unity の下にある、 Asset Store-5.x (Unity5でダウンロードしたアセット) Asset Store (Unity4.x以前でダウンロードしたアセット) に保存されている。 これらのフォルダを、新しい保存先にコピーする。

  2. コピー後、C:\Users\ユーザー名\AppData\Roaming\Unityの下の2つのアセットフォルダを削除。

  3. デフォルト保存フォルダから新規保存フォルダへシンボリックリンクを貼る。  コマンドプロンプトを開いて、次のようにタイプする。

mklink /j "C:\Users\YourUsername\AppData\Roaming\Unity\Asset Store" "X:\WhateverLocationYouWant1"
mklink /j "C:\Users\YourUsername\AppData\Roaming\Unity\Asset Store-5.x" "X:\WhateverLocationYouWant2"

X:\WhateverLocationYouWant1/2は新しい保存先フォルダ。

以上で、AssetStoreからダウンロードしたアセットは、新規保存先へ保存される。

Oculus Riftの導入(DK2)

Oculus Riftは初代DK1から使っているが、DK2も出てSDKもどんどんアップデートされている。ので、このあたりでUnity導入時の覚書を残しておくことにした。


OculusのDeveloperページ。"Oculus PC SDK"をクリック(この次元では、0.5.0.1 betaが最新だった)。

f:id:yasuda0404:20150510165427p:plain

Oculus Runtime for Windowsをダウンロード f:id:yasuda0404:20150510165449p:plain

SDKのLicense Agreementのページが表示されるので…

f:id:yasuda0404:20150510165507p:plain

チェックボックスにチェックし、”DOWNLOAD NOW”を押してファイルをダウンロードする。

f:id:yasuda0404:20150510171405p:plain

インストールの実行ウィンドウが表示されるので、「実行」。

f:id:yasuda0404:20150510182453p:plain

インストールの開始。'Nect>'

f:id:yasuda0404:20150510182533p:plain

ライセンスへの同意。'I accept ...'を選択して、'Next>' f:id:yasuda0404:20150510182542p:plain

インストール先フォルダ。必要なら変更する。

f:id:yasuda0404:20150510182548p:plain

'Next>'を押すとインストールが始まる。

f:id:yasuda0404:20150510182556p:plain

’Oculus Display Driver(Install Only)'という子ウィンドウが開いてしばらくとまるが我慢して待つ!しびれを切らしてCnacelはおさないように!

f:id:yasuda0404:20150510182602p:plain

途中、「このドライバをインストールしますか」という日本語のウィンドウが開くので「インストール」をクリック。(私の場合、この画面が2度出た。手順が間違っていたのか、そういうものなのか不明)

f:id:yasuda0404:20150510182608p:plain

インストールが完了。'Finish' f:id:yasuda0404:20150510182614p:plain

デフォルトでReadMeテキストが表示される。

f:id:yasuda0404:20150510182621p:plain

ドライバを有効にするには再起動が必要。 f:id:yasuda0404:20150510182627p:plain

Unity4.6以降の場合は、Unity 4 Integrationをダウンロードする

f:id:yasuda0404:20150510171226p:plain

【追記】 現在はつぎのようなインターフェースになっている。

f:id:yasuda0404:20150728205305p:plain

Unity5は、V0.1.0-betaをダウンロード。次のような画面になる。なお、以前のものも'Unity Legacy Integration V0.6.0.1-beta'としてダウンロード可能。

f:id:yasuda0404:20150728195442p:plain

ダウンロードしたZIPファイルを解凍すると、中にOculusUnityIntegration.unitypackageというUnityパッケージがあるので...

f:id:yasuda0404:20150510171605p:plain

このパッケージをUnityに読み込む(Unityのバージョンは4.6.3以上が必要)

f:id:yasuda0404:20150510173033p:plain

Player設定 (Edit>Project Settings...>Player)

f:id:yasuda0404:20150510173326p:plain

※Dirext11はオフにする。

f:id:yasuda0404:20150729181629p:plain

Quality設定 (Edit>Project Settings...>Quality)

f:id:yasuda0404:20150510173345p:plain

Unityとのインテグレーションの場合、Extended Modeにする。詳細は、

qiita.com

www.youtube.com

また、Edit-Preferences... の'Oculus VR'タブで、'Optimize Build for Oculus'にチェックを入れる。

f:id:yasuda0404:20150819141755p:plain

Unity Editor上かどうかで処理内容を変える

Unityの開発はUnity Editorで行うが、Editor上と実際の実行プラットフォーム(Windows, Mac, LinuxiOS, Androidなど)とで処理を変えたい場合がある。これには次の2つの方法がある。

1. "Application.platform"を使う方法

実行時にスクリプト内で現在の実行プラットフォームを見て、処理を変える方法。

docs.unity3d.com

プラットフォームのクラス変数は、"RuntimePlatform"に定義されている。

docs.unity3d.com

2. プリプロセッサ"UNITY_EDITOR"を使う方法

コンパイル時に(つまり実行前に)ターゲットとなるプラットフォームを評価して、実行する処理を選択する方法。実行時に動的に評価するのではなく、プラットフォームに応じて実行ファイル自体を変えてしまうもの。

#if UNITY_EDITOR エディターでの処理 #else エディター以外での処理 #endif

のように記述する。

さらに、エディター上でも、実行中か否かで別処理にしたい場合はApplication.isPlayingと組み合わせて、たとえば、

#if UNITY_EDITOR
    nextBlendTime = Application.isPlaying ? blendTime : 0f;
#else
    nextBlendTime = blendTime;
#endif

のように書けばよい。

より細かく、

  • UNITY_EDITOR_WIN :Windowsのエディタ環境
  • UNITY_EDITOR_OSXMac(OS X)のエディタ環境

などの区別も可能。

  

また、

  • UNITY_4_6

など、Unityのバージョンによって処理を変えることもできる。

プリプロセッサで使用できるプラットフォーム種類の変数は次を参照。

docs.unity3d.com

C#からJavascriptのクラスを呼びだせない時

C#からJavascriptのクラスは、通常のC#クラスと同じように呼び出せる。たとえば、

[SerializeField]protected FPSInputControllerREI fpsInputController; //Javascript Class

ところが、これでは「該当クラスがない」というエラーが出る。

Assets/Scripts/REIControllerDangeon.cs(15,43): error CS0246: The type or namespace name `FPSInputControllerREI' could not be found. Are you missing a using directive or an assembly reference?

この原因は、アセットの読み込み順番で、C#スクリプトと実行する際にJavascriptが読み込まれていないことにある。

Javascriptのクラスを先に読み込ませるために、読み込ませたいJSファイルは、

  • Plugins
  • StandardAssets

などのフォルダにいれる。これでエラーはなくなるはず。

角度指定と外部呼出しに関するベンチマーク

Unityでは、角度は、オイラー角とクォータニオンの2つの方法で扱える。また、回転を設定する際、角度の絶対値と、Rotate()で相対角変化を与える方法がある。いったいどれがもっとも効率的、すなわち高速なのだろうか?

また、あるオブジェクトのクラスから他のオブジェクトを操作する際、操作する側のクラスに操作される側のGameObjectなりTransformコンポーネントを保持して操作を加えるのと、操作される側にクラスを作ってそのPublicメソッドを呼び出すのと、どちらが速いのだろう。

そういう疑問がおきたので、ベンチマークしてみた。

比較結果

ベンチマークスクリプトは下に記す。各方法とも10万回ループの経過時間。

No. 処理内容 時間(mSec)
1-1 オイラー角で設定する 130
1-2 Rotate()関数を使って相対的にまわす 146
1-3 クォータニオンで設定する 123
1-11 ターゲット側のPublic関数に角度をを渡す(外部関数の中身は1-1と同等) 129
1-12 ターゲット側のPublic関数に角度ベクトルをを渡す(外部関数の中身は1-1と同等) 130
1-1A 1-1と同じ処理で、毎回transformコンポーネントを探す 139
1-12A 1-12と同じ処理でループの中で毎回同階層にある外部クラス(コンポーネント)を接続する 191
1-12B 1-12と同じ処理でループの中で毎回外部GameObjectを探す 241
結論
  • 角度の指定はEulerでもQuaternionでも、違いはそんなにない。Quaternionのほうが若干(5%程度) 速い程度。
  • 回転の際、角度を直接指定するより、Rotate()を使うほうが10%程度時間がかかる。
  • Public関数の呼び出しはコストがかからない。つまり、外部コンポーネントを自クラスに取り込んで自クラス内で操作しても、外部コンポーネントのPublic関数を呼び出してその中で操作しても、時間に差はない。
  • (やはり)外部コンポーネント・外部クラスの呼び出しは時間がかかる。呼び出しは最初にやって内部変数にリンクを格納しておくのがベター
ベンチマークスクリプト
// Bench Mark for Rotation & Function Call
// First Version 2015/03/14 by A.Y.@XOOMS
// Last Update   2015/mm/dd by A.Y.@XOOMS
//
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Xooms;

namespace Xooms{
    public class BenchMark1 : MonoBehaviour {
        
        //Public Variables
        public Transform targetTrans;

        //Private Variables
        GameObject targetGameObject;
        bool firstTime = true;
        Stopwatch sw = new Stopwatch();
        int maxItr = 100000;
        float delA = 1.0f;
        DummyCube dummyCube;

        //Public Functions

        //--------------
        // Initialization
        void Start () {
            targetGameObject = targetTrans.gameObject;
            dummyCube = targetTrans.GetComponent<DummyCube>();
        }
    
        //
        void Update () {
            if(firstTime) {
                firstTime = false;
                //1.回転関連ベンチマーク
                //1-1 オイラー角で設定する
                sw.Reset();
                sw.Start();
                for(int i = 0; i < maxItr; i++) {
                    Vector3 v = new Vector3(0.0f, i*delA, 0.0f);
                    targetTrans.eulerAngles = v;
                }
                sw.Stop();
                DebugOut("1-1",sw.ElapsedMilliseconds);
                //
                //1-2 Rotate()関数を使って相対的にまわす
                sw.Reset();
                sw.Start();
                for(int i = 0; i < maxItr; i++) {
                    targetTrans.Rotate(i*delA*Vector3.up);
                }
                sw.Stop();
                DebugOut("1-2", sw.ElapsedMilliseconds);
                //
                //1-3 クォータニオンで設定する
                sw.Reset();
                sw.Start();
                for(int i = 0; i < maxItr; i++) {
                    targetTrans.rotation = Quaternion.Euler(0.0f, i*delA, 0.0f);
                }
                sw.Stop();
                DebugOut("1-3", sw.ElapsedMilliseconds);
                //
                //1-1A 1-1と同じ処理で、毎回transformコンポーネントを探す
                sw.Reset();
                sw.Start();
                for(int i = 0; i < maxItr; i++) {
                    Vector3 v = new Vector3(0.0f, i*delA, 0.0f);
                    targetGameObject.transform.eulerAngles = v;
                }
                sw.Stop();
                DebugOut("1-1A",sw.ElapsedMilliseconds);

                //
                //1-11 ターゲット側のPublic関数に角度をを渡す(外部関数の中身は1-1と同等)
                sw.Reset();
                sw.Start();
                for(int i = 0; i < maxItr; i++) {
                    dummyCube.RotateByAngle(i*delA);
                }
                sw.Stop();
                DebugOut("1-11",sw.ElapsedMilliseconds);

                //1-12 ターゲット側のPublic関数に角度ベクトルをを渡す(外部関数の中身は1-1と同等)
                sw.Reset();
                sw.Start();
                for(int i = 0; i < maxItr; i++) {
                    Vector3 v = new Vector3(0.0f, i*delA, 0.0f);
                    dummyCube.RotateByVector(v);
                }
                sw.Stop();
                DebugOut("1-12",sw.ElapsedMilliseconds);

                //1-12A 1-12と同じ処理でループの中で毎回外部クラス(コンポーネント)を探す
                sw.Reset();
                sw.Start();
                for(int i = 0; i < maxItr; i++) {
                    DummyCube target = targetTrans.GetComponent<DummyCube>();
                    Vector3 v = new Vector3(0.0f, i*delA, 0.0f);
                    target.RotateByVector(v);
                }
                sw.Stop();
                DebugOut("1-12A",sw.ElapsedMilliseconds);

                //1-12B 1-12と同じ処理でループの中で毎回外部GameObjectを探す
                sw.Reset();
                sw.Start();
                for(int i = 0; i < maxItr; i++) {
                    GameObject go = GameObject.Find("DummyCube");
                    DummyCube target =go.GetComponent<DummyCube>();
                    Vector3 v = new Vector3(0.0f, i*delA, 0.0f);
                    target.RotateByVector(v);
                }
                sw.Stop();
                DebugOut("1-12B",sw.ElapsedMilliseconds);
            }
        }

        private void DebugOut(string title, float timeMsec){
            UnityEngine.Debug.Log(title+ ": "+timeMsec.ToString("f1")+" msec");
        }
    }
}

uGUIのテキストにブラーがかかってしまう問題

uGUI(Canvas UIシステム)のTextUI要素にブラーがかかってしまう問題は、既知のバグのようだ。

現時点では、対応策はピクセル解像度の大きなテキストを作り、Scaleを小さくして縮小する、という手しかないようだ。

Text UI要素のインスペクタは次のような感じになる。RectTransformのWidth/Hight、FontSizeを大きくし、RectTransformのScaleを0.1とか0.01とかに小さくする。

f:id:yasuda0404:20150312141620p:plain

しかし、この設定でもすこしぼやけた感じがする。早急な対応をお願いします!

uGUI: スクリプトからUIのパラメータを変更する

uGUIへユーザが操作した際にメソッドを呼び出すのとは逆に、スクリプトからUIの状態やパラメータを変更したい場合もある。代表的な例を下にあげる。

テキスト

uGUIのテキストを変更するには、テキストGameObjectのTextコンポーネントを取得し、このText.textプロパティを変更すればよい。

サンプルスクリプトは次。

ポイントは、UnityEngine.UIネームスペースを追加すること!

using UnityEngine;
using UnityEngine.UI;

public class Example : MonoBehaviour
{

 [SerializeField]Text btnText;
  [SerializeField]Toggle toggle;
  [SerializeField]Slider slider;

  private bool isOn = false;
  
  REIPacket packet=new REIPacket();

  public void OnOff()
  {
      isOn = !isOn;
      if(isOn) {
         btnText.text = "On";
         toggle.isOn  = true;
         slider.value = 1.0f;
         slider.Select();
      } else {
         btnText.text = "Off";
         toggle.isOn  = false;
         slider.value = 0.0f;
         toggle.Select();
      }
  }

トグル(チェックボックス)状態

Toggleコンポーネントbool isOnを変更する。

スライダの値

Sliderコンポーネントvalueを変更する。

フォーカス(共通)

各UIコンポーネント.Select()メソッドを呼ぶ。該当UIにフォーカスが移り、その他はフォーカスが外れる。

※注)ゲームコントローラやキーボードからの操作を可能にするよう、EventSystemのFirst Selectedに、最初にハイライトするUI要素を設定しておくこと!

スクリプトのテンプレートを追加する

スクリプトを新規作成する際に、独自のテンプレートを使いたいことがあるとおもう。

その場合は、Unityのインスールフォルダ/Editor/Data/Resources/ScriptTemplates/の下にある、

  • 80-Javascript-NewBehaviourScript.js.txt
  • 81-C# Script-NewBehaviourScript.cs.txt
  • 82-Boo Script-NewBehaviourScript.boo.txt
  • 83-Shader-NewShader.shader.txt
  • 84-Compute Shader-NewComputeShader.compute.txt

を修正するか、あるいは、新規にテンプレートファイルを追加する。

僕の場合、主に使うC#用テンプレートにヘッダコメントとNamespaceをデフォルトで入れたテンプレートを作っている。

// Title
// First Version 2015/mm/dd by A.Y.@XOOMS
// Last Update   2015/mm/dd by A.Y.@XOOMS
//
using UnityEngine;
using System.Collections;
using Xooms;

namespace Xooms{
    public class #SCRIPTNAME# : MonoBehaviour {

        // Initialization
        void Start () {
    
        }
    
        //
        void Update () {
    
        }
    }
}

これを、オリジナルのC#テンプレートに上書きしてもよいが、オリジナルのテンプレートは残したい場合は、別名で保存する。

ファイル名は、'番号+表示名-スクリプト種類.拡張子.txt'となり、'-'ハイフンより前の、番号+表示名は自由に設定できる。番号は数字のほかアルファベットでもいいようだ。要は番号部分のテキストの小さい順番に、メニューに並ぶ。

たとえば81A-C#XOOMS Script-NewXoomsScript.cs.txtという別の名前で保存すると、正規のC#テンプレートの次に、オリジナルテンプレートが表示される。

f:id:yasuda0404:20150309164902p:plain

Materialを比較する

あるオブジェクトにアサインされている特定のマテリアルを別のマテリアルに置き換えたかったので、次のようなコードを書いた。

[SerializeField]protected Renderer rend; //Target Renderer
[SerializeField]protected Material matFrom; //Change from this material
[SerializeField]protected Material matTo;   //Change to this material

<途中省略>

void Change()
{
    Material[] mats = rend.sharedMaterials;
    Debug.Log("ChangeMaterial: mats.Length= "+mats.Length);
    for(int i=0;i<mats.Length;i++) {
        Debug.Log(i+" Spec Int "+mats[i].GetFloat("_SpecInt"));
        if(mats[i] == matFrom) {
            Debug.Log("ChangeMaterial:Material("+i+" changed");
            mats[i]= matTo;     //Replace the material
        }
    }
    rend.materials = mats;  //Reassign Materials
}

ところがこれは機能しない。マテリアルはRunTimeでインスタンス化されるが、インスペクタでアサインしたマテリアルはインスタンスではない。このため、mats[i] == matFromという比較が真にならない。

そこで、マテリアルの名前で比較しようと思い、比較分の箇所を

if((mats[i].name == matFrom.name)...

と書いたが、これもうまくいかない。マテリアルがインスタンス化されると名前も変わるからだ。

結局、

if(mats[i].name == (matFrom.name+" (Instance)")) {

と、元の名前の後に" (Instance)"を加えれば、一応うまくいった。

しかし、もっとスマートな比較方法がないものだろうか…。

"9x9 Slice" Spriteを作成する

UI用のイメージを設定する場合、イメージを拡大しても周囲のラインは画像が荒れるので拡大したくない。これを実現するのが、「9x9スライス」というテクニック。要は、4つの角はスケーリングせず、中間の画像のみ拡大するという手法だ。

これをUnityで実現するには、SpriteとBorderを使う。

まずPhotoshopなどでUI用の画像を作る。シンプルなものなら縦横16pxの正方形にする。PNG形式で書き出す(アルファを使えるPNGがよい)。

f:id:yasuda0404:20150307182000p:plain

Unityで、この画像をアセットして読み込む。

  • Texture Type Sprite(2D and UI)
  • Sprite Mode Single

に設定。

f:id:yasuda0404:20150307182013p:plain

し、Sprite Editorを開き、左下の入力フォームでL/R/B/Tを適当に設定し、9分割のボーダーを引く。Applyで変更を反映。

f:id:yasuda0404:20150307182021p:plain

後は、各UI要素のImageコンポーネントSource Imageに、上で作成したSpriteを適用する。UI要素を拡大しても、エッジラインは保たれる。

f:id:yasuda0404:20150307182601p:plain

CanvasUI(uGUI)要素にアニメーションを設定する

CanvasUI(uGUI)のインタラクティブ要素(Button, Toggle, Sliderなど)は、「操作状態」に応じて「外観」を変更できる。

操作状態

各UI要素の状態には

  • Normal
  • Highlighted
  • Pressed
  • Disabled

の4通りがある。'Highlighted'はフォーカスがあたった状態で、マウスならなくてもよいが、ゲームコントローラで制御する場合は必須。どの要素が選択されているかをフィードバックしなければならないからだ。

外観

外観の変更は各コンポーネントTransitionで行い、

  • none 外観を変えない
  • Color Tine RGBAの変更
  • Sprite Swap 画像の変更
  • Animation アニメーションの付加

の4つの設定がある。

f:id:yasuda0404:20150307155309p:plain

アニメーション

TransitionでAnimationを選択。Animationを使うにはAnimatorコンポーネントが必要。'Auto Generate Animation Controller'をクリックし、AnimationControllerをアセット内に保存する。デフォルトでは、たとえばButton.Controllerのような名前になる。

f:id:yasuda0404:20150307154919p:plain

同時に、AnimatorコンポーネントがUI要素に追加される。

f:id:yasuda0404:20150307160633p:plain

アニメーションはAnimation Window(Window - Animation)で編集する。

f:id:yasuda0404:20150307160901p:plain

Animation Windowの左上、再生ボタンの下をクリックし、編集したいアニメーションを選択する。