■マウスの水平操作でキャラを中心に回転
*プログラムの全容は後で示す。ここでは必要となったTipsだけ記載する。
例えば、StandardAssetsから3rd Person移動のEthan君を持ってきて、カメラを子オブジェクトにしたとする。このときのカメラワークは次の図のようになる。
TransformにはRotateAroundという関数が用意されており、これを使えば自身のTransformを指定角度分だけ円軌道させることができる(詳しくはリファレンス参照)。なお、この関数はあくまで円軌道させるものであり、プレイヤーの方向を向かせる機能はない。これについては「カメラワーク③」で触れる。
プレイステーション®のようなコントローラーであればL・Rボタンにカメラの円軌道を割り当てたいところだが、今回はパソコンで遊んでもらうことを想定しているのでマウスにこの機能を持たせる。Input.GetAxis("Horizontal")で水平方向の入力が得られるのと同様に、Input.GetAxis ("Mouse X")でマウスのX軸方向の移動量を平滑化した値が得られる。
よって、次のような関数を作りUpdateで呼び出せば、マウスの動きに応じて円軌道させることができる。
■マウスの上下操作でカメラの仰角・俯角を調整
本来ならば上下操作も円軌道にすべきだが、そうするとカメラがすぐに地面にすぐぶつかってしまう。「ステージの用意」で解説したように、地面を透過すると神社まで消えてしまうので、ここではベクトルの理解も兼ねてカメラのrotationを変更する。仰角・俯角はInspecterで表示されるrotetionのXの値のこと。Inspecter上ではオイラー角によるVector3に見えるが、transform.rotationはQuaternionという回転を表す4次元ベクトルである。(>>Quaternionについて)
Unityでオブジェクトを回転させたり角度を変える際には、Quaternionの関数かTransformの関数を使用したほうが無難。transform.eulerAnglesで現在のオイラー角のVector3が得られるので、このx成分にInput.GetAxis ("Mouse Y")を加えることで水平操作と同じようなことができる。Transform.Rotateを使う方が素直な気がするが、結局上限角を調べる必要があるため次のようにした。
Quaterion.Eulerは指定したオイラー角のQuaternionを作る関数。transform.eulerAnglesと同様にInspecterで表示されるrotationとイメージは同じなので、このコンビでの操作は直感的に分かりやすい。ただし、transform.eulerAnglesは制限が多いので安易に使うのは禁物。
尚、transform.eulerAnglesのx成分がX軸周りの回転であるため、マウスのY成分を加えることで合っているのだが、改めて見るとx成分にy成分を加えるという様子が奇妙に見えるので注意。また x成分は仰角が負、俯角が正のため、Input.GetAxis ("Mouse Y")の入力と逆転している。よって加算するときは符号を逆転する必要がある。これもまた奇妙に見えるので注意。
■マウス操作のプログラム全体(Main Cameraにアタッチ)
*ゲーム起動時にTitleManagerでTime.timeScale = 0とするのだが、このときこのプログラムを停止させないとゲーム立ち上げの暗転時に微妙にカメラを動かすことができてしまう。またタイトル画面ではカーソルを動かすことができ、アクションパートはカーソルをロックしたい。これらの都合から、このプログラムでカーソルをロックしている。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using System.Collections; | |
public class CameraMovement_Mouse : MonoBehaviour { | |
public Transform target; //<! Playerを中心に回転するのに使用 | |
public float speedY = 60f; | |
public float maxAngle = 45f; | |
private float anglePerSec = 360f; //<! 角速度(オイラー) | |
private float hitDir = 0f; | |
private bool Impenetrable = false; //<! カメラが通行不能な場合はtrue | |
// Update is called once per frame | |
void Update () { | |
//カーソルのロック | |
Cursor.lockState = CursorLockMode.Locked; | |
Cursor.visible = false; | |
//X軸の監視 | |
Impenetrable = Input.GetAxis ("Mouse X") * hitDir > 0;//<! 入力方向と壁のある方向が一致する場合は0より大きな正の数になるため、これで通行可能か判定(Rigidbodyで動かしていないためこのように判定) | |
if(Impenetrable){Debug.Log("カメラ接触中"); return;} | |
MouseX (); | |
//Y軸の監視 | |
MouseY (); | |
} | |
void MouseX (){ | |
//X方向の入力でtargetを中心に回転 | |
float angle = Input.GetAxis ("Mouse X") * anglePerSec * Time.deltaTime; | |
transform.RotateAround(target.position, Vector3.up ,angle); | |
} | |
void MouseY (){ | |
//カメラの回転をオイラーで取得(角度の限度をオイラーで判定するため) | |
Vector3 angles = transform.eulerAngles; | |
//x軸周りの回転にマウスの上下の動きを減算(MouseYは上が負、下が正) | |
angles.x -= Input.GetAxis ("Mouse Y") * speedY * Time.deltaTime; | |
//減算後の角度を限度角度内に収める | |
float limitUpper = 360 - maxAngle; | |
//仰角の限度 | |
if(angles.x < limitUpper && angles.x > 180f){angles.x = limitUpper;} | |
//俯角の限度 | |
if(angles.x > maxAngle && angles.x < 180f){angles.x = maxAngle;} | |
//カメラの回転 | |
transform.rotation = Quaternion.Euler(angles.x, angles.y, angles.z); | |
} | |
void OnTriggerEnter(Collider other){ | |
hitDir = Input.GetAxis("Mouse X"); | |
} | |
void OnTriggerExit(Collider other){ | |
hitDir = 0; | |
} | |
} |
0 件のコメント:
コメントを投稿