1 c# unity-game-engine raycasting
我在理解如何保留对先前被光线投射击中的对象的引用时遇到问题。
例如,我可以将光线投射脚本放在我的第一人称控制器的相机上,从相机位置到前向矢量 * 某个值
此脚本附加到相机
public class raycast : MonoBehaviour {
float lenthRay = 10.0f;
Vector3 originePos;
Vector3 dir;
RaycastHit hitinfo;
GameObject hitten;
bool isHitting;
Color beforC;
int selectionLayer = 9;
void Update () {
originePos = Camera.main.transform.position;
dir = Camera.main.transform.forward * lenthRay;
Debug.DrawRay(originePos, dir, Color.blue);
if (Physics.Raycast(originePos, dir, out hitinfo, lenthRay , selectionLayer)) {
hitten = hitinfo.transform.gameObject;
MeshRenderer tmp = hitten.transform.GetComponent<MeshRenderer> ();
beforC = tmp.material.color;
tmp.material.color = Color.black;
}
//hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
print(hitten.name);
}
Run Code Online (Sandbox Code Playgroud)
}
它工作得很好,除非我尝试在我的 if 条件之外访问 GameObject Hitten(如打印print(hitten.name)
)
在从正确的层击中对象之前,我收到此错误:
NullReferenceException: Object reference not set to an instance of an object
raycast.Update () (at Assets/raycast.cs:30)
Run Code Online (Sandbox Code Playgroud)
然后当我击中物体时就可以了
但问题是,我不明白我怎么可以变回对象的颜色其原来的颜色(beforC)
也开始转向后Color.black
当光线出口对象
这就是我在注释行中尝试做的事情,但我得到的错误与打印时相同,并且没有任何变黑。
我试过这个:
originePos = Camera.main.transform.position;
dir = Camera.main.transform.forward * lenthRay;
Debug.DrawRay(originePos, dir, Color.blue);
isHitting = Physics.Raycast (originePos, dir, out hitinfo, lenthRay, selectionLayer);
if (isHitting) {
hitten = hitinfo.transform.gameObject;
MeshRenderer tmp = hitten.transform.GetComponent<MeshRenderer> ();
beforC = tmp.material.color;
tmp.material.color = Color.black;
}
if(!isHitting){
hitten.transform.GetComponent<MeshRenderer> ().material.color = beforC;
print(hitten.name);
}
Run Code Online (Sandbox Code Playgroud)
但它也不起作用
你能帮我理解我应该使用的逻辑吗 提前谢谢
我也有同样的需求,当我试图检测墙壁何时挡住了玩家。我以前从未使用过 Raycast(或 Linecast),并且很惊讶没有内置方法来检测“进入”、“停留”和“离开”事件。
所以我创建了这个简单的类来为我处理细节。我没有费心创建任何类构造函数,只是将属性公开为公共。它处理光线投射和线投射。
一旦您使用属性进行设置,该类就会为您跟踪每一帧的对象。
下面是一些示例代码来演示潜在的用法(我用于墙壁检测的代码):
private RayCaster wallRay;
void Start() {
wallRay = new RayCaster();
wallRay.OnRayEnter += WallRay_OnEnter;
wallRay.OnRayExit += WallRay_OnExit;
wallRay.LayerMask = RayCaster.GetLayerMask("Wall");
wallRay.StartTransform = camera.transform;
wallRay.EndTransform = PlayerManager.Player.transform;
}
void Update() {
wallRay.CastLine();
}
void WallRay_OnEnter(Collider collider) {
// Fade OUT wall section [Needs DOTween (free) installed]
collider.gameObject.renderer.material.DOFade(0.65f, 0.2f);
}
void WallRay_OnExit(Collider collider) {
// Fade IN wall section
collider.gameObject.renderer.material.DOFade(1f, 0.2f);
}
Run Code Online (Sandbox Code Playgroud)
这是RayCaster类:
using System;
using System.Collections;
using UnityEngine;
public class RayCaster {
public Transform StartTransform;
public Transform EndTransform;
public Vector3 Direction;
public float RayLength;
public int LayerMask = 0;
public event Action<Collider> OnRayEnter;
public event Action<Collider> OnRayStay;
public event Action<Collider> OnRayExit;
Collider previous;
RaycastHit hit = new RaycastHit();
public bool CastRay() {
Physics.Raycast(StartTransform.position, Direction, out hit, RayLength, LayerMask);
ProcessCollision(hit.collider);
return hit.collider != null ? true : false;
}
public bool CastLine() {
Physics.Linecast(StartTransform.position, EndTransform.position, out hit, LayerMask);
ProcessCollision(hit.collider);
return hit.collider != null ? true : false;
}
private void ProcessCollision(Collider current) {
// No collision this frame.
if (current == null) {
// But there was an object hit last frame.
if (previous != null) {
DoEvent(OnRayExit, previous);
}
}
// The object is the same as last frame.
else if (previous == current) {
DoEvent(OnRayStay, current);
}
// The object is different than last frame.
else if (previous != null) {
DoEvent(OnRayExit, previous);
DoEvent(OnRayEnter, current);
}
// There was no object hit last frame.
else {
DoEvent(OnRayEnter, current);
}
// Remember this object for comparing with next frame.
previous = current;
}
private void DoEvent(Action<Collider> action, Collider collider) {
if (action != null) {
action(collider);
}
}
public static int GetLayerMask(string layerName, int existingMask=0) {
int layer = LayerMask.NameToLayer(layerName);
return existingMask | (1 << layer);
}
}
Run Code Online (Sandbox Code Playgroud)