使用带偏移的 Raycast 命中点移动对象
Move object using Raycast hitpoint with offset
我正在尝试创建一个简单的 ObjectMover
class 来在基地内移动物体(想想 Clash of Clans 基地编辑)。
我遇到的问题是,当使用 RayCast
选择一个对象时,它会跳转到 RayCast hit.point
,因为对象的 collider
可以被击中边缘然后将移动到 hit.point
.
的中心
我试过使用偏移量,我确信这是微不足道的事情,但脑子放屁,找不到解决方案。
ObjectMover.cs
using UnityEngine;
using System.Collections;
public class ObjectMover : MonoBehaviour
{
#pragma warning disable 0649
[SerializeField] private GameObject _tmpObjectToMove;
[SerializeField] private LayerMask _groundLayerMask;
[SerializeField] private LayerMask _objectsLayerMask;
#pragma warning restore 0649
private Camera _cam;
private GameObject _movableObject;
private bool _objectIsSelected;
private Vector3 _objectSelectionOffset;
private void Awake()
{
_cam = Camera.main;
}
private void Start()
{
//TMP call and object instantiation for testing purposes
GameObject obj = Instantiate(_tmpObjectToMove, Vector3.zero, Quaternion.identity);
MakeObjectMoveable(obj);
}
private IEnumerator UpdatePosition()
{
while (_movableObject != null)
{
if (Input.GetButtonDown("Fire1"))
{
TestObjectSelection();
}
else if (Input.GetButtonUp("Fire1"))
{
if (_objectIsSelected)
{
_objectIsSelected = false;
}
}
if (_objectIsSelected)
{
_movableObject.transform.position = GetNewPosition();
}
yield return null;
}
}
public void MakeObjectMoveable(GameObject objectToMakeMovable)
{
_movableObject = objectToMakeMovable;
StartCoroutine(UpdatePosition());
}
private Vector3 GetNewPosition()
{
if (_movableObject != null)
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _groundLayerMask, QueryTriggerInteraction.Ignore))
{
Vector3 pos = hitInfo.point - _objectSelectionOffset;
return new Vector3(pos.x, 0f, pos.z);
}
}
return _movableObject.transform.position;
}
private void TestObjectSelection()
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _objectsLayerMask, QueryTriggerInteraction.Ignore))
{
if (hitInfo.transform.gameObject == _movableObject)
{
Vector3 difference = hitInfo.point - _movableObject.transform.position;
_objectSelectionOffset = new Vector3(difference.x, 0f, difference.z);
_objectIsSelected = true;
}
}
}
}
我没看到什么?
一个问题是你的区别在于光线与建筑物表面和地面的碰撞,你将它添加到地面以获得变换的原点。
相反,根据玩家光线击中地面的位置设置偏移量:
private void TestObjectSelection()
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _objectsLayerMask, QueryTriggerInteraction.Ignore))
{
if (hitInfo.transform.gameObject == _movableObject)
{
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float groundDistance;
groundPlane.Raycast(ray, out groundDistance);
Vector3 groundPoint = ray.GetPoint(groundDistance);
// groundPoint is guaranteed y=0, so _objectSelectionOffset y=0;
_objectSelectionOffset = _movableObject.transform.position - groundPoint;
_objectIsSelected = true;
}
}
}
如果你的地面不是平面,你可以使用另一个 Physics.Raycast
得到 groundPoint
:
private void TestObjectSelection()
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _objectsLayerMask, QueryTriggerInteraction.Ignore))
{
if (hitInfo.transform.gameObject == _movableObject)
{
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _groundLayerMask, QueryTriggerInteraction.Ignore))
{
_objectSelectionOffset = _movableObject.transform.position - hitInfo.point;
_objectIsSelected = true;
}
}
}
}
无论哪种方式,然后你可以根据偏移量设置位置:
private Vector3 GetNewPosition()
{
if (_movableObject != null)
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _groundLayerMask, QueryTriggerInteraction.Ignore))
{
return hitInfo.point + _objectSelectionOffset;
}
}
return _movableObject.transform.position;
}
我正在尝试创建一个简单的 ObjectMover
class 来在基地内移动物体(想想 Clash of Clans 基地编辑)。
我遇到的问题是,当使用 RayCast
选择一个对象时,它会跳转到 RayCast hit.point
,因为对象的 collider
可以被击中边缘然后将移动到 hit.point
.
我试过使用偏移量,我确信这是微不足道的事情,但脑子放屁,找不到解决方案。
ObjectMover.cs
using UnityEngine;
using System.Collections;
public class ObjectMover : MonoBehaviour
{
#pragma warning disable 0649
[SerializeField] private GameObject _tmpObjectToMove;
[SerializeField] private LayerMask _groundLayerMask;
[SerializeField] private LayerMask _objectsLayerMask;
#pragma warning restore 0649
private Camera _cam;
private GameObject _movableObject;
private bool _objectIsSelected;
private Vector3 _objectSelectionOffset;
private void Awake()
{
_cam = Camera.main;
}
private void Start()
{
//TMP call and object instantiation for testing purposes
GameObject obj = Instantiate(_tmpObjectToMove, Vector3.zero, Quaternion.identity);
MakeObjectMoveable(obj);
}
private IEnumerator UpdatePosition()
{
while (_movableObject != null)
{
if (Input.GetButtonDown("Fire1"))
{
TestObjectSelection();
}
else if (Input.GetButtonUp("Fire1"))
{
if (_objectIsSelected)
{
_objectIsSelected = false;
}
}
if (_objectIsSelected)
{
_movableObject.transform.position = GetNewPosition();
}
yield return null;
}
}
public void MakeObjectMoveable(GameObject objectToMakeMovable)
{
_movableObject = objectToMakeMovable;
StartCoroutine(UpdatePosition());
}
private Vector3 GetNewPosition()
{
if (_movableObject != null)
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _groundLayerMask, QueryTriggerInteraction.Ignore))
{
Vector3 pos = hitInfo.point - _objectSelectionOffset;
return new Vector3(pos.x, 0f, pos.z);
}
}
return _movableObject.transform.position;
}
private void TestObjectSelection()
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _objectsLayerMask, QueryTriggerInteraction.Ignore))
{
if (hitInfo.transform.gameObject == _movableObject)
{
Vector3 difference = hitInfo.point - _movableObject.transform.position;
_objectSelectionOffset = new Vector3(difference.x, 0f, difference.z);
_objectIsSelected = true;
}
}
}
}
我没看到什么?
一个问题是你的区别在于光线与建筑物表面和地面的碰撞,你将它添加到地面以获得变换的原点。
相反,根据玩家光线击中地面的位置设置偏移量:
private void TestObjectSelection()
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _objectsLayerMask, QueryTriggerInteraction.Ignore))
{
if (hitInfo.transform.gameObject == _movableObject)
{
Plane groundPlane = new Plane(Vector3.up, Vector3.zero);
float groundDistance;
groundPlane.Raycast(ray, out groundDistance);
Vector3 groundPoint = ray.GetPoint(groundDistance);
// groundPoint is guaranteed y=0, so _objectSelectionOffset y=0;
_objectSelectionOffset = _movableObject.transform.position - groundPoint;
_objectIsSelected = true;
}
}
}
如果你的地面不是平面,你可以使用另一个 Physics.Raycast
得到 groundPoint
:
private void TestObjectSelection()
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _objectsLayerMask, QueryTriggerInteraction.Ignore))
{
if (hitInfo.transform.gameObject == _movableObject)
{
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _groundLayerMask, QueryTriggerInteraction.Ignore))
{
_objectSelectionOffset = _movableObject.transform.position - hitInfo.point;
_objectIsSelected = true;
}
}
}
}
无论哪种方式,然后你可以根据偏移量设置位置:
private Vector3 GetNewPosition()
{
if (_movableObject != null)
{
Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray.origin, ray.direction, out RaycastHit hitInfo, 200f, _groundLayerMask, QueryTriggerInteraction.Ignore))
{
return hitInfo.point + _objectSelectionOffset;
}
}
return _movableObject.transform.position;
}