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

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

Из приведенного выше изображения, учитывая начальную позицию b0 (x, y), конечную позицию b1 (x, y) и положения a (x, y) и c (x, y). Как можно определить, будет ли квадрат B0 перемещаться от b0 (x, y) до b1 (x, y), не вступая в контакт с прямоугольником A и C? Я считаю, что угол будет необходим.

Ответ 1

Некоторые наблюдения...

Если исходное положение коробки B находится справа от конечной позиции (в промежутке), тогда поле может успешно переместиться в конечное положение, не сталкиваясь с другими полями, только если theta - против часовой стрелки (см. рис. ниже). Для этого теста используйте поле B в правом верхнем углу и нижний левый угол C.

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

Аналогично, если начальная позиция окна B находится слева от конечной позиции, то она может успешно перейти в конечную позицию, не сталкиваясь с другими полями, только если theta - против часовой стрелки (см. рисунок ниже). Для этого теста используйте поле B в верхнем левом углу и в нижнем правом углу A.

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

Некоторые коды...

Сначала растяните CGPoint, чтобы определить углы поля.

extension CGPoint {
    func bottomLeftCorner(size:CGSize) -> CGPoint {
        return CGPoint (x:x - size.width/2.0, y:y - size.height/2.0)
    }

    func bottomRightCorner(size:CGSize) -> CGPoint {
        return CGPoint(x:x + size.width/2.0, y:y - size.height/2.0)
    }

    func topLeftCorner(size:CGSize) -> CGPoint {
        return CGPoint (x:x - size.width/2.0, y:y + size.height/2.0)
    }

    func topRightCorner(size:CGSize) -> CGPoint {
        return CGPoint(x:x + size.width/2.0, y:y + size.height/2.0)
    }
}

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

class GameScene: SKScene {

    let size1 = CGSize(width: 100, height: 50)
    let size2 = CGSize(width: 50, height: 50)
    let size3 = CGSize(width: 100, height: 50)

    var boxA:SKSpriteNode!
    var boxB:SKSpriteNode!
    var boxC:SKSpriteNode!

    var center:CGPoint!

    override func didMove(to view: SKView) {

        // This is box B ending position
        center = CGPoint (x:0,y:0)

        // Define and add the boxes to the scene
        boxA = SKSpriteNode(color: SKColor.yellow, size: size1)
        boxB = SKSpriteNode(color: SKColor.red, size: size2)
        boxC = SKSpriteNode(color: SKColor.blue, size: size3)

        boxA.position = CGPoint(x: -size1.width, y: 0)
        boxB.position = CGPoint(x: 0, y: 0)
        boxC.position = CGPoint(x: size3.width, y: 0)

        boxB.zPosition = 1

        addChild(boxA)
        addChild(boxB)
        addChild(boxC)
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in touches {
            let location = touch.location(in: self)

            // Allow user to drag box to a new location
            boxB.position = location

            // Find the appropriate corners
            var cornerA:CGPoint!
            var cornerB:CGPoint!
            var cornerC:CGPoint!
            if (boxB.position.x < center.x) {
                cornerA = boxA.position.bottomRightCorner(size: boxA.size)
                cornerB = boxB.position.topLeftCorner(size: boxB.size)
                cornerC = center.topLeftCorner(size: boxB.size)
            }
            else {
                cornerA = center.topRightCorner(size: boxB.size)
                cornerB = boxB.position.topRightCorner(size: boxB.size)
                cornerC = boxC.position.bottomLeftCorner(size: boxC.size)
            }
            // Test if box B can move in the gap without colliding
            if isCounterClockwise(A: cornerA, B: cornerB, C: cornerC) {
                boxB.color = SKColor.green
            }
            else {
                boxB.color = SKColor.red
            }
        }
    }

    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        // Move box B to the ending position
        let action = SKAction.move(to: center, duration: 2)
        boxB.run(action)
    }

    // Test direction of angle between line segments AB and AC
    func isCounterClockwise (A:CGPoint, B:CGPoint, C:CGPoint) -> Bool {
        return (C.y-A.y)*(B.x-A.x) > (B.y-A.y)*(C.x-A.x)
    }
}

и видеоклип...

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

Вставка B становится зеленой, если она может перемещаться в промежуток без столкновения и становится красной, если нет.