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

1

10

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.

Mongolic answered 4/1, 2016 at 1:4 Comment(15)
no angle is needed, you know your start box, and your end box, just make lines from each point on B0 to its respective point on B1, and see if these lines intersect with A or CJinny
@Jinny please I'm not sure how to just make lines from each point on B0 to its respective point on B1, and see if these lines intersect with A or C Mongolic
This is basic math, google how to make a line with 2 points, and how to check if a line intersects with a boxJinny
btw, the only way the box can get into the space is if it goes straight up, so technically, all you need to do is see if B0.x <> B1.x, then it will make contact before positioningJinny
@Jinny have you taken the gap between A and B1 and between B1 and C into consideration?Ptyalin
oh yeah, if the box is smaller then you need to do the formula, if the box fits perfectly you do not, @Ptyalin thanksJinny
How are the (relative) alignments and dimensions? Has A, B and C always the same height? Is A, B1 and C vertically centered (on a horizontal line)? Is B1 centered in the gap between A and C?Darden
@Darden yes, the height is always the same for each of them. Yes, each of them is centre aligned. Yes, B1 is centred in the gap.Mongolic
@Jinny all you need to do is see if B0.x <> B1.x. Where B0.x < ? > B1.x. I don't think it's that simple, as @Darden asked some important questions that have to be considered.Sacramentalism
@Sacramentalism my first comment handles qbytes question, your comment only asks if the box fits, my proposal will tell if a collision will happen if when b goes from 0 to 1Jinny
@Jinny okay, so basically, two lines at the corners from B0 to B1 can handle this.Sacramentalism
@NSSwift, if you were optimizing it, you would have to do whatever 2 corners would make the box the widest, so if the box is going in a top right direction, you would use the top left and bottom right corners of b.Jinny
@Jinny this is certainly not basic maths. I am reading about a cross product approach to finding the intersectionMongolic
It is basic, and i believe cgrect has it built in, but here is a post on SO that may help you. #16204260Jinny
I assume the box need to fit with a single motion in a straight line, right? You do not consider e.g. moving horizontally until it aligns with the hole and then forwards?Parmer
B
11

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.

Breed answered 5/1, 2016 at 22:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.