如何在Unity中创建一个可缩放的移动端画布图像,而不需要对主摄像机进行缩放?

4
我在我的画布中有一个带有滚动矩形和矩形遮罩的游戏对象,并且其中有一个图像。 我想对该图像进行放大和缩小。 但是,我不想缩放主摄像机,因为屏幕上会有其他对象,我不想进行缩放。 我搜索了它,但所有教程都是通过缩放主摄像机来完成的。
这个视频正是我想要的,但在Android上无法工作。 https://www.youtube.com/watch?v=BFX3FpUnoio&ab_channel=JasonWeimann

enter image description here

这是视频中添加到“image”的脚本。我尝试修改它,但把它搞砸了。如何使它在移动设备上工作?

using UnityEngine;
using UnityEngine.EventSystems;

public class UIZoomImage : MonoBehaviour, IScrollHandler
{
    private Vector3 initialScale;

    [SerializeField]
    private float zoomSpeed = 0.1f;
    [SerializeField]
    private float maxZoom = 10f;

    private void Awake()
    {
        initialScale = transform.localScale;
    }

    public void OnScroll(PointerEventData eventData)
    {
        var delta = Vector3.one * (eventData.scrollDelta.y * zoomSpeed);
        var desiredScale = transform.localScale + delta;

        desiredScale = ClampDesiredScale(desiredScale);

        transform.localScale = desiredScale;
    }

    private Vector3 ClampDesiredScale(Vector3 desiredScale)
    {
        desiredScale = Vector3.Max(initialScale, desiredScale);
        desiredScale = Vector3.Min(initialScale * maxZoom, desiredScale);
        return desiredScale;
    }
}

-------更新---------

我在Unity论坛中找到了这个:https://answers.unity.com/questions/1280592/pinch-and-zoom-functionality-on-canvas-ui-images.html

它几乎可以工作,但我需要捏屏幕2-3次才能缩放。第一次触摸没有反应。这太烦人了。我尝试更改_minZoom、_maxZoom、速度和灵敏度值,但没有效果。

这是脚本:

using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 public class PinchableScrollRect : ScrollRect
 {
     [SerializeField] float _minZoom = .1f;
     [SerializeField] float _maxZoom = 10;
     [SerializeField] float _zoomLerpSpeed = 10f;
     float _currentZoom = 1;
     bool _isPinching = false;
     float _startPinchDist;
     float _startPinchZoom;
     Vector2 _startPinchCenterPosition;
     Vector2 _startPinchScreenPosition;
     float _mouseWheelSensitivity = 1;
     bool blockPan = false;
 
     protected override void Awake()
     {
         Input.multiTouchEnabled = true;
     }
 
     private void Update()
     {
         if (Input.touchCount == 2)
         {
             if (!_isPinching)
             {
                 _isPinching = true;
                 OnPinchStart();
             }
             OnPinch();
         }
         else
         {
             _isPinching = false;
             if (Input.touchCount == 0)
             {
                 blockPan = false;
             }
         }
         //pc input
         float scrollWheelInput = Input.GetAxis("Mouse ScrollWheel");
         if (Mathf.Abs(scrollWheelInput) > float.Epsilon)
         {
             _currentZoom *= 1 + scrollWheelInput * _mouseWheelSensitivity;
             _currentZoom = Mathf.Clamp(_currentZoom, _minZoom, _maxZoom);
             _startPinchScreenPosition = (Vector2)Input.mousePosition;
             RectTransformUtility.ScreenPointToLocalPointInRectangle(content, _startPinchScreenPosition, null, out _startPinchCenterPosition);
             Vector2 pivotPosition = new Vector3(content.pivot.x * content.rect.size.x, content.pivot.y * content.rect.size.y);
             Vector2 posFromBottomLeft = pivotPosition + _startPinchCenterPosition;
             SetPivot(content, new Vector2(posFromBottomLeft.x / content.rect.width, posFromBottomLeft.y / content.rect.height));
         }
         //pc input end
 
         if (Mathf.Abs(content.localScale.x - _currentZoom) > 0.001f)
             content.localScale = Vector3.Lerp(content.localScale, Vector3.one * _currentZoom, _zoomLerpSpeed * Time.deltaTime);
     }
 
     protected override void SetContentAnchoredPosition(Vector2 position)
     {
         if (_isPinching || blockPan) return;
         base.SetContentAnchoredPosition(position);
     }
 
     void OnPinchStart()
     {
         Vector2 pos1 = Input.touches[0].position;
         Vector2 pos2 = Input.touches[1].position;
 
         _startPinchDist = Distance(pos1, pos2) * content.localScale.x;
         _startPinchZoom = _currentZoom;
         _startPinchScreenPosition = (pos1 + pos2) / 2;
         RectTransformUtility.ScreenPointToLocalPointInRectangle(content, _startPinchScreenPosition, null, out _startPinchCenterPosition);
 
         Vector2 pivotPosition = new Vector3(content.pivot.x * content.rect.size.x, content.pivot.y * content.rect.size.y);
         Vector2 posFromBottomLeft = pivotPosition + _startPinchCenterPosition;
 
         SetPivot(content, new Vector2(posFromBottomLeft.x / content.rect.width, posFromBottomLeft.y / content.rect.height));
         blockPan = true;
     }
 
     void OnPinch()
     {
         float currentPinchDist = Distance(Input.touches[0].position, Input.touches[1].position) * content.localScale.x;
         _currentZoom = (currentPinchDist / _startPinchDist) * _startPinchZoom;
         _currentZoom = Mathf.Clamp(_currentZoom, _minZoom, _maxZoom);
     }
 
     float Distance(Vector2 pos1, Vector2 pos2)
     {
         RectTransformUtility.ScreenPointToLocalPointInRectangle(content, pos1, null, out pos1);
         RectTransformUtility.ScreenPointToLocalPointInRectangle(content, pos2, null, out pos2);
         return Vector2.Distance(pos1, pos2);
     }
 
     static void SetPivot(RectTransform rectTransform, Vector2 pivot)
     {
         if (rectTransform == null) return;
 
         Vector2 size = rectTransform.rect.size;
         Vector2 deltaPivot = rectTransform.pivot - pivot;
         Vector3 deltaPosition = new Vector3(deltaPivot.x * size.x, deltaPivot.y * size.y) * rectTransform.localScale.x;
         rectTransform.pivot = pivot;
         rectTransform.localPosition -= deltaPosition;
     }
 }

