2016年11月06日

【Unity】動く床に乗った時、キャラクターも一緒に移動するようにする方法

先日動く床を作成しましたが、そのままではキャラクターが乗った時に床だけ移動してキャラクターは床から落ちてしまいました。

【Unity】複数の目的地を通って動く床を作ってみた

今回はその解決方法を書いておこうと思います。

解決方法はとても簡単で、動く床に乗った時にキャラクターを動いている床の子オブジェクトにすれば良いのです。

スクリプトを書く前にまずはヒエラルキーから動く床のオブジェクトmFloorを選択し、Tagの横のUndefinedとなっているところを開きAdd Tagをクリックします。

オブジェクトにタグを加える。

するとインスペクターがタグを追加出来る画面に変わります。
Tagsのところにある+をクリックし、出てきたボックスにMoveFloorと入力します。

MoveFloorというタグを加える。

そしたらまたヒエラルキーからmFloorを選択し、TagをMoveFloorに変更します。

オブジェクトのタグを選択する

あとはキャラクターがこのMoveFloorのタグが付いた床に乗った時にその子オブジェクトになるようなスクリプトを書けばOKです!

function OnControllerColliderHit(hit : ControllerColliderHit) {
	if (hit.gameObject.tag == "MoveFloor") {
		transform.parent = hit.gameObject.transform;
	} else {
		transform.parent = null;
	}
}

言語はJavascriptです。
このスクリプトをキャラクターを動かしているスクリプトに書き加えるか新しくスクリプトのファイルを作成して書いてキャラクターにアタッチすれば動く床と一緒にキャラクターも移動するはずです。

このスクリプトはキャラクターコントローラーを使用していることを前提に書いていますが、状況に応じてOnCollisionEnterやOnTriggerEnter等を使えば良いと思います。

試しに動かしてみます。

オブジェクトにタグを加える。

ちゃんと動く床と一緒に移動していますね!

ヒエラルキーのキャラクターの動きにも注目してください。
今回使っているキャラクターは名前をSpartaにしてあります。
動く床に乗るとSpartaがmFloorの子オブジェクトになり、床から降りるとその親子関係が解消されているのが分かりますね!

ただこのスクリプトも気になる程ではないかもしれませんが問題点があって、動く床から降りる際に別の動かない床などに触れるまでは動く床の子オブジェクトのままなので、それまでは動く床の動きに合わせてキャラクターも動いてしまうのです。

これはOnControllerColliderHitを使って全部処理しているからなので、キャラクターの足元にキャラクターコントローラーから下に少しはみ出るくらいの位置にトリガーを配置してスクリプトの最後のelseを消して下記のようにすれば解決します。

オブジェクトにタグを加える。
function OnControllerColliderHit(hit : ControllerColliderHit) {
	if (hit.gameObject.tag == "MoveFloor") {
		transform.parent = hit.gameObject.transform;
	} 
}

function OnTriggerExit(){
	transform.parent = null;
}

これで動く床から離れた瞬間に親子関係が解消されるので、ジャンプすると床だけ目的地に移動します。

どちらが良いかはその時の状況や好みで使えば良いと思います。

スポンサードリンク
タグ:JavaScript UNITY
posted by ナオ at 17:49 | Comment(0) | Unityの使い方メモ
2016年10月27日

【Unity】複数の目的地を通って動く床を作ってみた

ゲームをやっていると床が離れた場所との間を行ったり来たりしていることがありますよね? 今回はその動く床をUnityで作ってみたいと思います。

今回作る動く床は2か所以上の目的地を設定し、その目的地を通って往復するというものです。
単純な動きですが、敵の巡回なんかにも使えると思います。

まずは空のゲームオブジェクトを作成し、名前をMoveFloorにします。
ポジションを(0,0,0)にします。
ポジションは適当でも大丈夫ですが、(0,0,0)にしておくと後で子オブジェクトを配置する際に座標がワールド座標と同じになるので分かりやすいと思います。

空のオブジェクトMoveFloorを配置。

