Nanashi-softプログラマ専用Unityでゲーム開発


◇Unityでゲーム開発 -Mecanimを使ってキャラを動かしてみる(12-

実際に実装していってみます

様々な方法が考えられるわけですが,単純な構造で考えてみます
・膝ボーンがスカートボーンに近付いたら浮かす
・離れたら戻す
というものです

本当は脚全体とスカート全体で判定したいところですが,ゲームでそんな事をすると処理が重過ぎます
歩行時に一番上がるのは膝なので,そこをスカートに張り巡らされたボーンの繋ぎ目で検知して動かす事にします

○膝ボーンにコライダを付ける

膝ボーンの位置はメカニムに組み込んだ際に,オートで設定されているはずなので,それを確認すれば良いです

Project上のモデルデータをクリック
Inspectorの Rigタブ→Configure...ボタン
人型が表示されるので,膝の部分をクリックすると,Hierachyにその部分が選択される
両膝のボーンの場所を覚える ←
Inspectorの Doneボタンを押して終了

シーン上に配置したキャラの Hierarchyにはボーン構造も見える状態になっています
先ほど確認した膝のボーンをクリック
メニュー→Component→Physycs→Sphere Collider
Game画面の右上の Gizmosをオンにすると,コライダのサイズがワイヤ表示されます
Inspectorの Shere Collider→Radiusを 0.1に設定(適当に縮めただけです)

○スカートを浮かす

これを適当に実装して,わけのわからない動きになったので,どういう動きをさせるのか? を説明します

Unityを実行中にボーンの Inspector→Transform→Rotaion→Zの数値を変えると,スカートが動きます
Z軸回転の小さくすると広がり,大きくするとすぼみます

回転ですので,ボーンの軸の位置は変わりません
そうすると,膝が近付いて来た際にスカートを広げたとしても,位置は動かないので膝が突き抜けるのを回避できません ←これになかなか気が付かなかった
1つ上の階層のボーンを回転させて,自身が広がるようにする必要があります

コレを踏まえてスクリプトを作成する
Projectの下の Create→C# Script→適当に skirtなどの名前に変える

以下のスクリプトを保存する
using UnityEngine;
using System.Collections;

public class skirt : MonoBehaviour {
	float syoki_rotz;	//初期位置
	float counter;		//カウンター

	void Start () {
		syoki_rotz=this.transform.parent.localEulerAngles.z;	//初期位置を保存
		counter=0;
	}

	// Update is called once per frame
	void Update () {
		float radius=0.1f;
		Collider[] hitColliders = Physics.OverlapSphere(this.transform.position, radius);	//この範囲内のコライダを抽出
		int i = 0;

		if(hitColliders.Length == 0){
			//周囲にコライダが無くなったら,元の位置に徐々に戻す
			if(0 < counter){
				this.transform.parent.localRotation=this.transform.parent.localRotation * Quaternion.AngleAxis(5.0f, Vector3.forward);
				counter--;
			}
		}else{
			while(i < hitColliders.Length){
				if(hitColliders[i].name != "Plane"){	//地面との衝突を除く
					//膝が近付いて来たのでスカートを広げる
					this.transform.parent.localRotation=this.transform.parent.localRotation * Quaternion.AngleAxis(-5.0f, Vector3.forward);
					counter++;	//広げた回数をカウント
				}
				i++;
			}
		}
	}
}
このスクリプトをスカートのボーンに追加する
注意点として,スカートの一番上には設置しないこと。1つ上のボーンを回転させるので,おかしくなる

1つ上のオブジェクトは,transform.parentでわかります(Unity3Dの仕様)
親のオブジェクトの回転角は,localRotationではなぜか正しく取得できませんでしたので,localEulerAnglesを使用して取得しました(なぜかはわかりません)
セットする時は localRotationでうまくいったので,そのままにしています

ちなみに,回転軸に関して,直接値を触ろうとすると,途端に破綻します(汗
回転計算は,基本的に行列を掛けるものだと思っていると幸せになれます
DirectXや OpenGLを直接プログラミングした事がある場合の経験則です('-'*)
なので,親オブジェクトの現在の回転角に,Quaternion.AngleAxisで角度ベクトルを生成して掛けています
これを,transform.rotation.zの値を変えようと考えると非常に難しいです(簡単そうに見えるのですがハマりの原因です)



TOPプログラマ専用Unityでゲーム開発

魔女っ子のヘアバンド