为什么你的方法ClamDesiredScale会计算两次desiredScale?第二个赋值覆盖了第一个,所以第一行desiredScale = Vector3.Max(initialScale, desiredScale); 没有意义。 - Windgate
这不是我的方法。我从视频中获取了脚本:https://www.youtube.com/watch?v=BFX3FpUnoio&ab_channel=JasonWeimann 它在电脑上完美运行,但在Android上无法运行。我需要为移动设备更改脚本,但我无法做到。 - Serkan Tarakcı
2个回答

1

如果相机投影设置为正交,则此脚本可以解决问题。来自this源代码。

 using UnityEngine;
 
 public class Zoom : MonoBehaviour {
 
 public float zoomSpeed = 1;
 public float targetOrtho;
 public float smoothSpeed = 2.0f;
 public float minOrtho = 1.0f;
 public float maxOrtho = 20.0f;
 
 void Start() {
     targetOrtho = Camera.main.orthographicSize;
 }
 
 void Update () {
     
     float scroll = Input.GetAxis ("Mouse ScrollWheel");
     if (scroll != 0.0f) {
         targetOrtho -= scroll * zoomSpeed;
         targetOrtho = Mathf.Clamp (targetOrtho, minOrtho, maxOrtho);
     }
     
     Camera.main.orthographicSize = Mathf.MoveTowards (Camera.main.orthographicSize, targetOrtho, smoothSpeed * Time.deltaTime);
 }

}


1
谢谢,但这不是在缩放相机吗?我不想缩放相机。我只想缩放游戏对象中具有滚动矩形和遮罩的图像。@rustyBucketBay - Serkan Tarakcı

1
为什么你不对图像进行缩放?!

是的,我已经想在Android上通过捏放来缩放图像。我该怎么做呢?我在Unity社区中找到了这个链接:https://answers.unity.com/questions/1280592/pinch-and-zoom-functionality-on-canvas-ui-images.html它几乎可以工作,但问题是不够流畅。我的意思是需要在屏幕上捏两三次才能缩放。第一次触摸没有任何反应 :( - Serkan Tarakcı

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接