Как получить разницу в ширине между холстом и масштабированным изображением и сделать эффективный эффект PingPong в Unity3D - PullRequest
1 голос
/ 13 февраля 2020

Я пытаюсь получить разницу в ширине между холстом и изображением, которое масштабируется на CanvasScaler, чтобы создать перевод между изображением и его границей.

Иллюстрация: Illustration

Как получить размер красной стрелки?

[РЕДАКТИРОВАТЬ 1]

Фрагмент кода ниже дай мне возможный правильный результат

var dist = (canvasRectTransform.rect.width - image.sprite.rect.width) / 2;

Но, похоже, он неверный:

public class Background : Monobehaviour 
{
        private float dist;
        private float _percentage;
        private float _currentLerpTime;`
        private readonly Dictionary<LerpDirection, Func<Vector3>> _lerpDirectionActions;

        public float lerpTime;

        void Awake()
        {
            var image = GetComponent<Image>();
            var canvasRectTransform = GetComponentInParent<RectTransform>();
            dist  = (canvasRectTransform.rect.width - image.sprite.rect.width) / 2;
            _lerpDirectionActions = new Dictionary<LerpDirection, Func<Vector3>>
            {
                [LerpDirection.Left] = LerpToLeft, 
                [LerpDirection.Right] = LerpToRight
            };
        }

        private Vector3 Lerp()
        {
            return Vector3.Lerp(
                transform.position, 
                _lerpDirectionActions[lerpDirection].Invoke(), // will call LerpToRight or LerpToLeft
                _percentage
            );
        }

        private float LerpX => Lerp().x;


        private Vector3 LerpToRight()
        {
            return new Vector3(transform.position.x - dist, transform.position.y);
        }

        private Vector3 LerpToLeft()
        {
            return new Vector3(transform.position.x + dist , transform.position.y);
        }

        void Update() 
        {

             _currentLerpTime += Time.deltaTime;
             _percentage = _currentLerpTime / lerpTime;
             var localPositionX = tranform.position.x;

             var mustGoRight = localPositionX <= 0 && lerpDirection == LerpDirection.Right;
             var mustGoLeft = localPositionX >= dist && lerpDirection  == LerpDirection.Left;

             if (mustGoLeft || mustGoRight)
             {
                direction = direction.Invert(); // invert direction
                Reset();
             }

             tranform.position =  new Vector3(LerpX, tranform.position.y)
        }

}

Сценарий Background применяется к Background GameObject.

_lerpDirectionActions[lerpDirection].Invoke()

этот код выше будет вызывать правую функцию для рыскания слева или справа.

Иллюстрация: issue

Перевод меняет направление, но не тогда, когда холст находится на границе изображения.

1 Ответ

2 голосов
/ 13 февраля 2020

Значение, которое вы ищете, будет

var difference = (canvas.GetComponent<RectTransform>().rect.width - image.GetComponent<RectTransform>().rect.width) / 2f;

Если честно, ваш сценарий выглядит довольно сложным.

Почему бы просто не сложить все в один Coroutine используя Mathf.PingPong, который делает именно то, что вы в настоящее время контролируете своими флагами направления и действиями

PingPongs значение t, чтобы оно никогда не превышало длину и никогда не уменьшалось чем 0.

Возвращаемое значение будет перемещаться вперед и назад между 0 и длиной.

public Canvas canvas;
public Image image;

// Time in seconds to finish the movement from one extreme to the other
public float duration = 1;

private void Start()
{
    StartCoroutine (LerpForthAndBack());
}

private IEnumerator LerpForthAndBack()
{
    var difference = (canvas.GetComponent<RectTransform>().rect.width - image.GetComponent<RectTransform>().rect.width) / 2f;

    var maxPosition = Vector3.right * difference;
    var minPosition = Vector3.left * difference;

    // Hugh? :O
    // -> This is actually totally fine in a Coroutine
    //    as long as you yield somewhere within it
    while(true)
    {
        image.transform.position = Vector3.Lerp(minPosition, maxPosition, Mathf.PingPong(Time.time / duration, 1));

        // "Pause" the routine, render the frame and
        // and continue from here in the next frame
        yield return null;
    }
}

Конечно, вы можете сделать то же самое еще в Update

private Vector3 minPosition;
private Vector3 maxPosition;

private void Start()
{
    var difference = (canvas.GetComponent<RectTransform>().rect.width - image.GetComponent<RectTransform>().rect.width) / 2f;

    maxPosition = Vector3.right * difference;
    minPosition = Vector3.left * difference;
}

private void Update()
{
    image.transform.position = Vector3.Lerp(minPosition, maxPosition, Mathf.PingPong(Time.time / duration, 1));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...