VR、ゲーム制作、プログラミング。Unity とか Oculus Rift とか。

2013年5月10日金曜日

[Unity]NGUIで当たり判定を付ける

NGUI でスプライトに当たり判定を付ける場合、普通に

  • スプライトに Collider を付ける
  • 必要に応じて RigidBody も付ける
  • OnCollisiionEnter などを書く

とした上で、

  • RigidBody の FreezePosision の z と FreezeRotation の x, y にチェック(負荷が減る、と思う)
  • 表示順の制御に z 座標を使っている場合、衝突し得るように Collider の Size.z などを調整
    • クリック等のイベントを受け取るスプライトの Collider は最も手前になるようにする
    • または、イベントを受け取るスプライトを含む UIPanel のレイヤを分け(スプライト個別にはレイヤを変更できないため UIPanel 単位になる)、UICamera の Event Receiver Mask をそのレイヤだけに、Camera の Culling Mask はそのレイヤも表示するようにする
あたりに気を付けるとよさそうです。

複数のスプライトが他のオブジェクトの子である場合などは、Collider は各スプライトに付け、イベントは親オブジェクトで処理(スプライト側で一旦受けて親に SendMessage)するのもよいかもしれません。

3D 用の衝突判定を 2D で使うのは富豪的な気もしますが…

2013年5月8日水曜日

[Unity]NGUIのOnDragイベントを使う

NGUI のスプライトをドラッグで動かせるようにしたときのメモです。

(2013/5/9 追記 : 動かすだけなら UIDragObject だけで済みます。こちらはコーディング不要です。)

スプライトに Collider をつけた上で、

public class Player : MonoBehaviour
{
    void OnDrag(Vector2 delta)
    {
        Vector2 mousePoint = UICamera.lastTouchPosition;
        Vector2 worldPoint = UICamera.currentCamera.ScreenToWorldPoint(mousePoint);
        
        transform.position = new Vector3(worldPoint.x, worldPoint.y, transform.position.z);
    }
}

または

public class Player : MonoBehaviour
{
    void OnDrag(Vector2 delta)
    {
        Vector2 mousePoint = UICamera.lastTouchPosition;
        Vector2 worldPoint = UICamera.currentCamera.ScreenToWorldPoint(mousePoint);
        
        // 普通は毎回 Find() しない
        transform.localPosition = GameObject.Find("UI Root (2D)").transform.InverseTransformPoint(new Vector3(worldPoint.x, worldPoint.y, 0));
    }
}

などですね。

引数の delta はスクリーン座標上での前回のマウス位置との差分(だと思う)なので、UIRoot の Scaling Style を Pixel Perfect にしていない限りはそのままでは使いにくそうですね。


2013/5/9 追記 : UIDragObject について追記しました。

2013年5月7日火曜日

[Unity]NGUIでスプライトを隙間なく並べる

NGUI で 2D ゲーム風にドット絵のマップチップを敷き詰めた時などに、スプライト間に 1px 程度の隙間が空いてしまう場合の確認内容です。

  • テクスチャの Filter Mode を Point にする


  • 元画像を周囲 1px 拡大しておく(TexturePacker を使っているなら、Layout の Extrude を 1 にするだけで簡単にできます)




2013年5月4日土曜日

[Unity]NGUIで画面サイズに合わせる(NGUI2.3.0対応版)

以前 [Unity]NGUIで画面サイズに合わせる(その2) で書いたスクリプトが、NGUI 2.3.0 の変更との兼ね合いで正しく動かなくなっていたので、今更ですが対応版です。

UIRoot.automatic が obsolete 扱いになり、代わりに scalingStyle というパラメータに変更になったようです。

  • PixelPerfect : 拡大縮小しない(automatic = true 相当)
  • FixedSize : 画面の高さに合わせる(automatic = false 相当)
  • FixedSizeOnMobile : iOS, Android のときは FixedSize、それ以外では PixedPerfect

横がはみ出ないように画面の幅に合わせる機能は現在でもないようですね。

というわけで、数行しか変わっていませんが 2.3.0 対応版です。

using UnityEngine;

[ExecuteInEditMode]
public class UIRootScale : MonoBehaviour
{
    public int manualWidth = 1280;
    public int manualHeight = 720;
    
    UIRoot uiRoot_;
    
    public float ratio {
        get {
            if(!uiRoot_){ return 1.0F; }
            return (float)Screen.height / uiRoot_.manualHeight;
        }
    }
    
    void Awake()
    {
        uiRoot_ = GetComponent<UIRoot>();
    }
    
    void Update()
    {
        if(!uiRoot_ || manualWidth <= 0 || manualHeight <= 0){ return; }
        
        int h = manualHeight;
        float r = (float)(Screen.height * manualWidth) / (Screen.width * manualHeight); // (Screen.height / manualHeight) / (Screen.width / manualWidth)
        if(r > 1.0F){ h = (int)(h * r); } // to pretend target height is more high, because screen width is too smaller to show all UI
        
        //if(uiRoot_.automatic){ uiRoot_.automatic = false; } // for before NGUI 2.3.0
        if(uiRoot_.scalingStyle != UIRoot.Scaling.FixedSize){ uiRoot_.scalingStyle = UIRoot.Scaling.FixedSize; } // for NGUI 2.3.0 or later
        if(uiRoot_.manualHeight != h){ uiRoot_.manualHeight = h; }
        if(uiRoot_.minimumHeight > 1){ uiRoot_.minimumHeight = 1; } // only for NGUI 2.2.2 to 2.2.4
        if(uiRoot_.maximumHeight < System.Int32.MaxValue){ uiRoot_.maximumHeight = System.Int32.MaxValue; } // only for NGUI 2.2.2 to 2.2.4
    }
}


2013/5/4 20:23 追記 : スクリプトに余計な行があったのを修正しました。