Editor拡張ではSerializedPropertyを使おう。
UnityのEditor拡張は便利だが、よく紹介されているEditorGUILayout.FloatValue()などの直接値を返すものを使用すると、Prefabモードでは値が反映されない。 その場合は、SerializedProperty経由のEditorGUILayout.PropertyFieldを使うと、Prefabモードでも正しく値が反映される。
以下のようなEditor拡張はサンプルとしてもよく見ると思う。
using UnityEngine; using UnityEditor; public class EditorSample1 : MonoBehaviour { public float a; public GameObject b; #if UNITY_EDITOR [CustomEditor(typeof(EditorSample1))] class InternalEditor : Editor { EditorSample1 _self; private void OnEnable() { _self = target as EditorSample1; } public override void OnInspectorGUI() { _self.a = EditorGUILayout.FloatField(_self.a); _self.b = EditorGUILayout.ObjectField(_self.b, typeof(GameObject), false) as GameObject; } } #endif }
このコンポーネントをアタッチすると、Projectビューから直接選択した場合には問題なく編集することができる。
しかしUnity2018.3から追加されたPrefabモードでは値を変更することができない。
代わりにSerializedObjectからSerializedPropertyを取得して、EditorGUILayout.PropertyField()を使用するように変更する。 (Editorクラスのみ抜粋)
[CustomEditor(typeof(EditorSample1))] class InternalEditor : Editor { EditorSample1 _self; SerializedObject _sObj; private void OnEnable() { _self = target as EditorSample1; _sObj = serializedObject; } public override void OnInspectorGUI() { var propA = _sObj.FindProperty("a"); var propB = _sObj.FindProperty("b"); EditorGUILayout.PropertyField(propA); EditorGUILayout.PropertyField(propB); if(_sObj.hasModifiedProperties) { _sObj.ApplyModifiedProperties(); } } }
これによりPrefabモードでも値を変更することができる。
内積はクランプしたほうがいい
結論
内積を関数の入力にする場合はクランプした方がいい。
理由
正規化済みの内積であっても、計算誤差によっては絶対値が1を超える場合があるのでクランプしたほうが良いです。
// a, bは正規化済みのベクトルとする Vector3 a, b; float dot = Vector3.Dot(a, b); float rad = Mathf.Acos(dot);
Mathf.Acos()は1より大きく、-1より小さい値が入力された場合はNaNを返すので、結果がNaNになる場合があります。
なので、Clampで-1から1の範囲にしたほうが良い。
// a, bは正規化済みのベクトルとする Vector3 a, b; float dot = Mathf.Clamp(Vector3.Dot(a, b), -1f, 1f); float rad = Mathf.Acos(dot);
なんかNaNになるなと思ったら、こんなところで引っかかってましたとさ。
PlayCanvasチートシート Unityと比べてみよう エディタ拡張編 その2
前回の記事で触れてなかったところなどを追加したバージョン
前回の記事
seiroise.hatenablog.com
Unityを使ったことのある人がPlayCanvasに手を出したとき「Unityのアレをやりたいんだけど・・・」という状況が結構あった。
今回はその中でもPlayCanvas版のエディタ拡張的要素であるスクリプト属性についてまとめる。
参考
スクリプト属性についてのリファレンス
Script Attributes | Learn PlayCanvas
注意
PlayCanvasではスクリプトを書いた後にEditorのParseボタンを押さないと更新されないので注意しよう。
また、エディタ上の値をいじったあと、入力を確定させないとLaunch後に反映されないので必ず確定させるよう注意しよう。
目次
数値
Unity
public int hp = 80;
PlayCanvas
ScriptAttribute.attributes.add("hp", { type: "number", default: 80 }); console.log(this.hp); //80
typeオプションに"number"を指定して数値に、defaultオプションでデフォルトの値を決めてる。
ちなみに日本語でもいける。でもソースコード中に文字列以外で日本語があると精神上よろしくない。
なのでtitleオプションで変更する方が心臓に負担がかからないかも。(あとタブがずれる)
ScriptAttribute.attributes.add("お金", { type: "number", default: 100 }); console.log(this.お金); //100
titleオプションを使ったバージョン
ScriptAttribute.attributes.add("money", { type: "number", title: "お金", default: 100 }); console.log(this.money); //100
単位の表示
Unityだとエディタ拡張しないとできないので割愛
PlayCanvas
NumberAttribute.attributes.add("weight", { type: "number", placeholder: "kg", default: 60 }); console.log(this.weight); //150(kgは出力されない)
(薄い
スライダー
Unity
[Range(10, 200)] public float height = 60;
PlayCanvas
NumberAttribute.attributes.add("height", { type: "number", default: 175.8, min: 100, max: 250 }); console.log(this.height); //175.8
minとmaxの二つのオプションを必ず指定すること。
文字列
Unity
public string id;
PlayCanvas
StringAttribute.attributes.add("id", { type: "string", }); console.log(this.id); //
defaultオプションで初期値の指定もできる
StringAttribute.attributes.add("name", { type: "string", default: "太郎" }); console.log(this.name); //"太郎"
UnityのTextArea属性みたいに複数行入力を可能にするオプションはないみたい
真偽値
Unity
public bool isHeal;
PlayCanvas
BooleanAttribute.attributes.add("isHeal", { type: "boolean" }); console.log(this.isHeal); //false
defaultオプションで初期値の指定もできる
BooleanAttribute.attributes.add("isTrigger", { type: "boolean", default: true }); console.log(this.isTrigger); //true
配列
Unity
public string[] characters;
PlayCanvas
Test.attributes.add("characters", { type: "string", array: true, });
重複は許されない(gifだと"太郎")
列挙
Unity
public enum Value { valueOne = 1, valueTwo = 2, valueThree = 3 } public Value value;
PlayCanvas
Test.attributes.add("value", { type: "number", enum: [ {"valueOne": 1}, {"valueTwo": 2}, {"valueThree": 3} ] });
ベクトル
Vec2
Unity
public Vector2 direction;
PlayCanvas
VectorAttribute.attributes.add("direction", { type: "vec2" }); console.log(this.direction); //[0, 0]
defaultオプションに配列を指定することで初期値の指定もできる。
Vec3とVec4も同様に初期値の指定ができる。
VectorAttribute.attributes.add("direction", { type: "vec2", default: [1, 2] }); console.log(this.direction); //[1, 2]
さらにplaceholderオプションに配列を指定することで要素ごとの単位の表示もできる。
これもVec3とVec4も同様に指定できる。
VectorAttribute.attributes.add("direction", { type: "vec2", default: [1, 2] placeholder: ["cm", "cm"] });
Vec3
Unity
public Vector3 position;
PlayCanvas
VectorAttribute.attributes.add("position", { type: "vec3" }); console.log(this.position); //[0, 0, 0]
Vec4
Unity
public Vector4 rotation;
PlayCanvas
VectorAttribute.attributes.add("rotation", { type: "vec4" }); console.log(this.rotation); //[0, 0, 0, 0]
色
rgb
たしかUnityだとエディタ拡張しないとできないので割愛。(できたっけ?)
PlayCanvas
ColorAttribute.attributes.add("backgroundColor", { type: "rgb" }); console.log(this.backgroundColor); //[1, 1, 1]
defaultオプションに配列を指定することで初期値の指定もできる。
このとき有効なのは0~1のみで0~255でも"#FF5588"などもだめ。
rgbaも同様に指定できる。
ColorAttribute.attributes.add("mainColor", { type: "rgb", default: [0.2, 0.5, 1] }); console.log(this.mainColor); //[0.2, 0.5, 1]
rgba
Unity
public Color vertexColor;
PlayCanvas
ColorAttribute.attributes.add("vertexColor", { type: "rgba", });
曲線
Curve
Unity
おそらく一番近いのはAnimationCurve
public AnimationCurve wave;
PlayCanvas
CurveAttribute.attributes.add("wave", { type: "curve" });
CurveSet
多分Unityにはない?かな
curvesオプションに値を指定することでCurveSetになる。
CurveAttribute.attributes.add("xyzCurve", { type: "curve", curves: ["x", "y", "z"] });
GradientCurve
Unity
public Gradient gradient;
PlayCanvas
CurveAttribute.attributes.add("gradient", { type: "curve", color: "rgba" });
colorオプションに"r"などを指定することでその色だけの曲線を設定することもできる
ツールチップ
Unity
[Tooltip("握力")] public int grip;
PlayCanvas
NumberAttribute.attributes.add("grip", { type: "number", description: "握力", default: 30 });
PlayCanvasチートシート Unityと比べてみよう エディタ拡張編 その1
PlayCanvasのエディタ拡張的な要素である「スクリプト属性」について
あんまり日本語の解説がなかったのでUnityと比較してまとめてみる。
参考
色
Unity
public Color color;
PlayCanvas
Attribute.attributes.add("color", { type: "rgba" });
こんな感じになる
スライダー
Unity
[Range(100f, 250f)] public float height = 175.8f;
PlayCanvas
Test.attributes.add("height", { type: "number", placeholder: "cm", default: 175.8, min: 100, max: 250 });
こんな感じになる
配列
Unity
public string[] characters;
PlayCanvas
Test.attributes.add("characters", { type: "string", array: true, });
こんな感じになる
ちなみに重複は許されない(gifだと"太郎"のところ)
列挙
Unity
public enum Value { valueOne = 1, valueTwo = 2, valueThree = 3 } public Value value;
PlayCanvas
Test.attributes.add("value", { type: "number", enum: [ {"valueOne": 1}, {"valueTwo": 2}, {"valueThree": 3} ] });
こんな感じになる
曲線
Unity
public AnimationCurve wave;
PlayCanvas
Attribute.attributes.add("wave", { type: "curve" });
こんな感じになる
備考
Unityにはない使い方ができるものもあるので、 それはまた今度
【Unity】かっちょいいUIを作る!解説編【UI】
今朝に引き続きUIのお話です。
前回はこちら
seiroise.hatenablog.com
今回は前回紹介したこいつ↓について解説します。(主に忘れっぽい自分へ)
ソースコード
まず初めに全体のソースコードへのリンクをはっておきます。
説明なんていらん!という人はこっちを見てください。
github.com
円の描画
Unityで円を描画させるにはいくつかあるんですが、 今回は円形のMeshを作って描画するようにしました。 ソースコードでいうと
円の形状の定義
UniCoLib/CircleFragment.cs at master · seiroise/UniCoLib · GitHubUIとしての円の描画
UniCoLib/UICircleFragment.cs at master · seiroise/UniCoLib · GitHub
といった役割になっています。
円の形状定義と描画部分を分けてモジュールっぽさを上げてます。
描画するための形状のデータはEasyMeshとかいう、簡易的な頂点などの集合を介して行うようにしています。
メインの部分は円の形状を定義しているCircleFragment.csですかね。こいつに何度(start)から何度(end)まで、内径(inner)と外径(outer)といった円の形状を指定して、あとはSetIndicate()でどんな表示の仕方をするかを決めてCircleFragment.Update()を呼ぶことで形状をいじくってます。
コライダーへのポインタイベントの送信
今回の方法では既存のEventSystemは使えないので、こちらで都合の良いものを用意します。
イベントの送信
UniCoLib/CollisionEventSystem.cs at master · seiroise/UniCoLib · GitHubイベント受け取り用インタフェース
UniCoLib/ICollisionEventHandler.cs at master · seiroise/UniCoLib · GitHub
ほぼほぼいうことはないと思いますがCollisionEventSystemはマウスの位置からRaycastを行って当たったものに対してICollisionEventHandlerが確認できたらそいつにイベントを送るといった感じです。
Radial Menu の制御
最後にRadialMenuの管理ですがその名の通りRadialMenu.cs君が全て行っています。
UniCoLib/RadialMenu.cs at master · seiroise/UniCoLib · GitHub
表示命令がきたらそのオブジェクトの子のUICircleFragmentを探しそれらに対して位置や範囲を指定して表示するようにしています。
親子関係はTreeではなくStackで擬似的に管理しています。
今回のRadialMenuでは別の子が同時に二つ以上表示されることがないのでStackでおけっていうことですね。
こいつの問題点
今更ですが、ここでこのRadialMenuの問題点を言っておこうと思います。
なんとなく察しているとは思いますが。こいつはワールド空間に配置されているので一緒にテキストを表示するのがちとめんどくさいです。
こいつに関しては今の所良い方法が思い浮かばないので保留です。
何か良い方法があったらコメントください・・・
おわり
かなり端折りましたが解説はこんな感じです。
ここわからんという方はコメント欄とかでよろしくです。
そんでは次の記事では使い方を説明していきたいと思います。
明日の朝には書けると良いなぁ・・・
ではではー
余談
すーぱー被ってるAssetを発見。
事前調査してなかった・・・
assetsale.hateblo.jp
【Unity】かっちょいいUIを作った!みんなの憧れRadial Menu【UI】
お久しぶりです。せいろです。
近況報告みたいな感じです。
ゲームを作りたい欲求を我慢していたらなぜかUIを作ってしまいました。
だってこういうUIかっこいいじゃん・・・
とりあえず作ったものの見た目はこんな感じです。
親子関係を持ったRadial Menuを作ることができます。(見たまんま)
あとはボタンっぽい挙動のカスタマイズだったり、
表示方法とか結構いじくれます。
表示方法その1 内側から外側
その2 端から端
その3 外から中
とりあえずこんな感じです。
UGUIを使うと当たり判定が矩形でしか行えないのでワールド座標に置いたメッシュをそれっぽく扱っています。
実際の詳しいことは次回で解説する予定です。今回は紹介のみです。
今日の夜ぐらいには書けたら良いなぁ・・・
ではっでは。
【Unity】ビルド後に使えるお手軽パラメータ調節機能【OnGUI】
最近,Unityのフロントのアルバイトをしているのですが,
ゲームデザイナの方がテスト用にビルドしたアプリのパラメータを調節したいとのことだったので,ビルド後もお手軽にパラメータを調節出来る何かを作りました。
お手軽にということで,C#のインタフェースとUnityのOnGUIを使って実装します。
OnGUIは小回りが利くのでお手軽にやるときには結構使える子だったりします。
今回は直線移動するプログラム(Move.cs)を調節できるようにします.
インタフェース(IParameterIndicator.cs)はこんな感じです.
このインタフェースをMove.csにインプリメンツして表示用のコードを書くとこんな感じです.
GUILayoutを使ってるのは下の方まで読めば分かるはずです.
そんで重要な関数を読んであげる人です
全てのインタフェースを取得するプログラムはここを参考にしてあります.
http://forum.unity3d.com/threads/how-to-get-all-components-on-an-object-that-implement-an-interface.101028/forum.unity3d.com
そんなこんなでそれぞれをUnity上に配置して実行するとこんな感じです.
メリットとしては
- お手軽
- 表示側からスクリプトへの参照がないのでシンプル
- インタフェースなので後から付け加えるとか出来る
デメリットとしては
- あんまり複雑なのは表示に向いてない
- 表示するものが多すぎると重たい
ってことが挙げられますね.
やってることは単純なんですけどそこそこ便利だったりします.
ではでは~