簡體   English   中英

(Unity3D)獲取一個網格系統以檢測大於一個圖塊的GameObject

[英](Unity3D) Getting a grid-system to detect GameObject that is bigger than one tile

我遇到了一個問題,其中我有一個GameObject,例如大小為1x3-並且該游戲對象僅被識別為位於圖塊上,因為它放置在圖塊上並在檢查器中指定了坐標(例如5 x,0 y,6 z) 。 問題在於該代碼僅檢測到一個圖塊(網格代碼的中間圖塊)上有一個GameObject。

我需要確保GameObject覆蓋的其他圖塊知道那里有一個GameObject,因此我可以將它們全部設置為例如它們不可在上面行走-或在旁邊緊挨着將它們用作覆蓋物他們。 但是到目前為止,該代碼僅注冊了GameObject的1個圖塊-問題就出在這里。

問題是,我不知道從哪里開始。 我有一些想法,也許做一個循環來檢查是否有游戲對象,然后檢查旁邊的瓷磚,但是代碼不會知道該瓷磚上是否有東西,並且該循環的性能也會非常高-除非我這樣做在“喚醒”或“開始”或類似內容上。

誰能指出我正確的方向? Unity中是否有一些內置的東西可以檢測某些東西是否在我創建的特定圖塊之上?

它是一個自己的網格系統,可以支持3D記錄,因此我沒有使用Unity如今提供的用於2D游戲的內置tilemaps系統。

Unity版本2017.3

下面是Gridbase.cs-處理世界並產生所有節點(平鋪)

public class GridBase : MonoBehaviour
{
    //Grid Scale
    public int sizeX = 32;
    //amount of floors/levels, Y is up
    public int sizeY = 3;
    public int sizeZ = 32;
    public float scaleXZ = 1;
    // character scale
    public float scaleY = 2.3f;

    public Node[,,] grid;
    public List<YLevels> yLevels = new List<YLevels>();

    public bool debugNode = true;
    public Material debugMaterial;
    GameObject debugNodeObj;

    void Start()
    {
        InitPhase();
    }

    public void InitPhase()
    {
        if (debugNode)
            debugNodeObj = WorldNode();

        //debug check all values for the grid.
        Check();

        //Spawn Grid Function
        CreateGrid();

        GameManager.singleton.Init();


    }

    void Check()
    {
        if(sizeX == 0)
        {
            Debug.Log("Size x is 0, assigning min");
            sizeX = 16;
        }
        if(sizeY == 0)
        {
            Debug.Log("Size y is 0, assigning min");
            sizeY = 1;
        }

        if (sizeZ == 0)
        {
            Debug.Log("Size z is 0, assigning min");
            sizeX = 1;
        }

        if (scaleXZ == 0)
        {
            Debug.Log("ScaleXZ is 0, assigning min");
            scaleXZ = 1;
        }

        if (scaleY == 0)
        {
            Debug.Log("ScaleY is 0, assigning min");
            scaleY = 2;
        }
    }


    void CreateGrid()
    {
        grid = new Node[sizeX, sizeY, sizeZ];

        for (int y = 0; y < sizeY; y++)
        {
            YLevels ylvl = new YLevels();
            ylvl.nodeParent = new GameObject();
            ylvl.nodeParent.name = "Level" + y.ToString();
            ylvl.y = y;
            yLevels.Add(ylvl);

            //Creating Collision for all nodes)
            CreateCollision(y);

            for (int x = 0; x < sizeX; x++)
            {
                for (int z = 0; z < sizeZ; z++)
                {
                    Node n = new Node();
                    n.x = x;
                    n.y = y;
                    n.z = z;

                    n.isWalkable = true;

                    if(debugNode)
                    {

                        Vector3 targetPosition = WorldCoordinatesFromNode(x, y, z);
                        GameObject go = Instantiate(debugNodeObj,
                            targetPosition,
                        Quaternion.identity ) as GameObject;

                        go.transform.parent = ylvl.nodeParent.transform;

                    }



                    grid[x, y, z] = n;


                }

            }
        }
    }

