Войти
UnityФорумПрограммирование

Как в Unity свайпом переместить объект на заданное расстояние?

#0
1:03, 15 апр 2022

Ребята, подскажите, как плавно переместить куб свайпом по оси X на 1 шаг?
Куб имеет Scale 1. Нужно его передвинуть на расстояние равно этому кубу, или на один поинт.
Вот такой код написал, но не работает как надо.

  void Update()
  {   
           if (Input.touchCount == 1)
            {
                Touch screenTouch = Input.GetTouch(0);

                if (screenTouch.phase == TouchPhase.Moved)
                                      
                  transform.position = Vector3.Lerp(transform.position, new Vector3 (screenTouch.deltaPosition.normalized.x, transform.position.y, transform.position.z) speed * Time.deltaTime);
                
     }
}


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

#1
9:19, 15 апр 2022

Так если тебе надо конкретное перемещение, то зачем ты берешь вообще deltaPosition в расчет?

Перемещай сразу на нужное расстояние, как только TouchPhase.Moved обнаружил.

#2
11:22, 15 апр 2022

Increaser
Ну на самом деле мне нужно двигать куб или в лево, или в право, в зависимости от свайпа, по-этому использовал нормализованную дельту. Но как оказалась, она мне Не возвращает почему-то единицу.
Но и это не главное. Проблема что перемещение выполнялось постоянно пока есть свайп, а нужно разовое выполнение кода. Переписал код, но все равно не получается строго на единицу двигаться:

void Update()
  {   
           if (Input.touchCount == 1)
            {
                Touch screenTouch = Input.GetTouch(0);
                if (screenTouch.phase == TouchPhase.Moved)     
                  
                        if (Mathf.Abs(screenTouch.deltaPosition.magnitude) > 1)
                        targetPosition = transform.position;
                        targetPosition.x += 1f * screenTouch.deltaPosition.normalized.x ;
             }

   transform.position = Vector3.MoveTowards(transform.position, targetPosition, Time.deltaTime * 2);
  }

Короче точное перемещение не получается. А в итоге нужно еще что бы движение было и влево  и вправо. По идеи это решилось бы так: 
targetPosition.x += 1f * screenTouch.deltaPosition.normalized.x;
где screenTouch.deltaPosition.normalized.x давал бы мне единицу с плюсом или с минусом, но что-то работает не так, и перемещение не точное

#3
11:44, 15 апр 2022

Попробовал сделать так 
targetPosition.x += Mathf.Sign(screenTouch.deltaPosition.x);

Mathf.Sign - возвращает положительную или отрицательную единицу.
Но во время одного свайпа в апдейте эта строчка успеваете выполнится много раз, а нужно один раз за свайп

#4
11:48, 15 апр 2022

Ну так добавь флаг какой-нибудь. Как movePhase началась, ставишь флаг в false и до тех пор, пока пользователь не отпустит руку, не сбрасываешь его.

Так у тебя код только один раз выполнится, сколько бы не длился свайп.

#5
11:51, 15 апр 2022

Increaser
Дружище, можешь написать пример кода? Я сам не соображу

#6
(Правка: 12:41) 12:30, 15 апр 2022

Что-то такое. Это, конечно, уродство, но для иллюстрации идеи пойдет.

public sealed class MoveSample : MonoBehaviour
{
    private bool _isMoving;
    private Vector3 _targetPosition;

    private void Update()
    {
        if (_isMoving)
        {
            return;
        }

        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
        {
            _isMoving = true;
        
            if (Input.GetTouch(0).deltaPosition.x > 0)
            {
                _targetPosition = new Vector3(transform.position.x + 1, transform.position.y, transform.position.z);
                StartCoroutine(MoveRight());
            }
            else
            {
                _targetPosition = new Vector3(transform.position.x - 1, transform.position.y, transform.position.z);
                StartCoroutine(MoveLeft());
            }
        }
    }

    private IEnumerator MoveRight()
    {
        while (transform.position != _targetPosition)
        {
            var targetX = transform.position.x + Time.deltaTime;
            if (targetX > _targetPosition.x)
            {
                targetX = _targetPosition.x;
            }
            transform.position = new Vector3(targetX, transform.position.y,
                transform.position.z);
            yield return null;
        }

        _isMoving = false;
    }
    
    private IEnumerator MoveLeft()
    {
       //аналогично
    }
}
#7
(Правка: 12:47) 12:42, 15 апр 2022

Вообще рекомендую для всяких движений использовать твинер, например вот этот, чтобы не городить кастомные велосипеды там где это не надо
https://assetstore.unity.com/packages/tools/animation/dotween-hotween-v2-27676

Тогда весь стриптиз выше превратится в что-то более удобоваримое

public sealed class MoveSample : MonoBehaviour
{
    private bool _isMoving;

    private void Update()
    {
        if (_isMoving)
        {
            return;
        }

        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
        {
            _isMoving = true;
            var delta = Mathf.Sign(Input.GetTouch(0).deltaPosition.x);
            var targetPosition = new Vector3(transform.position.x + delta, transform.position.y, transform.position.z);
            transform.DOMove(targetPosition, 1f)
                .OnComplete(() => _isMoving = false);
        }
    }
}
#8
13:11, 15 апр 2022

Increaser
Дружище, спасибо огромное! Жму руку!

#9
16:11, 15 апр 2022

Increaser
Собрал сцену, все работает. Осталось только сделать так, что бы одни кубы могли двигаться только по X, другие по Z, и что бы не наезжали на друг друга. Еще раз спасибо!

Подскажи, а можно сделать движение от слабого свайпа на 1 шаг, а от сильного на 2 шага?

#10
19:19, 15 апр 2022

Vadimicus
Слабого по скорости или по расстоянию?

#11
20:32, 15 апр 2022


Increaser
> Слабого по скорости или по расстоянию?

По расстоянию

#12
14:51, 16 апр 2022

Ну в таком случае можно считать расстояние deltaPosition и при достижении конца первого движения добавить еще одно передвижение. Если ты использовал второй вариант, то по достижении OnComplete можешь передать туда функцию проверки, которая в случае превышения порога повторит тот же самый код со сдвигом.

Если первый вариант, то там можно targetPosition сделать переменной уровня класса, и в апдейте смотреть дельту. Если она превысила порог, то добавить еще единицу к targetPosition.x

UnityФорумПрограммирование