##レーザー
Ray
とLineRenderer
で実装します。
Ray
がオブジェクトに当たったかどうかの判定を行い、LineRenderer
の終点の位置を変えることで
レーザーの途切れを表現します。
そのためにはRay
とLineRenderer
の始点、終点を合わせておく必要があります。
void OnRay()
{
float lazerDistance = 10f;
Vector3 direction = hand.transform.forward * lazerDistance;
Vector3 pos = hand.transform.position;
RaycastHit hit;
Ray ray = new Ray(pos, hand.transform.forward);
lineRenderer.SetPosition(0,hand.transform.position);
if (Physics.Raycast(ray, out hit, lazerDistance))
{
lineRenderer.SetPosition(1, pos + direction);
}
Debug.DrawRay(ray.origin, pos + direction, Color.red, 0.1f);
}
画像のようにぴったりと合わせることができました。(赤い線=Ray
,青い線=LineRenderer
)
##貫通してしまう
先程のコードのままでは画像のようにオブジェクトを貫通してしまいます。
この問題を解決するうえで、Ray
とLineRenderer
をぴったりと合わせたことが鍵となります。
Ray
はオブジェクトとの衝突判定を行うことができます。
また、オブジェクトと衝突した座標を取得することもできます。
つまり、LineRenderer
の終点にRay
が衝突した座標を当てはめれば
オブジェクトに当たった箇所でレーザー(LineRenderer)が途切れているように見せることができるということです。
コードに落とし込むとこうです。
if (Physics.Raycast(ray, out hit, lazerDistance))
{
hitPos = hit.point; //オブジェクトとの衝突座標を取得
lineRenderer.SetPosition(1, hitPos); //LineRendererの終点に当てはめる
}
##デモ
OculusQuestでビルドしたデモになります。
遮蔽物でレーザーが途切れているように見えます。ばっちりです。
デモにおいて、始点も少しずらしているので
始点のずらし方に関しても最終的なコードと合わせて記述していきます。
##最終的なコード
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class Laser : MonoBehaviour
{
[SerializeField]
GameObject hand;
LineRenderer lineRenderer;
Vector3 hitPos;
Vector3 tmpPos;
float lazerDistance = 10f;
float lazerStartPointDistance = 0.15f;
float lineWidth = 0.01f;
void Reset()
{
lineRenderer = this.gameObject.GetComponent<LineRenderer>();
lineRenderer.startWidth = lineWidth;
}
void Start()
{
lineRenderer = this.gameObject.GetComponent<LineRenderer>();
lineRenderer.startWidth = lineWidth;
}
void Update()
{
OnRay();
}
void OnRay()
{
Vector3 direction = hand.transform.forward * lazerDistance;
Vector3 rayStartPosition = hand.transform.forward*lazerStartPointDistance;
Vector3 pos = hand.transform.position;
RaycastHit hit;
Ray ray = new Ray(pos+rayStartPosition, hand.transform.forward);
lineRenderer.SetPosition(0,pos + rayStartPosition);
if (Physics.Raycast(ray, out hit, lazerDistance))
{
hitPos = hit.point;
lineRenderer.SetPosition(1, hitPos);
}
else
{
lineRenderer.SetPosition(1, pos + direction);
}
Debug.DrawRay(ray.origin, ray.direction * 100, Color.red, 0.1f);
}
}
##始点をずらす
始点をずらしているのは下記の箇所です。
Vector3 rayStartPosition = hand.transform.forward*lazerStartPointDistance;
Ray ray = new Ray(pos+rayStartPosition, hand.transform.forward);
Vector3 pos = hand.transform.position;
lineRenderer.SetPosition(0,pos + rayStartPosition);
Shaderで始点をずらしているようにみせる1こともできますが、
今回は始点そのものの座標を調節してます。
手にコライダーが付いている状態で手のTransformを参照してRay
を出した場合、
手のPivot、コライダーの大きさによっては
Ray
が手のコライダーに衝突してしまって判定が取れない場合があります。
そもそものRay
の始点をずらすことで意図しない衝突を回避できます。