NGUI ボタン操作別呼び出されるアクションメモ

NGUI アクション別呼び出される関数

最近NGUIを触り始めたので、メモ代わりにアクション別の呼び出される名前一覧。
間違ってても泣かない。

・マウスアイコンがボタンの上に行く→HoverOver
・上記の状態からボタン領域外に出る→HoverOut
・HoverOver/HoverOutと同じ動作の時、ドラッグして(左クリック押して)いる→DragOver/DragOut
・ボタンを1クリック→Press/Select
・上記の状態からクリックを離す→Release/ClickOrTap
 ※Press/Select状態から「ボタンの領域外に出て」「クリックを離した」場合は「Release」のみ。
・ClickOrTapが動いた後、ボタンの領域外をクリック→Deselect(微妙。Selectは直接は関係ないっぽい?)
・ボタンをダブルクリック→DoubleClickOrTap
 ※トリプルクリック時は2度・四回クリックした時は3度呼び出されるので注意。

アニメーションへの第一歩

Unity-Chanを使用して色々試した結果のメモ。
なお各語は自分用なので正しいものと一致するとは限らない。

・Animator Contollerの設定およびAnimator操作
Projectの中でCreate->Animator Controllerを作成する。
Animator Controllerを選択しAnimator Windowに移ることでアニメーションの状態遷移を作成する。
f:id:DYMN:20140625111205p:plain
Parametersで状態遷移に使用する変数(Float, Int, Bool, Trigger)を作成。スクリプト内と相互にやり取りできるようになる。

各StateとAnimationファイルを結びつけ、State間を矢印で結び遷移条件を付与することでオブジェクトに対するアニメーションを操作する。

新StateはCreate State->Emptyで作成する。From New Blend Treeについては後述。

図中の場合、IdleフラグがTrueになることでIdle状態にいる場合、Rest状態に移ることを意味している。
True下の+/-を使用することで他の条件を追加し、フラグのANDを取ることができる。
新たな矢印を追加することでORを取ることができる。たぶん。

遷移に使用する変数は左下のParameterで追加・削除を行う。+で追加、-で削除。

AnimationControllerをモデルに適用する場合は対象となるオブジェクトにAnimatorコンポーネントを追加し、Inspector上からControllerにAnimationControllerファイルを指定する。

スクリプト内での操作

スクリプト内でAnimationContollerにアクセスする場合は、ContollerをAnimationに適用した状態で
Animator anim = GetComponent();
のようにGetComponentで取得する。

スクリプト内での変数の操作例
anim.SetBool("Jump", false); "Jump"フラグをFalseにする
anim.SetFloat("Speed", Mathf.Abs(h)); "Speed"に変数hの絶対値をセットする
anim.GetBool("OnGround"); "OnGround"変数の現在の状態を取得する(Bool)
anim.GetFloat("JumpHeight"); "JumpHeight"変数の現在の値を取得する(Float)
anim.SetTrigger("Sliding"); "Sliding"変数をON/OFFする
anim.ResetTrigger("Sliding");

現在の状態Stateの取得
予め
static int idleState = Animator.StringToHash("Base Layer.Idle");
のような形でState毎のHash値を取得しておき(INT)
private AnimatorStateInfo currentBaseState = anim.GetCurrentAnimatorStateInfo(0)
を毎フレーム行い、Stateの現在状態を取得する。
以後
if(currentBaseState.nameHash == idleState)
の形で現在Stateに基いた処理を行うことが可能。遷移中か否かは
anim.IsInTransition(0)
で取得できる。

・各アニメーションへの設定

Stateから辿る場合。
Stateに設定されているアニメーションファイルを辿り、Animations内の親になるPrefabファイルを選択する。
(Explorerで見るとFBXファイルになっている)
Inspector->Animations内のCurvesを選択するとアニメーションの時間を横軸にしたグラフを操作可能。
JumpHeightの場合、時間経過で飛び上がった高さを変更するので、凸型のカーブを作成する。作成した後はInspector下部の「Apply」を押すことで適用する。
逆に言うと作成に失敗した場合はRevertを押すと元に戻る。
このカーブをスクリプト内で取得することでジャンプ時のキャラクターの当たり判定の大きさ変更に使用する。
f:id:DYMN:20140625111220p:plain

・BlendTree
新Stateを作るときにFrom New Blend Treeを選択することが可能。1つのStateの中で変数の値に応じて複数のアニメーションを呼び出すことができる。
図中Blend TreeにWALKとRUNの2つのアニメーションを設定し、変数Speedの0/0.8を閾値として与えている。
Animator側に与えたSpeedが0.8以上になると走りのアニメーションになる。
f:id:DYMN:20140625111222p:plain

参考http://www.slideshare.net/gametsukuru/ss-34996719

球体の表面の座標を取得したい(直交座標→極座標変換)

