光线投射同时击中2个物体



我最近在unity中开发,我有一个使用光线投射的问题。我创建了三个脚本:

  • 交互器:连接到播放器,它管理所有的光线投射功能
  • InteractionObject:钩到需要动画的对象
  • InteractionRaycast:钩到需要销毁的对象

一切正常,唯一的问题是,当游戏对象的动画发生时(在我的例子中,游戏对象是一个枕头),另一个游戏对象(它在枕头下面)在动画开始的同时被破坏。我的目标是首先移动枕头,然后点击要破坏的游戏对象,我能做什么?提前感谢您的帮助

Interactor.cs

public class Interactor : MonoBehaviour
{
[SerializeField]
private float _interctRange;
private InteractionObject _interactObject;
private InteractionRaycast _interactionRaycast;
private Camera _camera;
private RaycastHit _hit;
// Start is called before the first frame update
void Start()
{
_camera = Camera.main;
}
// Update is called once per frame
void Update()
{
if (Input.GetButton("Fire1"))
{
Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out _hit, _interctRange);
if (_hit.transform)
{
_interactObject = _hit.transform.GetComponent<InteractionObject>();

}
if (_interactObject)
{
_interactObject.PerfomAction();

}

}
}
}

InteractionObject.cs

public class InteractionObject : MonoBehaviour
{
[SerializeField]
private Vector3 _openPosition, _closePosition;
[SerializeField]
private float _animationTime;
private Hashtable _iTweenArgs;
[SerializeField]
public  bool _isOpen;
// Start is called before the first frame update
void Start()
{
_iTweenArgs = iTween.Hash();
_iTweenArgs.Add("position", _openPosition);
_iTweenArgs.Add("time", _animationTime);
_iTweenArgs.Add("islocal", true);
}
public void PerfomAction()
{
if (Input.GetButton("Fire1"))
{
if (_isOpen)
{
_iTweenArgs["position"] = _closePosition;
}
else
{
_iTweenArgs["position"] = _openPosition;
}
_isOpen = !_isOpen;
iTween.MoveTo(gameObject, _iTweenArgs);

}
}

} 

InteractionRaycast.cs

public class InteractionRaycast : MonoBehaviour
{
[SerializeField]
private float _range;
Ray _myRay;
RaycastHit _hit;
// Update is called once per frame
void Update()
{
if (Input.GetButton("Fire1"))
{
Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out _hit, _range);
if (_hit.transform)
{
Destroy(gameObject);
}

}
}
}

提示:使用RaycastAll()并根据条件过滤掉你想要的对象。

它可能会帮助你解决你的问题,尽管你首先应该注意@derHugo答案。它指出了你需要在代码中改进的许多方面。

你的InteractionRaycast将完全摧毁它所附着的gameObject,无论你击中的是什么。

您可以像

那样进行额外检查。
if (Input.GetButton("Fire1"))
{
var ray = _camera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
if(Physics.Raycast(ray, out var hit, _interctRange))
{
// Is this actually the object that was hit?
if(hit.transform == transform)
{
Destroy(gameObject);
}
}
}

或者-通常我会这样做-而不是在每个物体上都有这样一个组件,你可以与之交互并拍摄数百个冗余的光线投射,我宁愿在你的播放器对象上有一个组件,拍摄一个单一的光线投射并与你击中的任何物体进行交互。

你的两个目标对象可以有一个共同的接口

public interface IInteractionObject
{
void PerfomAction();
}

意味着这两种类型都需要实现一个名为PerformAction的不带参数的方法。

与 中的内容直接交互
public class Interactor : MonoBehaviour
{
[SerializeField]
private float _interctRange;

private Camera _camera;
// Start is called before the first frame update
void Start()
{
_camera = Camera.main;
}
// Update is called once per frame
void Update()
{
if (Input.GetButton("Fire1"))
{
var ray = _camera.ViewportPointToRay(new Vector3(0.5f, 0.5f));
// was something hit at all? => Check the API and return values of methods!
if(Physics.Raycast(ray, out var hit, _interctRange))
{
// Did we hit an IInteractionObject
if(hit.transform.TryGetComponent<IInteractionObject>(out var interactable))
{
// This class has no idea what exactly it is interacting with and doesn't need to know
interactable.PerfomAction();
}
}
}
}
}

然后你有不同的实现:

public class AnimatedInteractionObject : MonoBehaviour, IInteractionObject
{
[SerializeField] private Vector3 _openPosition;
[SerializeField] private Vector3 _closePosition;
[SerializeField] private float _animationTime;
[SerializeField] public bool _isOpen;
private Hashtable _iTweenArgs;
private void Start()
{
_iTweenArgs = iTween.Hash();
_iTweenArgs.Add("position", _openPosition);
_iTweenArgs.Add("time", _animationTime);
_iTweenArgs.Add("islocal", true);
}

public void PerfomAction()
{
_isOpen = !_isOpen;
// use ternary makes it easier to read
_iTweenArgs["position"] = _isOpen ? _openPosition : _closePosition;

iTween.MoveTo(gameObject, _iTweenArgs);
}
} 

public class DestroyInteractionObject : MonoBehaviour, IInteractionObject
{
public void PerfomAction()
{
// This is only called by the Interactor 
// it already does a key and raycast check so no need to do that here 
Destroy(gameObject);
}
}

最新更新