敵に目視されていなくてもフラッシュライトの当たった場所が敵から見えているとプレイヤーの位置がバレるようにしてみました。
まず敵のスクリプトにFPSプレイヤーが持っているスポットライトをアタッチします。
[SerializeField] Transform flashLight;
そして、フラッシュライトからレイを飛ばして、当たった場所に向けて、敵の顔からレイを飛ばします。それらが同じ場所に当たっているかどうかで、敵からライトが見えているかを判断します。
RaycastHit lightHit;
// フラッシュライトからレイを飛ばす
if(Physics.Raycast(flashLight.position, flashLight.forward,out lightHit,Mathf.Infinity))
{
Vector3 headToLightHitDir = Vector3.Normalize(lightHit.point - head.position); // 敵の顔から1つ目のレイの当たった場所への方向
RaycastHit seeTheLightHit;
// フラッシュライトからのレイが当たった場所に向けて敵の顔からレイを飛ばす
if (Physics.Raycast(head.position, headToLightHitDir, out seeTheLightHit, Mathf.Infinity))
{
// ライトと視線が同じ場所に当たったとき
//if (lightHit.point == seeTheLightHit.point)
if (Vector3.Distance(lightHit.point, seeTheLightHit.point) < 0.1f)
{
float dot = Vector3.Dot(headToLightHitDir, head.forward); // 内積
if (dot > 0)
{
// ゲージの増加分
increaseAttention += 0.03f * dot * Mathf.Clamp(10f / seeTheLightHit.distance, 0f, 1f)
text.text += "\nA:ライトが見えている";
}
else
{
text.text += "\nA:ライトが見えていない";
}
}
else
{
text.text += "\nA:ライトが見えていない";
}
}
else
{
text.text += "\nA:ライトが見えていない";
}
}
else
{
text.text += "\nA:ライトが見えていない";
}
ライトと敵の顔からのレイが同じ位置に当たったか判断するときに == を使うと、不安定だったので、それらの位置の間の距離が小さいかどうかを見るようにしました。
//if (lightHit.point == seeTheLightHit.point)
if (Vector3.Distance(lightHit.point, seeTheLightHit.point) < 0.1f)
その後、敵の顔の正面と顔からライトへの方向の内積から、視界の範囲内かどうかを判定しています。全く同じ向きだと1で逆方向だと-1です。角度が90度より小さいときに見えていることにしました。
float dot = Vector3.Dot(headToLightHitDir, head.forward); // 内積
if (dot > 0) {
// ...
}
敵が音と目視でプレイヤーを発見すると同様に、視界に入ったときにゲージを上げて、ゲージが満タンになるとプレイヤーが発見されます。
ゲージの増加分には内積をかけます。すると、視界の端よりも中央よりでライトが見えているときのほうがゲージが短時間で増加します。
また、ライトを見るレイの長さを0~1にした値もかけているので、遠くで見るより近くで見るほうがゲージが上がりやすくなります。
隙間の開いた柵などにライトを当てると、隙間をレイが通過したときだけ向こうの敵に発見されますが、こういう部分は常に縞状の影が見えているはずなので、レイが柵を無視するようにした方がいいのかもしれません。