次は移動させる床を配置します。
MoveFloorの子オブジェクトとしてキューブを配置し、名前をmFloorと適当につけます。
サイズは(5,1,5)にしました。
ポジションは普通の床から少し浮いた適当な場所にします。

MoveFloorの子オブジェクトに動かす床mFloorを配置。

白いままでは味気ないのでテクスチャを貼り付けました。

mFloorにテクスチャを貼った。

mFloorの移動先になる目的地を配置していきます。
MoveFloorの子オブジェクトとして移動させたい目的地の数だけ空のゲームオブジェクトを作ります。
名前はTarget1、Target2といった具合に適当に付けます。

ポジションは移動させたい場所に適当に設定します。
今回は(-5,1.5,0)、(0,5,10)、(5,1.5,0)の3か所に目的地を配置しました。

空のゲームオブジェクトを目的地に配置。

次は床を動かすためのスクリプトを作ります。
プロジェクトウィンドウでJavascriptのファイルを作成し、名前をMoveFloorにしてファイルを開きます。

開いたファイルに下記のコードを書きます。

#pragma strict

public var moveFloor : GameObject;       //移動させる床
public var TargetPoint : GameObject[];    //目的地
public var moveSpeed : float = 5;         //移動速度

private var Target : int = 0;             //TargetPointの配列の番号
private var count : int;                  //TargetPointの長さ
private var ReturnPath : boolean = false; //復路かどうか

function Start () {
	count = TargetPoint.Length;
}

function Update () {
	//動く床が目的地に着いたら次の目的地を設定する
	if(moveFloor.transform.position == TargetPoint[Target].transform.position){
		if(ReturnPath){
			Target --;
			if(Target < 0){
				Target = 1;
				ReturnPath = false;
			}
		} else {
			Target ++;
			if(Target >= count){
				Target = count - 2;
				ReturnPath = true;
			}
		}
	}

	Debug.Log(TargetPoint[Target]); //移動先の確認用。不要なら消してOK。
	moveFloor.transform.position = Vector3.MoveTowards (moveFloor.transform.position, TargetPoint[Target].transform.position, Time.deltaTime * moveSpeed);
}

スタート関数ではcountに目的地の数を代入しています。

次にアップデート関数を見ていきます。
まずif文で目的地に着いたかどうかを判定しています。
さらにif文で往路か復路かを判定し、復路であればTargetの値を1減らして次の目的地を設定しています。
そのときTargetの値が0より小さくなったらTargetを1にして次の目的地を設定し、ReturnPathをfalseにすることで往路に切り替えます。
elseの後はその逆のことなので説明は省きます。

Debug.Log(TargetPoint[Target]);はコンソールウィンドウで移動先を確認するためのものなので消してOKです。

最後にVector3.MoveTowardsを使って目的地まで床を移動させます。
Vector3.MoveTowards(現在地, 目的地, 移動速度)で目的地まで一定の速度で移動することが出来ます。
このVector3.MoveTowardsをVector3.LerpやVector3.Slerpに変えても少し違った動きをするので場面によっては変えても良いかもしれません。
Vector3.Lerpにすると僕のイメージではUFOのような感じの動きになります。

2Dでこのスクリプトを使う場合はVector3をVector2に変えれば多分OK。

書き終えたら保存してヒエラルキーにあるゲームオブジェクトのMoveFloorにスクリプトをアタッチします。

MoveFloorスクリプトをゲームオブジェクトMoveFloorにアタッチ

インスペクターから今加えたスクリプトのMove FloorにmFloorを入れ、Target PointのSizeを目的地の数に設定し、Elementに先ほど配置した目的地の空のゲームオブジェクトを入れます。

Target PointのSizeを変更して目的地を設定。

これで動く床は完成です!
試しに動かしてみるとこんな感じになります。

動く床完成。

途中動きがカクカクした感じになってるのは僕のPCのスペックが足りてないので動画を撮りながら動かすのがきついからなだけで、実際にはちゃんと動いています。
設定した目的地をちゃんと通って移動しているのが分かると思います。