    void CreateCollision(int y)
    {
        YLevels lvl = yLevels[y];
        GameObject go = new GameObject();
        BoxCollider box = go.AddComponent<BoxCollider>();
        // Creates a box collider that has the whole size of the grid + a little bit more
        box.size = new Vector3(sizeX * scaleXZ + (scaleXZ * 2),
            0.2f,
            sizeZ * scaleXZ + (scaleXZ * 2));

        //Spawn box collider in center
        box.transform.position = new Vector3((sizeX * scaleXZ) * .5f - (scaleXZ * .5f),
            y * scaleY,
            (sizeZ * scaleXZ) * 0.5f - (scaleXZ * .5f));

        lvl.CollisionObj = go;
        lvl.CollisionObj.name = "lvl " + y + " collision";

    }

    public Node GetNode(int x, int y, int z)
    {
        x = Mathf.Clamp(x, 0, sizeX - 1);
        y = Mathf.Clamp(y, 0, sizeY - 1);
        z = Mathf.Clamp(z, 0, sizeZ - 1);
        return grid[x, y, z];
    }

    //get World Cordinates from any Node
    public Vector3 WorldCoordinatesFromNode(int x, int y, int z)
    {
        Vector3 r = Vector3.zero;
        r.x = x * scaleXZ;
        r.y = y * scaleY;
        r.z = z * scaleXZ;
        return r;
    }

    GameObject WorldNode()
    {
        GameObject go = new GameObject();
        GameObject quad = GameObject.CreatePrimitive(PrimitiveType.Quad);
        Destroy(quad.GetComponent<Collider>());
        quad.transform.parent = go.transform;
        quad.transform.localPosition = Vector3.zero;
        quad.transform.localEulerAngles = new Vector3(90, 0, 0);
        quad.transform.localScale = Vector3.one * 0.95f;
        quad.GetComponentInChildren<MeshRenderer>().material = debugMaterial;
        return go;


    }

    public static GridBase singleton;
    private void Awake()
    {
        singleton = this;
    }
}


[System.Serializable]
public class YLevels
{
    public int y;
    public GameObject nodeParent;
    public GameObject CollisionObj;
}

這是Node.cs文件

public class Node
{
    //Node's position in the grid
    public int x;
    public int y;
    public int z;

    //Node's costs for pathfinding purposes
    public float hCost;
    public float gCost;

    public float fCost
    {
        get //the fCost is the gCost+hCost so we can get it directly this way
        {
            return gCost + hCost;
        }
    }

    public Node parentNode;
    public bool isWalkable = true;

    //Reference to the world object so we can have the world position of the node among other things
    public GameObject worldObject;

    //Types of nodes we can have, we will use this later on a case by case examples
    public NodeType nodeType;
    public enum NodeType
    {
        ground,
        air
    }
}

這是生成節點(平鋪)的GridBase代碼pastebin.com/gazu9jPR,這是每當gridbase引用Node類時觸發的節點腳本-pastebin.com/jk25n6ee

您可以在將要創建游戲對象的位置使用觸發對撞機。 每個網格單元都需要一個單獨的對撞機。 使具有對撞機的游戲對象成為網格單元的子級(我不完全了解您的層次結構,因此我會繼續猜測)。 然后,當對撞機檢測到游戲對象時,讓相應的單元知道它已被占用。 希望這可以幫助。

所有的瓷磚都需要有對撞機。 另外,您放置在網格上的對象還需要有一個碰撞器(刻度作為觸發器),該碰撞器必須足夠大以與圖塊的碰撞器重疊。 然后,您可以使用它來檢查該對象覆蓋了多少塊瓷磚。 您可以使用Bounds類型的Collider.bounds來做到這一點。 Bounds對象具有一個名為Contains的方法,您可以在該圖塊的中心點傳遞該方法,查看它是否被該對象覆蓋。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM