Неожиданное ускорение в пользовательском поведении UIFieldBehavior - PullRequest
0 голосов
/ 20 мая 2018

Я создаю настраиваемое поле для замедления движения объектов после того, как пользователь выполняет жест панорамирования.Использование нормального трения заставляет объекты чувствовать себя слишком скользкими, поэтому я пытаюсь применить физику пружин вместо трения.

У меня есть функция, которая, кажется, правильно рассчитывает поведение, которое я ищу.

extension UIFieldBehavior {
    static func dampingField(_ constant: CGFloat) -> UIFieldBehavior {
        return UIFieldBehavior.field { field, position, velocity, mass, charge, time in
            let speed = sqrt(pow(velocity.dx, 2) + pow(velocity.dy, 2))
            let angle = acos(velocity.dx / speed)
            let force = -constant * speed
            guard angle.isNaN == false, force.isNaN == false
                else { return .zero }
            return  CGVector(dx: cos(angle) * force, dy: sin(angle) * force)
        }
    }
}

Однако вертикальное движение ведет себя не так, как я ожидал.Любое движение в сторону верхней эталонного зрения причиняет объект для ускорения быстрее.

1007 * Я играл с тригонометрии на некоторое время, но я в тупик. пример быстрой игровой площадки на GitHub, демонстрирующий эту проблему.

Что я пропускаю в своей математике?

1 Ответ

0 голосов
/ 22 мая 2018

Ответ буквально пришел ко мне во сне, смеется.

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

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

var vector = CGVector(dx: cos(angle) * force, dy: sin(angle) * force)
if vector.dy.sign == velocity.dy.sign {
    vector.dy *= -1
}
return vector

ПопыткаЧтобы обдумать, почему только компонент y был неправильно подписан, я заметил, что угол был вычислен относительно оси x.

let angle = acos(velocity.dx / speed)

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

return CGVector(dx: cos(angle) * force, dy: sin(asin(velocity.dy / speed)) * force)

Подумав немного, я понял, что, поскольку asin и acos являютсяв обратном порядке к sin и cos, соответственно, код можно уменьшить, чтобы полностью исключить использование sin и cos.

return CGVector(dx: velocity.dx / speed * force, dy: velocity.dy / speed * force)

Действительно, хотя мне это и не нужнопривести тригонометрию в это вообще, так как операции над компонентами векторов эквивалентны операциям над самим вектором.Теперь моя сила работает, как ожидалось, и о ней проще рассуждать.

extension UIFieldBehavior {
    static func dampingField(_ constant: CGFloat) -> UIFieldBehavior {
        return UIFieldBehavior.field { field, position, velocity, mass, charge, time in
            return  CGVector(dx: -constant * velocity.dx, dy: -constant * velocity.dy)
        }
    }
}
...