ドアを見ているかどうか
プレイヤーがドアの近くでドアに視線を合わせているときに、マウスの左クリックを押すと、ドアを開閉できるようにします。
まずはプレイヤーの見ているものを調べましょう。
プレイヤーの向いている方へ Ray という光線を出して、それをぶつかったオブジェクトの情報を得られます。
out とともにつけた変数にオブジェクトの情報が入ります。初めに RayCastHit hit; と宣言しています。
hit.collider.name でオブジェクトの名前が取得できたり、hit.distance で ぶつかった点までのRay の長さを調べられます。
if(RayCastHit.collider.CompareTag("タグ名"))
{
}
とすると、このタグ名と、Ray がぶつかったオブジェクトのタグ名があっていれば true を返すので、タグでも判別できます。
Inspector > Tag > Add Tag… で新しいタグを作って選択します。
ドアに「Door」というタグをつけました。
加えて、プレイヤーとドアの距離が近い時にマウスの左クリックを押すと開閉できるようにします。
一度クリックすると、mouseClick という変数に true が入って、これが true の時に開閉処理をします。
プレイヤーの視線やドアまでの距離に関係なく、左クリックが終了すると、mouseClick が false になって、開閉処理が終わるようにします。
カーソル表示、プレイヤーの動きの固定
ところでどんな風にドアを開閉すると良いでしょうか。
いろんな方法がありますが、今回はホラーFPSなどでよくある操作にしましょう。
つまり、ドアの近くで左クリックすると、プレイヤーの動きやカメラの動きが固定されて、マウスを上下するとドアが開閉します。
なので、まずはマウスカーソルの表示やカメラの動きを変えられるようにします。
今回は、Standard Assets に含まれている FPSController を使っているので、その中で使われている MouseLook スクリプトを見てみましょう。
FPSController では、マウスを動かしても、カーソルの位置は画面の中央で固定されていますが、この、SetCursorLock() メソッドでロックのオンオフができます。
プレイヤーには、Rigidbody FPS Controller を使っています。これにはFPSのためのメインカメラがくっついていて、走ったりジャンプしたりといった動作が初めからできるようになっています。
Rigidbody FPS Controller には上のスクリプトがついているのでこれを見てみると
この部分で、MouseLook のインスタンスが、mouseLook という変数で作られていますね。
つまり、この Rigidbody FPS Controller の スクリプトの中で
mouseLook.SetCursorLock(false);
とすると、カーソルのロックが解除されるのですが、これをさっきの Raycast を飛ばしているスクリプトから実行します。
Raycast を飛ばしているスクリプトは、Rigidbody FPS Controller についている MainCamera についています。
なぜなら、Rigidbody FPS Controller の向きは左右のみで、上下を向くのは MainCamera だからです。
Rigidbody FPS Controller のスクリプトの namespace とクラス名 はこうなっているので、これを後ろにつなげてあげればOKです。
(sc_player 変数を宣言)
(void Start()内)
transform.parent.gameObject は、このオブジェクト(MainCamera)の親のオブジェクト(Rigidbody FPS Controller)です。
sc_player で、Rigidbody FPS Controller スクリプト を呼べるようになりました。
sc_player.mouseLook.SetCursorLock(false);
でカーソルロックの解除ができますね。
カーソルが表示され動かせるようになりましたが、カメラが付いてくると変ですね。
それから、この時はプレイヤーの歩行もロックしたいです。
そういったことも、Rigidbody FPS Controller スクリプト で行われています。
まずは、Rigidbody FPS Controller スクリプト に、新しく playerLock という変数をpublicで作ります。
この変数を MainCamera のスクリプトから切り替えます。
画面を動かしているのは、この RotateView() みたいなので、playerLock が true のときは実行されないようにします。
同様に、FixedUpdate() が playerLock が true では、冒頭で return されてそれ以降の処理を行わないようにします。
プレイヤーの動きが固定されました。マウスクリックをやめるとちゃんと元に戻ります。
ドアの開閉
ドアの開閉は、マウスを動かす方向によって、ドアに力を加えればできますね。
力を加えるには、AddForce() を使います。
// 宣言
public GameObject door;
Rigidbody rb_door;
// void Start()
rb_door = door.GetComponent<Rigidbody>(); //ドアのリジッドボディを取得
// 力を加えたいところで
rb_door.AddForce(力の方向, ForceMode);
ForceMode は力の加え方です。継続して与えるか一度に与えるかといったことを指定できます。ここでは Impulse で瞬間的に力を加えます。
力の方向は、ドアオブジェクトが向いている方向(transform.forward)の右の方向を取得できる、transform.right を使います。ここでは、forward は、ドアの軸から、ドアの先端へ向かう方向になっています。
ドアに向かった時の、カメラ側の方向です。
ところで、マウスドラッグはどうやって取得するでしょうか。
現在のマウスカーソルの座標は Input.mousePosition で得られます。これとクリックしたときのカーソルの座標の差をとって、クリックした場所から、マウスを上にドラッグしたら正の値、下にドラッグしたら負の値が得られるようにすると良いですね。
それを、AddForce のところで、transform.right にかけてあげれば、マウスを上にドラッグするとドアは時計回りに、マウスを下にドラッグすると、反時計回りに回転しますね。
ドアの向く方向(transform.forward)は回転とともに動きますから、ドアの右面が向いている方向が常に transform.right になるからです。
ですが、これだと、マウスを前に押すとドアがこちらに動いてしまうので、とりあえず -1 をかけて符号を逆にしてみます。
clickPosition には、マウスをクリックした時点の Input.mousePosition が入っています。
このままでは力が強すぎるので 2000で割っています。
良い感じですが、プレイヤーが向うの部屋へ行った後も、マウスを押し込むとドアが画面の奥へ進んでほしいです。マウスでドアを押す感じがいいですね。
次はドアのどちら側にいるかで力の方向を変えてみましょう。簡単な方法があります。