问题
I'm making a simple building system using Raycasting from the mouse pointer. The object that is to be placed is moved (and cloned on click) to the RaycastHit.point of the ray, but I want it to fully collide with objects of its own type, shifting its position relative to the hit point. The object can intersect the terrain as shown in the gif, but should not be inside of the already placed wall blocks. I tried using hit.distance but couldn't figure the detection out, since the object is being positioned at the collision point already. Should I try and detect how should the position should shift relative to the hit point or should I somehow make the MeshCollider work while it's being constantly moved to the RaycastHit.point?
回答1:
This is one way to do what you ask.
private void Update()
{
Vector3 hitPosition = Vector3.zero;
Ray ray = _camera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit))
{
hitPosition = hit.point; // 0
if (hit.transform.gameObject.CompareTag("cube")) // 1
hitPosition = ComputeHit(hit, hitPosition);
}
_current.transform.position = hitPosition;
}
private Vector3 ComputeHit(RaycastHit hit, Vector3 currentPosition)
{
var bounds = hit.transform.GetComponent<MeshRenderer>().bounds; // 2
Faces face = GetFace(hit); // 3
switch (face)
{
case Faces.Up:
currentPosition += new Vector3(0, bounds.extents.x, 0);
break;
case Faces.Down:
currentPosition += new Vector3(0, -bounds.extents.x, 0);
break;
case Faces.East:
currentPosition += new Vector3(bounds.extents.x, 0, 0);
break;
case Faces.West:
currentPosition += new Vector3(-bounds.extents.x, 0, 0);
break;
case Faces.North:
currentPosition += new Vector3(0, 0, bounds.extents.x);
break;
case Faces.South:
currentPosition += new Vector3(0, 0, -bounds.extents.x);
break;
}
return currentPosition;
}
public Faces GetFace(RaycastHit hit)
{
Vector3 res = hit.normal - Vector3.up;
if (res == new Vector3(0, -1, -1))
return Faces.South;
if (res == new Vector3(0, -1, 1))
return Faces.North;
if (res == new Vector3(0, 0, 0))
return Faces.Up;
if (res == new Vector3(1, 1, 1))
return Faces.Down;
if (res == new Vector3(-1, -1, 0))
return Faces.West;
if (res == new Vector3(1, -1, 0))
return Faces.East;
return Faces.Nothing;
}
public enum Faces
{
Nothing,
Up,
Down,
East,
West,
North,
South
}
I will explain further :
In your Update method, once you detect where is the hit.point
location // 0
, you can check whether or not you aim a cube or not // 1
. I don't know how you manage them once instantiated, but I add a tag named cube
.
It could be any name or a layer.
It could also be a component and check whether or not this component exist with hit.transform.GetComponent<...>()
method.
Then, you get the aimed cube bounds // 2
and use the normal to determine which direction you are aiming // 3
.
From here, depends on the aimed face (one out of 6), you add an offset to your hit.point
on one of the 3 axes.
bounds.extents give you the half of the faces, using bounds.extents.x
, bounds.extents.y
and bounds.extents.z
.
You only want the offset to be half length of the face, because when you move your cube with the mouse, the location of the cube is in the center of it.
Here is an example :
来源:https://stackoverflow.com/questions/61656803/make-an-object-collide-with-certain-other-objects-when-moved-to-raycasthit-point