ラベル Unity の投稿を表示しています。 すべての投稿を表示
ラベル Unity の投稿を表示しています。 すべての投稿を表示

2012-06-03

【Unity】GUIでテクスチャの回転

これ、GUITextureクラスじゃできないらしいってことでメモ。
(GUITextureは拡縮程度ならできるんだけどなー)

ちなみに、GUIになるので、Translateは使えない。
直接GUI.matrixに作用させて描画をする必要がある。

が、そこはUnityさん。わざわざ行列作らないくとも、


GUIUtility.RotateAroundPivot

を使えば行列生成してくれる模様。
そのあとは、
GUI.DrawTexture
すればいいだけ。

GUI.matrixに変更がかかってしまうの、matrixを一時保存してから戻すとしてみるテスト。

public class UICompass : MonoBehaviour {

    [SerializeField]
    private Texture guiCompass;

    private Matrix4x4 tmpMat;
    private float angle;

    void Start () 
    {
        angleY = 0.0f;
    }

    public void SetAngle( float angle_ )
    {
        angle = angle_;
    }

    void OnGUI()
    {
        // テクスチャの回転はGUIUtility.RotateAroundPivotではないと回転できない
        tmpMat = GUI.matrix;    // 一時退避
        {
            Vector2 point = new Vector2(Screen.width * 0.5f, (float)Screen.height);
            GUIUtility.RotateAroundPivot(angle, point);
            GUI.DrawTexture(new Rect(Screen.width * 0.5f - guiCompass.width * 0.5f,
                                        Screen.height - guiCompass.height * 0.5f,
                                        (float)guiCompass.width,
                                        (float)guiCompass.height), guiCompass);
        }
        GUI.matrix = tmpMat;    // 戻す
    }
}

で、このクラスをてきとーなところにつけておいておいて、
これをプレイヤー側から、

private UICompass uiCompass;

    void Start () 
    {
        GameObject uiObj = GameObject.Find("/UI");
        if (uiObj) { 
            uiCompass = uiObj.GetComponent<UICompass>();
        }
    }

    void RotatePlayer() 
    {
        deltaRot = Quaternion.Euler(rotVec * Time.deltaTime);
        rigidbody.MoveRotation(rigidbody.rotation * deltaRot);
        uiCompass.SetAngle(transform.localEulerAngles.y);
    }


みたいな感じでやれば、追従して回ってくれる感じ。

わざわざSendMessageするほどのものでもないかなーと思って、
コンポーネントから引っ張りだして参照を保存しておく。

UICompassをPlayerのコンポーネントにしてもいいんだけど、
他の調整用スクリプトがくっついていたりしてインスペクタがみにくてしょうがない。
なので、UI系は空のGameObejctにまとめて記述することにした。

これでなんとなくすっきり。満足。

2012-05-27

Unityで音のフェードアウト

まあ、たまにはまともな記事も書きますよ。
今回は、Unityの話。たぶん、ブログではそんな扱ってなかったね-。

定期的に音が鳴っているオブジェクトを破棄する場合、audio.Stop()使えばまあ音は止まるんだが、
音がブツっとなるのがちょっと嫌。
で、まあ、音量をフェードアウトさせてから破棄してみようと思った。(volume=0.0fとするだけでも十分という気もしないでもない。)
Audioクラス自体にはフェード機能とかそんなのないので、試しにコルーチンを使ってみる。

 

   void OnHitItem()
    {
        Debug.Log("OnHitItem"); 
        valid = false;
        // Stopと使うと音がぶつ切りになる場合があるため、音量をフェードアウトさせて対応
        //audio.Stop();

        // 子においておいたパーティクルのエフェクトを開始
        ParticleSystem particleSystem = gameObject.GetComponentInChildren<particlesystem>();
        if (particleSystem) {
            particleSystem.Play();
            Debug.Log("Particle Start");
        }

        // フェードアウトスタート
        StartCoroutine("Fadeout", 1.0f);
        Debug.Log("OnHitItem End");
    }

    IEnumerator Fadeout( float duration )
    {
        float currentTime = 0.0f;
        float waitTime = 0.02f;
        float firstVol = audio.volume;
        while (duration > currentTime)
        {
            currentTime += Time.fixedDeltaTime;
            audio.volume = Mathf.Clamp01(firstVol * (duration - currentTime) / duration);
            Debug.Log("Step:" + audio.volume);
            yield return new WaitForSeconds(waitTime);
        }

        // エフェクトが完全に終了していたらオブジェクト破棄
        ParticleSystem particleSystem = gameObject.GetComponentInChildren<particlesystem>();
        while (particleSystem.isPlaying)
        {
            yield return new WaitForSeconds(waitTime);
        }
        Destroy( gameObject );
        Debug.Log("Destory");
    }

    // (以下略

まあ、こんな感じかなー。
アイテムに接触時に、外からOnHitItemが呼ばれることを想定してる。

呼ばれると同時に、接触したことを知らせるパーティクル表現を入れつつ、音をコルーチンでフェードアウトする。
さらに、一応パーティクルによるエフェクトが終了していることを確認してからDestory

ただし、コルーチン使う場合は、StartCoroutine直後の

 
        Debug.Log("OnHitItem End");

も即実行されてしまうので注意。つまり、

OnHitItem
Particle Start
Step: xx
OnHitItem End
Step: xx
Step: xx
...
Destory

こんな感じの実行順になる。はず。