あとはこのMoveFloorをプレハブにすればOKです!
これで穴の上を移動する床を作ったり高い場所へ移動する床を作ったり出来ますね!

でもこの床にはまだ問題点があります。
それはこの床にキャラクターコントローラーで動かしているキャラを乗せても一緒に移動しないのです。

どういうことかというと次の画像を見てください。

動く床に乗ってもキャラクターは移動しない。

床は動いてるのにキャラクターは床に乗ってもその場から動かずに落ちてしまっていますね。

長くなってしまったのでこの解決方法はまた今度書くことにします。

【Unity】動く床に乗った時、キャラクターも一緒に移動するようにする方法
スポンサードリンク
タグ:JavaScript UNITY
posted by ナオ at 17:37 | Comment(0) | Unityの使い方メモ
2016年10月08日

Unityで裏面が表示されないので両面映るようにしてみる

以前Blenderで作ったスパルタ兵の3DモデルのデータをUnityに入れてみた際に、マントの裏面が表示されていませんでした。

スタンダードシェーダーをUnityにドラッグ&ドロップ

そこで今回はマントの裏面もUnityで表示できるようにしてみたいと思います。

とは言ったもののシェーダーに関する知識がないのでとりあえずググってみたところ以下のサイトを見つけました。

ImpressiveCode「Unity3dでPlaneの両面表示」

シェーダーを作成してファイルを開き、1行目のCustom/NewShaderを適当な名前に変更し、SubShaderの中にcull offと書けば良いらしいです。

ということで実際にやってみました。

プロジェクトウィンドウのCreateからシェーダーのファイルを作成すると、元からあるスタンダードシェーダーのような設定が出来ないので不便に感じることがあるかもしれません。
シェーダーのコードの書き方が分かっている人ならそれでも良いでしょうが、僕は分からないのでスタンダードシェーダーのコードにcull offを書き加えたいと思います。

ですがプロジェクトウィンドウの中を探してもスタンダードシェーダーのファイルは見つかりません。
スタンダードシェーダーのファイルはUnityのサイトからダウンロードしてくる必要があります。

Unity ダウンロード アーカイブ

上記のページにアクセスし、ダウンロードのところから「ビルトインシェーダー」を選択します。

スタンダードシェーダーをダウンロード

するとzipファイルがダウンロードされるので解凍ソフトで解凍します。

解凍したファイルを開くとDefaultResourcesExtraというフォルダがあり、その中にStandard.shaderがあります。
このファイルをプロジェクトウィンドウにドラッグ&ドロップします。

スタンダードシェーダーをUnityにドラッグ&ドロップ

投入したファイルの名前を変更します。
今回はBothFaceという名前にしました。

スタンダードシェーダーの名前を変更

ダブルクリックでファイルを開き、コードを変更します。

Shader "StandardBothFace" { // ←変更

// 〜略〜

SubShader {
	Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }
	LOD 300
	cull off // ←追加

// 〜略〜

1行目は普通のスタンダードシェーダーと区別するためにStandardBothFaceとしました。

SubShaderは52行目と211行目あたりの2か所にありますが、最初の方にあるSubShaderのところにcull offと書き加えれば両面表示になるようです。

コードを変更して保存したら両面を表示したいマテリアルを選択し、インスペクターのShaderからStandardBothFaceを選択します

マテリアルのインスペクターで両面シェーダーを選択

そしてシーンビューを見てみるときちんとマントが表示されています。

正面から見るとマントが映るようになった。

もちろん後ろから見てもマントは映っています。

後ろから見てもマントは映っている。

スタンダードシェーダーのコードに書き加えたので、インスペクターからスタンダードシェーダーと同じように設定もできます。

スタンダードシェーダーと同じ設定が出来る。

これで裏面が表示されない場合に対処することが出来るようになりました!

スポンサードリンク
posted by ナオ at 14:04 | Comment(0) | Unityの使い方メモ