Make an object collide with certain other objects when moved to RaycastHit point in Unity3D?

人走茶凉 提交于 2021-01-29 19:33:59

问题


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?

alt text


回答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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!