Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how can I determine if a square can reach position without contact with other sprites?

enter image description here

From the image above, given an initial position of b0(x, y), an end position of b1(x, y) and positions a(x, y) and c(x, y). How can I predetermine if square B0 will move from b0(x, y) to b1(x, y) without getting into contact with rectangle A and C? I believe that the angle will be needed.

like image 246
ItsMeAgain Avatar asked Jan 04 '16 01:01

ItsMeAgain


1 Answers

Some observations...

If box B's initial position is to the right of the ending position (in the gap), then the box can successfully move to the ending position without colliding with the other boxes only if theta is a counter-clockwise angle (see Figure below). For this test, use the box B's top-right corner and the bottom-left corner of C.

enter image description here

Similarly, If box B's initial position is to the left of the ending position, then it can successfully move to the ending position without colliding with the other boxes only if theta is a counter-clockwise angle (see Figure below). For this test, use the box B's top-left corner and the bottom-right corner of A.

enter image description here

Some code...

First, extend CGPoint to determine the corners of a box.

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)
    }
}

The following code allows the user to drop/drag box B. While the user moves the box, the code performs an on-the-fly test to see if the box can move into the gap without colliding with the other boxes.

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's 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)
    }
}

and a video clip...

enter image description here

Box B turns green if it can move into the gap without colliding and turns red if not.

like image 155
0x141E Avatar answered Nov 04 '22 10:11

0x141E