月別アーカイブ: 2015年7月

触れたら落ちる床を作る【Unity5】

img003

–まえがき–

中野シスターズがかわいいので、いろいろ組み合わせて何か作りたかったので、NavMeshで自動歩行させるところまでは思いつき、それにあわせてタワークライミング要素として落ちる床をUnityで作ろうと思いました。
これよりもコードを軽くする方法はあると思いますが、忘備録として記事を作りました。

Rigidbodyを追加し、スクリプトを作成、タグを作る

まずは床になるCubeをHierarchyから作成し、Rigidbodyを追加し、C#のスクリプト(下の例ではRandomForce.cs)を
作成し、コンポーネントに追加します。これをPrefabにしておきます。また、この方法ではタグが重要になってくるので、忘れずに
オリジナルのタグを作っておきます。(例ではCubeというタグを作っています。)

img000

タグは赤枠のところからAdd Tag…を選択し、Inspectorの画面がTags&Layersに変わるので、Tagsの下の+マークを押して
下図のように追加しておきます。

img001

RandomForce.csは以下のように書いています。

//###RandomForce.cs###

using UnityEngine;
using System.Collections;

public class RandomForce : MonoBehaviour {
    Rigidbody rigid;

    void Start () {
        rigid = gameObject.GetComponent<Rigidbody>();
        if (rigid) {
            rigid.constraints = RigidbodyConstraints.FreezeAll;
        }
    }

    public void Move(float time) {
        Invoke("_Move", time);
    }

    void _Move() {
        if (rigid) {
            rigid.constraints = RigidbodyConstraints.None;
            rigid.AddTorque(new Vector3(
                2f*Random.value-1f, 2f*Random.value-1f, 2f*Random.value-1f));
            Invoke("TimeOut", 10f);
        }
    }

    void TimeOut() {
        DestroyImmediate(gameObject);
    }
} 

ここでのポイントは、Rigidbodyのコンストレインを開始時にRigidbodyConstraints.FreezeAllにしておくことです。これで何らかの要因でCubeが勝手に動いてしまうことを防ぎます。

衝突後は_Move()の処理によって、コンストレインを解除します。また、普通にコンストレインを解除にしただけだとCubeがまっすぐ下に落ちて面白くないので、AddTorque()でランダムに弱い回転処理を加えています。
これだけでも落ちていく様子がずいぶんと変わってきます。

Move()と_Move()の二つの関数があるのは、衝突判定後に数秒してから落下を開始させたいのと、別のオブジェクトからCubeの参照を持たせないようにするためです。
また、落下が始まった後にひたすら物理が働いていても困るので、10秒後にインスタンスを破棄してHierarchyから消すようにしています。

PlayerのGameObjectにCapsuleColliderを追加、スクリプトを追加する

プレイヤー側にはカプセルコライダーをセットし、他のオブジェクトとの衝突判定用のスクリプトを用意します。同じようにスクリプト(MoveCube.cs)を追加します。
このとき、カプセルコライダはー小さめにセットしておくと、過判定を防げます。

img002

MoveCube.csは以下のように書いています。NavMeshAgentを加えているのは、Playerの動きを自動化しているためです。
詳しくは、NavmeshのAI経路探索とAnimatorのアニメーションを連動させる #Unity - テラシュールブログを参照してください。
NavMeshAgentが必要でない場合は、Update()のコードそのものを消して、プロパティからAnimatorとNavMeshAgentを取ってもらっても大丈夫です。
OnCollisionEnter() で衝突した相手のオブジェクトを参照して、"Cube"のタグを持つゲームオブジェクトのみに対し、SendMessage() を発行してCubeにアタッチされているRandomForce.csの関数を呼び出しています。
また、AudioSourceの処理である、sorce.Play()は足音の音をアタッチしているだけですので、これも不要ならSendMessage()の行だけで大丈夫です。

//###MoveCube.cs###
using UnityEngine;
using System.Collections;

public class MoveCube : MonoBehaviour {
    public NavMeshAgent agent;
    public Animator animator;
    public AudioSource source;
    int beforeTime;

    void Update () 
    {
        if (animator != null && agent != null) {
            animator.SetFloat ("Speed", agent.velocity.sqrMagnitude);
        }
    }

    void OnCollisionEnter(Collision other) {
        if (other.gameObject.CompareTag ("Cube")) {
            other.gameObject.SendMessage ("Move", 1f, SendMessageOptions.DontRequireReceiver);
            int current = Time.frameCount;
            if(current - beforeTime > 7) {
                source.Play();
                beforeTime = current;
            }
        }
    }
}

これを使って動画にしたものはこちらになります。

Youtube

ハコスコストア

モデルは中野シスターズの鷺宮カノちゃんを使用しました。
中野シスターズ