上下左右にスワイプ・フリックした時に、カメラと相対的な「奥前左右」にキャラクターの向きを変える。
カメラのRotation(Y軸のみ抽出)を入力座標に掛けて、相対的にするのがコツ。
解説
- スワイプ・フリックのデルタ値を、真上から見た形のワールド座標に変換。
- カメラのRotationからY軸のみ抽出。
- 入力した方向と、カメラのRotation(Y軸のみ)とを合わせた向きに、LookAtさせる。
- 短いコードで、PCとスマホ両方に対応する為、Input.GetTouchでなく、Input.GetMouseを使用。
コード
GameManager的な物
GameManager的な物に、これを記述。
//向きを変えたいキャラクターにアタッチしたメインスクリプトを紐付け。
//ここでは仮にPlayerとしておく。
[SerializeField]
Player player;
Vector2 beganTouchPosition;
Vector2 endedTouchPosition;
Vector2 direction;
void Update () {
CheckTouch();
}
void CheckTouch () {
if (Input.GetMouseButtonDown(0)) {
beganTouchPosition = Input.mousePosition;
}
if (Input.GetMouseButtonUp(0)) {
endedTouchPosition = Input.mousePosition;
//スワイプ・フリックした向きを計算。
direction = endedTouchPosition - beganTouchPosition;
//スクリーン座標の上下左右を、ワールド座標の奥前左右に修正。
player.StartLookAt(new Vector3(direction.x, 0, direction.y);
}
}
Player
Playerのメインスクリプトに、これを記述。
//向きの変更は、短時間で連発する事が予想されるので、StopCoroutine出来るように、きちんと管理する。
Coroutine lookAt;
//カメラのRotationを直接使うと、X、Z軸の回転が余計になる為(Z軸は余り使わないと思うが)、除外する。
Quaternion mainCameraRotationIgnoreXZ;
//LookAtのスピード。大きい程早くなる。
float lookAtRate = 0.1f;
//経過時間。
float elapsedTime = 0;
//LookAtが継続する任意の長さ。LookAtのスピードはlookAtRateで管理しているので、「向き終わった瞬間」と一致しないので注意。
float duration = 0.5f;
//毎回Camera.main.transformから読み取ると負荷になるので、初期化時に保持しておく。
Transform mainCameraTransform;
void Awake () {
mainCameraTransform = Camera.main.transform;
}
public void StartLookAt (Vector3 direction) {
//連続して使う場合は、前のコルーチンを止める。
//このコードではnullを代入しなくても大丈夫だが一応完全に止めている。
if (lookAt != null) {
StopCoroutine(lookAt);
lookAt = null;
}
lookAt = StartCoroutine("LookAt", direction);
}
IEnumerator LookAt (Vector3 direction) {
elapsedTime = 0;
mainCameraRotationIgnoreXZ = new Quaternion(0, mainCameraTransform.rotation.y, 0, 0);
while (true) {
elapsedTime += Time.fixedDeltaTime;
//入力された方向に、一定の速度で向き続ける。
//Rigidbodyがアタッチされているなら、transform.rotationでなく、rigidbody.rotationの操作に変更した方が良い。
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(mainCameraRotationIgnoreXZ * direction, Vector3.up), lookAtRate);
if (duration < elapsedTime) {
yield break;
}
yield return new WaitForFixedUpdate();
}
}