2014年10月2日木曜日

【Unity、UniRx】クリック回数をトースト表示しつつ、オブジェクトを動かす


@Baiteen

ReactiveExtensionsがUnityでも使えるってのを今更知ったので、今更ながら使ってみた。その7。

やりたいこと

ReactiveExtensionsを使ってクリック回数をトースト表示しつつ、左右にあるCubeオブジェクトを動かす。
せっかくなので、左のCubeはRigitbodyにAddForceで、右のCubeはイベント経由で動かすようにした。

前回の記事が分かりづらいと評判だったので、前回の補足も兼ねて。

やったこと

(UniRxはインポート済み)
※前回からUnityのバージョンが 4.6 beta になってます。(uGUIを使ってみたかっただけ)

前回のなごりでPlaneを追加(Planeじゃなくてもいい)
暗いのでDirectional lightを追加
クリック用のSphereを追加
トースト表示するためのText追加(GameObject→UI→Text)。Textを追加すると勝手にCanvas、EventSystemも追加されるはず。
動かすためのCubeを2つ追加。左をBlueCube、右をRedCubeとしました。両方共にRigitbodyを追加。
Cubeに色を付けるためのMaterialを作成。BlueMaterialとRedMaterial。それぞれBlueCube,RedCubeにドラッグドロップでCubeに色がつくはず。
※Sphere、Cubeの位置は適当に調整してください。

C#Scriptを作成して名前をSphereScriptに変更
今回はもう一つC#Scriptを作成して名前をCubeScriptに変更

ここまででこんな感じになってるはず。

SphereScript、CubeScriptをそれぞれ以下のように変更
・SphereScript
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UniRx;

static class ColorExt
{
  /// 
  /// Textのアルファ値をセットする拡張メソッド
  /// 
  /// uGUIのText
  /// アルファ値
  public static void setA (this UnityEngine.UI.Text text, float a)
  {
    text.color = new Color(text.color.r, text.color.g, text.color.b, a);
  }
}

public class SphereScript : ObservableMonoBehaviour
{
  /// トースト表示用オブジェクト
  public GameObject Toast;

  /// 赤い四角オブジェクト
  public GameObject RedCube;

  /// 
  /// 指定秒間だけEveryUpdateを発行する
  /// 
  /// 
  /// 秒
  private IObservable TakeSec (double value)
  {
    //0秒〜経過秒が値として発行される
    return Observable.EveryUpdate().Scan(
        new { time=0f, offset=Time.time }
        , (a, t)=>new { time=Time.time - a.offset, offset=a.offset }
      ).Select(delta => delta.time)
      .TakeUntil(Observable.Timer(System.TimeSpan.FromSeconds(value)));
  }

  #region 連打イベント関連 ここはC#のイベントの説明読んで
  public class BarrageEventArgs : EventArgs
  {
    public int ClickCount;
    public BarrageEventArgs(int clickCount){ this.ClickCount = clickCount; }
  }
  public event EventHandler Barrage;
  private void OnBarrage (BarrageEventArgs e)
  {
    if (Barrage != null) Barrage(this, e);
  }
  #endregion

  ///  RXのサンプルがAwakeだったので、ここに書きました。 
  public override void Awake ()
  {
    //参考サイト:http://neue.cc/2010/07/28_269.html

    //トースト用オブジェクトからuGUIのTextを取り出して、透明にする
    var text = Toast.GetComponent ();
    text.setA(0);

    //赤い四角オブジェクトからRigidbodyを取り出して、設定(重力無視&自然に止まって欲しいので空気抵抗を与える)
    var redRigidbody = RedCube.GetComponent();
    redRigidbody.useGravity = false;
    redRigidbody.drag = 5;

    //nueuccさんのアドカレ記事をパクりました
    //クリック回数をトースト表示
    OnMouseDownAsObservable ()
      .Buffer (OnMouseDownAsObservable ().Throttle (System.TimeSpan.FromMilliseconds (250)))
      .Select (xs => xs.Count)
      //クリック回数をテキストにセット
      .Do(cnt => text.text = string.Format ("{0} clicks", cnt))
      //クリック回数に比例した右向きの力を赤い四角に加える
      .Do(cnt => redRigidbody.AddForce(Vector3.right * cnt * 10))
      //連打イベントを発生させる
      .Do(cnt => OnBarrage(new BarrageEventArgs(cnt)))
      .SelectMany(cnt => 
        TakeSec(1).Do(t=>text.setA(t)).Last().SelectMany(_=>TakeSec(1).Do(t=>text.setA(1-t)))
      )
      .Subscribe (t=>Debug.Log(t));

    // If you use ObservableMonoBehaviour, must call base method ← サンプルにこう書いてますので、そのまま。
    base.Awake ();
  }
}

・CubeScript
using UnityEngine;
using System.Collections;

public class CubeScript : MonoBehaviour {

  // Use this for initialization
  void Start () {
    //自分からRigidbodyを取り出して、設定(重力無視&自然に止まって欲しいので空気抵抗を与える)
    var rigidbody = this.GetComponent();
    rigidbody.useGravity = false;
    rigidbody.drag = 5;

    //Sphereを探し出して、SphereScriptを取り出して、連打イベントが発生したら自分に力を加える
    var sphereScript = GameObject.Find("Sphere").GetComponent();
    sphereScript.Barrage += (sender, e) => { 
      rigidbody.AddForce(Vector3.left * e.ClickCount * 10); 
    };
  }
 
}

SphereScriptをSphereに、CubeScriptをBlueCubeにドラッグドロップ
Sphereに追加したSphereScriptに変数Toast、RedCubeがあるので、それぞれText、RedCubeをドラッグドロップ

これで完成。
Hosted by UnityRoom.com


Related Posts Plugin for WordPress, Blogger...