カーリングの的の画像をペイントソフトで適当に作ってマテリアルに設定しました。この的は「ハウス」と呼ばれます。
ハウスの近くにストーンがあって、そのストーンが動いているときだけ、上から見下ろすようなカメラに切り替えてみます。
ストーンをはじくスクリプトの付いた空のゲームオブジェクトを中央に持ってきます。
これにコライダーを付けて、Is Triggerにチェックを入れます。
サイズを変更して、ハウスの周辺をカバーします。Edit Colliderボタンを押すと、シーン上でオブジェクトのサイズを変更するようにコライダーのサイズを変えられます。
微調整するときに便利です。
トリガーの当たり判定をテストしてみます。
private void OnTriggerEnter(Collider other)
{
Debug.Log("enter");
}
コライダーの中に侵入したときにテキストが表示されています。
Is Triggerにチェックを入れているので衝突せずに通り抜けます。
上からハウスを見下ろすカメラを新規作成します。
非アクティブにしておきます。
ストーンがハウスの近くにきたらデフォルトのメインカメラをオフにして、このカメラをオンにします。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class CurlingScript : MonoBehaviour
{
Plane groundPlane;
Vector3 downPosition3D;
Vector3 upPosition3D;
public float thrust = 3f;
float rayDistance;
Ray ray;
public GameObject stone;
List<Rigidbody> stones;
bool stoneEnter = false;
public GameObject mainCamera;
public GameObject lookDownCam;
// Start is called before the first frame update
void Start()
{
groundPlane = new Plane(Vector3.up,0f);
stones = new List<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0)) // 左クリックを押した時
{
downPosition3D = GetCursorPosition3D();
}
else if (Input.GetMouseButtonUp(0)) // 左クリックを離した時
{
upPosition3D = GetCursorPosition3D();
if (stones.Count != 0 && downPosition3D != ray.origin && upPosition3D != ray.origin && stones[stones.Count - 1].GetComponent<StoneScript>().stoneState == 0)
{
stones[stones.Count - 1].GetComponent<Rigidbody>().AddForce((downPosition3D - upPosition3D) * thrust, ForceMode.Impulse); // ストーンをはじく
stones[stones.Count - 1].GetComponent<StoneScript>().stoneState = 1;
}
}
// ストーンを出現させる
if(Input.GetKeyDown(KeyCode.R) && (stones.Count == 0 || stones[stones.Count - 1].GetComponent<StoneScript>().stoneState != 0))
{
stones.Add(Instantiate(stone, new Vector3(42f, 3f, 0f), Quaternion.Euler(0f, 0f, 0f)).GetComponent<Rigidbody>());
}
if (stoneEnter)
{
stoneEnter = false;
foreach (Rigidbody stone in stones)
{
if (stone.velocity != Vector3.zero && stone.transform.position.x > -13f)
{
stoneEnter = true;
}
}
if (!stoneEnter) // 全てのストーンが止まっているとき
{
mainCamera.SetActive(true);
lookDownCam.SetActive(false);
}
}
}
Vector3 GetCursorPosition3D()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition); // マウスカーソルから、カメラが向く方へのレイ
groundPlane.Raycast(ray, out rayDistance); // レイを飛ばす
return ray.GetPoint(rayDistance); // Planeとレイがぶつかった点の座標を返す
}
private void OnTriggerEnter(Collider other)
{
stoneEnter = true;
mainCamera.SetActive(false);
lookDownCam.SetActive(true);
Debug.Log("enter");
}
}
ストーンが空のゲームオブジェクトのコライダーに侵入したらカメラが切り替わって、その後にストーンがもっと奥へ通り過ぎるか、動きを止めたらカメラが元に戻ります。
ストーンのインスタンスを作るときに、ゲームオブジェクトではなくRigidbodyをリストに入れるように変更しました。
stones.Add(Instantiate(stone, new Vector3(42f, 3f, 0f), Quaternion.Euler(0f, 0f, 0f)).GetComponent<Rigidbody>());
ストーンが範囲に入るとstoneEnterがTrueになります。その間だけリストの中のRigidbodyをForeach文で全て見ていって、速度と位置を調べています。
if (stoneEnter)
{
stoneEnter = false;
foreach (Rigidbody stone in stones)
{
if (stone.velocity != Vector3.zero && stone.transform.position.x > -13f)
{
stoneEnter = true;
}
}
if (!stoneEnter) // 全てのストーンが止まっているとき
{
mainCamera.SetActive(true);
lookDownCam.SetActive(false);
}
}
一旦stoneEnterをfalseにしてから、リストを調べて、一つでもハウスの近くで動いているストーンがあれば再度trueになります。
全てのストーンを調べてもstoneEnterがfalseのままならカメラを戻します。
(追記)
カーリングの試合中継をよく見ると、上から見下ろすカメラの映像では、ストーンが画面の上から下へ移動しています。
なので、カメラをZ軸で180度回転させました。