たとえばとある「球体の表面を這い回る」あるいは「ある点からX,Y,Z的に等距離の座標」を取得し続けたい場合……
球座標変換を行う。2角度と球体半径から直交座標を取得する。

	@Start
	// 親オブジェクトから与えられた角度(度数)をラジアン角に変換、極座標のθ・φの初期値とする.
	angleTheta	= initAngleT * Mathf.Deg2Rad;
	anglePhi	= initAngleP * Mathf.Deg2Rad;
	
	// パーティクルオブジェクトからパーティクルコンポーネントを取得する.
	partSys = tgtParticleObj.GetComponent<ParticleSystem>();
	
	// 初期θ・φからパーティクルオブジェクトの初期位置を決定する。基準は本オブジェクトの中心を使用する.
	tgtParticleObj.transform.position = pos + GetPositionOnSphere(angleTheta, anglePhi, particleSphereRadius);

	@Update
	// 中心として使用するスフィアはY軸を中心に回転し続ける.
	thisObj.transform.eulerAngles += new Vector3(0, Time.deltaTime * sphereRollingSpeed, 0);
	
	// 経過時間に従い、θ・φを変化させていく­.
	angleTheta	+= Time.deltaTime * moveSpeed1 * particleSpeed * Mathf.Deg2Rad;
	anglePhi	+= Time.deltaTime * moveSpeed2 * particleSpeed * Mathf.Deg2Rad;
	
	// 本フレームにおけるパーティクルオブジェクトの位置を決定・変更する.
	tgtParticleObj.transform.position = pos + GetPositionOnSphere(angleTheta, anglePhi, particleSphereRadius);

	// 直行座標・球体座標変換公式.
	public Vector3 GetPositionOnSphere(float angle1, float angle2, float r)
	{
	        float x = r * Mathf.Sin(angle1) * Mathf.Cos(angle2);
	        float y = r * Mathf.Sin(angle1) * Mathf.Sin(angle2);
	        float z = r * Mathf.Cos(angle1);
	        return new Vector3(x, y, z);
	}

画像だとわかりづらいが、パーティクルのエミッターを背負ったオブジェクトが球体の表面(正確には球体中心から一定の距離)を動き回っている。
f:id:DYMN:20140614232834p:plain

角度に乱数突っ込んで座標に小さいオブジェクト生成しまくるような処理試すと球が形作られていく。

パーティクルシステムShurikenの簡単な使用方法 とりあえずレベル

Shurikenて首をはねそうな名前だな……いや別に手裏剣が首はねするわけじゃないんだけど。

作成の方法は2通り。
GameObject -> Create Other -> Particle System or Component -> Effects -> Particle System
前者の方法だとEmptyなオブジェクトが生成され、それにParticleSystemがアタッチされた状態になる。
後者は選択中のオブジェクトにアタッチされる。Emptyなオブジェクトに貼り付けた場合前者と同じになる。たぶん。

パーティクルシステムの細かい設定は省略、というか検索すればいくらでも解説出てくるし、なによりまだ自分でも理解しきれていない。

スクリプトで使用する場合。
とりあえず呼び出したい。

	ParticleSystem pSys;
	:
	:
	GameObject pObj = thisPlayer.transform.FindChild("ConvergeMist").gameObject;
	pSys = pObj.GetComponent<ParticleSystem>();
	pSys.Play();
	:
	:

自分のEmptyな子オブジェクト、「ConvergeMist」にアタッチされているパーティクルを使用したいケース。
たとえばマウスクリックに合わせてpSys.Play()を呼び出すととりあえずは動く。LoopをOFFにしたりPlay on Awakeを切っとかないとなんか変になるけどそのへんは追々修正していけばよいかと。

パーティクルの扱いはモデルやプログラム構築とはまた違ったセンスが必要になりそうだなぁ……

オブジェクトに画像を貼り付ける際のあれやこれ

開発中に簡単な画像を貼り付けたい場合、Photoshop等で作成→UnityでAssetsに読み込み・テクスチャで使用という流れが簡単、というか今そうやってる。
透過画像を貼り付ける時の動作について自分用メモ。

f:id:DYMN:20140608011253p:plain

Aオブジェクト
 Photoshop側では「背景透過・文字シェイプをラスタライズ・結合せず・PNG保存」
 Unity側では「"LetterA"MaterialをCreate・Materialの画像にLetterA.png・ShaderはTransparent/Diffuse」

Dオブジェクト
 Photoshop側では「背景透過・文字シェイプをラスタライズ・画像結合・PNG保存」
 Unity側は「"LetterD"MaterialをCreate・Materialの画像にLetterD.png・ShaderはDiffuse・ついでにMain Colorもちょっと調整」

スクリプト内で動的にPhysicsMaterialを設定する/Resources.Load

基本的にはPrefab側で設定しておき、インスタンスを生成するのがベターだろうが時にはスクリプト内で動的に物理挙動を設定したい場合もある。かもしれない。
一応以下の方法で可能なことは確認した。PhysicsMaterialの設定というか、Resources.Loadの使い方かな。

thisObject.rigidbody.collider.material = (PhysicMaterial)Resources.Load("Physics/BulletSatellite");

ただし対象となるファイルはResourcesフォルダの下に配置しておかないとダメらしい。
AddComponentみたいに一発で決められるといいんだけどなぁ。
f:id:DYMN:20140604212612p:plain

http://realisapp.com/unity3d/resources-load/
http://answers.unity3d.com/questions/14242/how-to-change-physics-material-of-a-colider-in-run.html

レイヤー番号からレイヤー名を取得する/LayerMask.LayerToName

CollisionやTriggerで接触・取得したオブジェクトをレイヤー名で管理したい場合。

hogehoge.gameObject.layerに格納されているのはレイヤーの番号なので、名前で管理したい場合は文字列に変換する必要がある。

void OnCollisionEnter(Collision col)
{
  Debug.Log("Layer = "+col.gameObject.layer);
  Debug.Log("Layer2Name = "+LayerMask.LayerToName(col.gameObject.layer));
	
  if(LayerMask.LayerToName(col.gameObject.layer) == "Ground")
  {
    doJump = false;
  }
}

逆に名前からレイヤー番号に変換する場合はLayerMask.NameToLayer("hogehoge")

どっちが早いのかなぁ。変換の手間は同じだとするとやっぱり整数比較の方だろうか。