Unity2D implements UGUI scrolling mouse wheel to zoom the image centered on the mouse position point

 Let’s put the reference article first:

Unity3d UGUI scales images centered on the mouse position (including project source code) https://blog.csdn.net/qq_33789001/article/details/117749837

Then put it to achieve the effect:


Let’s talk about the reason. The project needed to use this effect, so I found a reference article online. Later, I didn’t know why it didn’t work, so I thought about changing it myself to see what the problem was.

Post the original code:

    //ZoomObj是需要缩放的UI
    private void ZoomImgByMousePos(GameObject ZoomObj)
    {
        //判断鼠标滚轮是否滚动
        if (Input.GetAxis("Mouse ScrollWheel") == 0)
            return;

        //一些变量的声明
        RectTransform RectTran = ZoomObj.GetComponent<RectTransform>();
        float PivotX = RectTran.pivot.x;
        float PivotY = RectTran.pivot.y;
        float OffsetX = 0f;
        float OffsetY = 0f;
        Vector2 addOffset;

        //获取轴心点在屏幕的坐标
        previewPosition = Camera.main.WorldToScreenPoint(RectTran.position);

        //获取鼠标坐标
        newPosition = Input.mousePosition;

        //计算偏差值
        addOffset = newPosition - previewPosition;

        //计算轴心点偏移量
        if (RectTran.rect.width != 0 && ZoomObj.transform.localScale.x != 0)
            OffsetX = addOffset.x / RectTran.rect.width / RectTran.localScale.x;
        if (RectTran.rect.height != 0 && ZoomObj.transform.localScale.y != 0)
            OffsetY = addOffset.y / RectTran.rect.height / RectTran.localScale.y;

        //计算轴心点新值
        RectTran.pivot += new Vector2(OffsetX, OffsetY);

        //计算UI新位置
        RectTran.anchoredPosition += addOffset;

        //放大UI
        if (Input.GetAxis("Mouse ScrollWheel") > 0)
            ZoomObj.transform.localScale += (ZoomObj.transform.localScale.x >= MaxScale - 0.1f ? Vector3.zero : Vector3.one * 0.1f);
        else if (Input.GetAxis("Mouse ScrollWheel") < 0)
            ZoomObj.transform.localScale += (ZoomObj.transform.localScale.x < MinScale + 0.1f ? Vector3.zero : Vector3.one * -0.1f);
    }

Comparing the original article, you can find that some changes have been made, including some bugs and implementation principles. I actually didn’t understand the original article very well. It omitted too much explanation, which made me, a math geek and a Unity novice, cry.

Explain the key code content. First, some variables need to be assigned values ​​within the script class. Please modify them yourself.

Get the coordinates of the pivot point on the screen

//获取轴心点在屏幕的坐标
previewPosition = Camera.main.WorldToScreenPoint(RectTran.position);

By converting the world coordinates of the UI into screen coordinates, the world coordinates of the UI seem to be where the pivot point of the UI is located in the world coordinates. Because the pivot point will not leave the screen, you can safely convert and obtain the value.

The reason why it is placed at the beginning is because the pivot point will shift when the UI is scaled later. This offset will not change after the UI scaling code block ends. There will be a delay. If it is placed at the end, it is likely that the changed value will not be captured.

Calculate deviation value

//计算偏差值
addOffset = newPosition - previewPosition;

Calculate the difference between the mouse position and the screen position of the pivot point

Calculate pivot point offset

//计算轴心点偏移量
if (RectTran.rect.width != 0 && ZoomObj.transform.localScale.x != 0)
    OffsetX = addOffset.x / RectTran.rect.width / RectTran.localScale.x;
if (RectTran.rect.height != 0 && ZoomObj.transform.localScale.y != 0)
    OffsetY = addOffset.y / RectTran.rect.height / RectTran.localScale.y;

The offset distance of the UI pivot point after scaling is calculated through the offset value. This offset distance is based on the mouse position, because the position of the pivot point is at the same position as the mouse by default. The unit distance of the screen coordinates is the same as the unit distance of the anchor coordinate system, so you can directly divide the offset value by the enlarged UI width and height to obtain the offset distance of the pivot point.

Calculate pivot point position

//计算轴心点新值
RectTran.pivot += new Vector2(OffsetX, OffsetY);

Move the pivot point to the mouse position

 Calculate UI position

//计算UI新位置
RectTran.anchoredPosition += addOffset;

The position of the UI must be added with an offset value. This position can be local coordinates or anchor coordinates. It seems that the movement of the pivot point of the UI will be accompanied by the movement of the UI position. If you do not add it, you will find that the UI will be offset by a certain distance from the predetermined coordinates after scaling. This multi-offset distance is the offset value calculated above. The specific logic is not clear, it should be set by the bottom layer of Unity.

2023/2/11 Update log

New projects need to use this function. As a result, I can find bugs when copying my own. I immediately became angry and compared and troubleshooted overnight to find out the problem.

  1. The initial values ​​of the Pivot of the Transform component that needs to scale the UI must be 0.5 and 0.5.
  2. The Anchor Presets of the Transform component that scales the UI must be the middle one

The settings are as follows:

2023/6/9 Update log

Some friends in the comments had a problem. I thought for a while that there might be people who are not very familiar with the UI, and I didn't clearly explain under what circumstances this code was used, so I would like to add a little bit.

This code is used with the Scroll View component. Scroll View cannot lock the X and Y axes. (Set up as shown below)

 

The ZoomObj in the code generally refers to the Content object in the Scroll View.


Summarize

  1. ZoomObj in the code generally refers to the Content object in Scroll View
  2. The initial values ​​of the Pivot of the Transform component (Content) that need to scale the UI must be 0.5 and 0.5
  3. The Anchor Presets of the Transform component that scales the UI must be the middle one

I'm ashamed to say that this article has a first version. I listed some possible problems, but I turned around and fell into a trap. In the first version, the screen size and the UI size were the same so that the desired effect could be achieved by luck. In fact, if the UI size was changed, something would go wrong. Then I spent a few more hours to fix the bug and revised this article. The content of this version should be correct.

In fact, this effect is not good enough. It feels like one card after another. In fact, it can be improved by reducing the scroll wheel value and using the coroutine loop to zoom several times to achieve the same effect. I think this will be smoother. Of course, It will take more configuration. But I'm too lazy, so I'll leave it to everyone to optimize it themselves.

It is recommended to experiment by yourself, change different places, and see the effect. It is difficult to understand just by looking at the code. If you have been working on Unity2D projects, you will encounter this problem sooner or later. Understanding it early can deepen your understanding of Unity components. Anyway, I didn't do it.

It would be best if Unity had built-in scaling functionality, why not?

Finally, I hope it can help friends who are in trouble, and I wish you all good luck.

Guess you like

Origin blog.csdn.net/weixin_49779414/article/details/127498521