我正在尝试创建一个简单的ObjectMover
类来在基础内移动对象(想想《部落冲突》的基础编辑)。
我遇到的问题是,使用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;
}
}
}
}
如果有人能告诉我我没有看到和/或想到的内容,将不胜感激。
答案 0 :(得分:1)
一个问题是,您的区别在于射线与建筑物表面和地面的碰撞之间的差异,并且将其添加到地面以获取变换的原点。
相反,请根据玩家的光线撞击地面的位置设置偏移量:
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;
}