Я хочу нарисовать Луну, а затем оживить тень Луны. Но после запуска этого кода я вижу некоторые сбои в строке анимации: введите описание изображения здесь

GIF: введите описание изображения здесь

Почему это происходит?

Код игровой площадки здесь

Обновление 1: оба пути, созданные этой функцией, но под разными углами (0 и π / 2 * 0,6):

func calculateMoonPath(for angle: CGFloat) -> UIBezierPath {
    let center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
    let radius = view.bounds.height/2
    
    let path = UIBezierPath(arcCenter: center,
                            radius: radius,
                            startAngle: -.pi/2,
                            endAngle: .pi/2,
                            clockwise: true)
    path.addArc(withCenter: .init(x: center.x - radius * tan(angle), y: center.y),
                radius: radius / CGFloat(cosf(Float(angle))),
                startAngle: .pi/2 - angle,
                endAngle: angle - .pi/2,
                clockwise: false
    )
    path.close()
    return path
}
2
Robot Bender 12 Окт 2021 в 21:31

2 ответа

Лучший ответ

По моему опыту, код, который генерирует дуги, создает различное количество кубических кривых Безье под крышками при изменении угла дуги.

Это изменит количество контрольных точек на двух кривых и испортит анимацию. (как говорит Дэвид Рённквист, анимация не определена, если начальный и конечный путь имеют разное количество контрольных точек.)

Из того, что я читал, полный круг требует для завершения 4 кубических кривых Безье.

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

Вероятно, вы могли бы разбить свою дугу на 4 части (используя 4 последовательных вызова addArc(withCenter:...) с разными начальными и конечными углами, чтобы они объединялись, чтобы получить желаемую полную дугу. Каждая из них должна быть достаточно короткой длины дуги, чтобы быть одной Кривая Безье, поэтому вы должны получить одинаковое количество контрольных точек для начальной и конечной комбинированной кривой.

Если вы перепишете свою функцию calculateMoonPath следующим образом:

func calculateMoonPath(for angle: CGFloat) -> UIBezierPath {
    let center = CGPoint(x: view.bounds.midX, y: view.bounds.midY)
    let radius = view.bounds.height/2

    let path = UIBezierPath(arcCenter: center,
                            radius: radius,
                            startAngle: -.pi/2,
                            endAngle: .pi/2,
                            clockwise: true)
    let startAngle = .pi/2 - angle
    let endAngle = angle - .pi/2
    let delta = (endAngle - startAngle) / 4
    for index in 0...3 {
        let thisStart = startAngle + delta * CGFloat(index)
        let thisEnd = startAngle + delta * CGFloat(index + 1)
        path.addArc(withCenter: .init(x: center.x - radius * tan(angle), y: center.y),
                    radius: radius / CGFloat(cosf(Float(angle))),
                    startAngle: thisStart,
                    endAngle: thisEnd,
                    clockwise: false
        )
    }
    path.close()
    return path
}

Это дает следующее:

enter image description here

3
Duncan C 13 Окт 2021 в 02:08

То, как вы выполняете каждую из двух строк,

Просто две контрольные точки!

По одному на каждом конце.

Вот и все. Не пытайтесь использовать дугу.

Вот ...

https://www.desmos.com/calculator/cahqdxeshd

1
Fattie 13 Окт 2021 в 02:14