Swift UIBezierPath Другая начальная точка координат - PullRequest
0 голосов
/ 17 января 2020

У меня есть стрелка UIBezierPath, которую я нашел здесь . Моя цель - передать функции addArrows список массивов игроков и нарисовать стрелки между ними. Этот код прекрасно работает ... кроме случаев, когда я звоню addArrows(gameScene: scene, from: [1, 3], to: [1, 3]) или addArrows(gameScene: scene, from: [2, 3], to: [2, 3]). Это должно создать стрелки между игроками 1 и 3 (1-й вызов) и 2 и 3 (2-й вызов). Тем не менее, он создает стрелки между игроками 2 и 3 (первый звонок) и игроками 1 и 3 (второй звонок). Я добавил операторы печати в функцию «addArrows», и она корректно возвращает местоположения (расположенные в моей структуре констант) игроков. Он работает, если ему подают массив из [1, 2, 3] и [1, 2, 3] или [1, 2] и [1, 2]. Что именно здесь происходит?

struct K {
static let stackPositions = [
    // Player 1
    1: CGPoint(x: (_screenW / 2), y: cardHeightConstant + cardHeight + 60),
    // Player 2
    2: CGPoint(x: (_screenW / 2), y: _screenH - cardHeightConstant - cardHeight - 60),
    // Player 3
    3: CGPoint(x: 30, y: _screenH / 2),
    // Player 4
    4: CGPoint(x: _screenW - 30, y: _screenH / 2)
]
}

// https://stackoverflow.com/questions/48625763/how-to-draw-a-directional-arrow-head
extension UIBezierPath {
func addArrow(start: CGPoint, end: CGPoint, pointerLineLength: CGFloat, arrowAngle: CGFloat) {
    self.move(to: start)
    self.addLine(to: end)

    let startEndAngle = atan((end.y - start.y) / (end.x - start.x)) + ((end.x - start.x) < 0 ? CGFloat(Double.pi) : 0)
    let arrowLine1 = CGPoint(x: end.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle + arrowAngle), y: end.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle + arrowAngle))
    let arrowLine2 = CGPoint(x: end.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle - arrowAngle), y: end.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle - arrowAngle))

    self.addLine(to: arrowLine1)
    self.move(to: end)
    self.addLine(to: arrowLine2)
}
}

func addArrows(gameScene: GameScene, from: [Int], to: [Int]) {

for fromPlayerNumber in from {
    for toPlayerNumber in to {
        guard let fromPos = K.stackPositions[fromPlayerNumber] else { return }
        guard let toPos = K.stackPositions[toPlayerNumber] else { return }
        if fromPos == toPos { continue }

        print(fromPos.y)
        print(toPos.y)
        let arrow = UIBezierPath()
        arrow.addArrow(start: CGPoint(x: fromPos.x, y: fromPos.y),
                       end: CGPoint(x: toPos.x, y: toPos.y),
                       pointerLineLength: 7,
                       arrowAngle: CGFloat(Double.pi / 4))

        let arrowLayer = CAShapeLayer()
        arrowLayer.strokeColor = UIColor.black.cgColor
        arrowLayer.lineWidth = 1.0
        arrowLayer.path = arrow.cgPath
        arrowLayer.fillColor = UIColor.clear.cgColor
        arrowLayer.lineJoin = CAShapeLayerLineJoin.round
        arrowLayer.lineCap = CAShapeLayerLineCap.round
        gameScene.view?.layer.addSublayer(arrowLayer)
    }
}

}

Редактировать

Я установил для местоположения «От» значение CGPoint(x: 0, y: 0). Это начинает стрелку в верхней левой части экрана, а не все мои другие ссылки, которые начинаются в левом нижнем углу экрана. Итак, похоже, что стрелка использует точку привязки, отличную от других объектов в моей сцене. Я попытался установить arrowLayer.anchorPoint = CGPoint(x: 0, y: 0), но это не сработало ...

1 Ответ

0 голосов
/ 05 февраля 2020

Здесь система координат ссылалась на верхний левый угол экрана, а не на нижний левый. Чтобы это исправить, все, что мне нужно было сделать, это «инвертировать» координаты y начальной и конечной точек y. Исправить ниже:

    func addArrow(start: CGPoint, end: CGPoint, pointerLineLength: CGFloat, arrowAngle: CGFloat) {

        // Adjust Y Directions Here! // 
        let adjStart = CGPoint(x: start.x, y: K._screenH - start.y)
        let adjEnd = CGPoint(x: end.x, y: K._screenH - end.y)

        self.move(to: adjStart)
        self.addLine(to: adjEnd)

        let startEndAngle = atan((adjEnd.y - adjStart.y) / (adjEnd.x - adjStart.x)) + ((adjEnd.x - adjStart.x) < 0 ? CGFloat(Double.pi) : 0)
        let arrowLine1 = CGPoint(x: adjEnd.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle + arrowAngle),
                                 y: adjEnd.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle + arrowAngle))
        let arrowLine2 = CGPoint(x: adjEnd.x + pointerLineLength * cos(CGFloat(Double.pi) - startEndAngle - arrowAngle),
                                 y: adjEnd.y - pointerLineLength * sin(CGFloat(Double.pi) - startEndAngle - arrowAngle))

        self.addLine(to: arrowLine1)
        self.move(to: adjEnd)
        self.addLine(to: arrowLine2)
    }
...