Unity realizes 2D ground digging! Smear terrain (collision part, method 2)


foreword

The old rules first upload the renderings
insert image description here

After the explanation of the previous article on smearing terrain, many netizens privately asked me for the original code, and some netizens thought it was too complicated to realize. Regarding the original code, because the original original code of this Demo is lost, and the code itself is used in the company's game project to add a lot of project-related logic, I don't know if it can be shared, so I didn't directly publish the original code. Regarding the problem that is too difficult to achieve, if you just want to achieve the smear terrain, here I will share a simpler way, which is very simple!

The address of the previous article:
Method 1 of smearing terrain collision

Why is it simple, because only the distance calculation formula and the circular collision box are needed:
insert image description here

Ok, let's start entering the text...


1. Initialize the virtual point

Create a checkpoint during initialization and store it in an array.
It should be noted that the checkpoint here is only Vector2, and it does not need to be instantiated, otherwise it will consume a lot of performance. Remember remember...

1.1 point structure:

Each point is saved with a structure, we need to save the
following point data structure, which are records: 1. The position of the point, 2. The state of the current point, 3. The corresponding collision box

private class PointData
{
    
    
    public Vector2 pos;               //点位置
    public pointStatic sta;          //点状态
    public GameObject col;          //点实例
}

1.2 The status of each point:

1. Abandoned, this position has been completely excavated
2. Waiting for detection, this position has not been dug
3. In use: that is, this position is the edge of excavation, with a collision box

private enum pointStatic
{
    
    
    die,                        //已经废弃
    wait,                       //等待检测
    collid                      //正在使用
}

1.3 Generation point structure:

int line = (int)(scale.x * 100);
int row = (int)(scale.y * 100);
float distancesX = 1f / line;
float distancesY = 1f / row;
for (int j = 0; j < row; j++)
{
    
    
    for (int k = 0; k < line; k++)
    {
    
    
        Vector2 v2 = new Vector2(distancesX * k - 0.5f, distancesY * j - 0.5f);
        PointData data = new PointData();
        data.pos = v2;
        data.sta = pointStatic.wait;
        listPoint.Add(data);
    }
}

It is not difficult to see that these structural points do not instantiate anything except Vector2. The main reason is that 10,000 points are created here, which can greatly save performance. In fact, as shown in the figure,
100X100 virtual points are created:
insert image description here


2. Instantiate the edge collision box

In order for the object not to pass directly from the edge of the box when it is not operated at the beginning, we need to instantiate the collision box at the edge point first, the effect is as shown in the figure:
insert image description here

2.1 Calculation and generation of edge collision boxes

The following method calculates the edge position, and generates a collision box around the edge, and records the points into the above array, so that the collision box can be removed when painting later. Calculate the edge
position and generate code:

distancesX *= 3;
distancesY *= 3;
for (float x = -0.5f; x <= 0.5; x += distancesX)
{
    
    
    CreateBianKuan(new Vector3(x, -0.5f, 0));
    CreateBianKuan(new Vector3(x, 0.5f, 0));
    CreateBianKuan(new Vector3(-0.5f, x, 0));
    CreateBianKuan(new Vector3(0.5f, x, 0));
}
下面是具体生成的代码:
public void CreateBianKuan(Vector3 v3)
{
    
    
    Object obj = Resources.Load("MousePoint3");
    GameObject go = Instantiate(obj, Vector2.zero, Quaternion.Euler(Vector3.zero), target.transform) as GameObject;
    go.transform.localPosition = v3;
    go.transform.localScale = new Vector3(ColliderSize / scale.x, ColliderSize / scale.y, ColliderSize);
    PointData data = new PointData();
    data.pos = new Vector2(v3.x, v3.y);
    data.sta = pointStatic.collid;
    data.col = go;
    listPoint.Add(data);
}

"MousePoint3" is actually a circle with a collision box
insert image description here


3. Smudge part

After laying out so much in front, I finally got to the smearing part of the core.
As shown in the picture:
insert image description here

3.1. Virtual points

The densely packed in the picture are the virtual points that we have not created a collision box,

3.2. Mouse point

The black circle is where the mouse is clicked

3.3. Inner ring

Red is the inner circle, which is the position we need to dig. The points in this circle are:
1): If the status is dit and discarded, no processing will be done;
2): If the status is collid (with collision box), that is, if there is a collision box, then , destroy the collision box and change to die (abandoned)
3): If it is wait (waiting for processing), the state is changed to die (abandoned)

3.4. Outer ring

The blue circle is slightly larger than the red circle. This range is the position of the edge of our excavation. Then the points outside the red circle and within the blue circle:
1): If the status is dit, it will not be processed;
2): If the status is wait (waiting for processing), then Create a collision box and change it to collid (with a collision box)
3): If the state is collid, it will not be processed

The specific code is as follows, please refer to it:

public void WaDong()
{
    
    
    //创建一条射线一摄像机为原点
    Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
    RaycastHit hit;
    //射线碰撞到游戏地形时
    if (Physics.Raycast(ray, out hit))
    {
    
    
        //从世界坐标转为局部坐标
        Vector2 localCenter = target.transform.InverseTransformPoint(hit.point);
        for (int i = 0; i < listPoint.Count; i++)
        {
    
    
            Vector2 centerPos = listPoint[i].pos - localCenter;
            centerPos.x *= scale.x;
            centerPos.y *= scale.y;
            float dis = Vector2.Distance(centerPos, Vector2.zero);
            if (dis < Circle1Range1 && listPoint[i].sta != pointStatic.die)
            {
    
    
                listPoint[i].sta = pointStatic.die;
                if (listPoint[i].col != null)
                {
    
    
                    GameObject.Destroy(listPoint[i].col);
                }
             
            }
            else if (dis >= Circle1Range1 && dis < Circle1Range2 && listPoint[i].sta == pointStatic.wait)
            {
    
    
                listPoint[i].sta = pointStatic.collid;
                Object obj = Resources.Load("MousePoint3");
                GameObject go = Instantiate(obj, Vector2.zero, Quaternion.Euler(Vector3.zero), target.transform) as GameObject;
                go.transform.localPosition = listPoint[i].pos;
                go.transform.localScale = new Vector3(ColliderSize / scale.x, ColliderSize / scale.y, ColliderSize);
                listPoint[i].col = go;
            }
        }
    }
}


4. About optimization

Regarding optimization, we can start from several aspects, because the number of collision boxes is relatively large, and the creation and destruction are more frequent. This part can consider the object pool. On the other hand, the destroyed point does not need to be calculated again, because it can be considered to be
discarded The point of the point is moved out of the table.
Further optimization is left to everyone to think for themselves...


Conclusion:

This article mainly shares with you the idea of ​​realization, which is easy to say. At the beginning, a bunch of virtual points are created for inspection. The distance is calculated with the clicked position as the center of the circle. The small circle is the smeared position, and the large circle
is The edge position judges whether to add or delete collision points.
I hope it will be helpful to everyone. If you can help, please give a thumbs up, thank you.

Guess you like

Origin blog.csdn.net/ww1351646544/article/details/132289934