CGRectIntersectsRect逻辑不准确

时间:2011-11-20 01:40:50

标签: objective-c cocoa-touch cgrect

在应用程序中,我每次运行时都会向广场提供随机帧。我用这个逻辑来确保

a)每个方格都不太靠近玩家 和
b)每个方块都包含在屏幕视图内 c)没有方块接触任何其他方块

for(UIButton* button in squareArray) {
    BOOL shouldContinue = YES;
    do {
        int randX = arc4random() % 321;
        int randY = arc4random() % 481;
        button.frame = CGRectMake(randX, randY, button.frame.size.width, button.frame.size.height);
        CGRect playerRect = CGRectMake(100, 180, 120, 120);
        for(UIButton* b in squareArray)
            if(!CGRectIntersectsRect(b.frame, button.frame) && 
                !CGRectIntersectsRect(button.frame, playerRect) && 
                CGRectContainsRect(self.view.frame, button.frame)) {
                shouldContinue = NO;
            }
    } while (shouldContinue);
}

使用这段代码,我希望squareArray中的每个正方形(一旦循环完成)完全位于视图边界内,不与数组中的任何其他按钮相交,并完全超出边界playerRect rect,在屏幕中央是一个120 x 120的正方形。我的代码错了吗?因为我没有这些功能。

编辑:我确实得到了这个方法的一个理想特征:没有正方形与playerRect相交。但是我仍然得到彼此重叠的正方形和部分偏离视野的正方形。

编辑2:

我对嵌套for循环进行了这些更改:

for(UIButton* b in squareArray)
            if(![b isEqual:button]) {
                if(CGRectIntersectsRect(b.frame, button.frame) || 
                   CGRectIntersectsRect(button.frame, playerRect) || 
                   !CGRectContainsRect(CGRectMake(10, 10, 300, 460), button.frame))
                    shouldContinue = YES;
                else
                    shouldContinue = NO;
            }

现在,方块总是在视图的稍微修改(较小)的矩形内,并且它们从不与玩家方块相交。好极了。但他们仍然相互重叠。为什么呢?

3 个答案:

答案 0 :(得分:1)

CGRectIntersectsRect不是问题,这是你的逻辑问题。当内循环找到一个不与按钮交叉的单个UIButton时,您接受为按钮生成的随机坐标。您需要确保squareArray中的所有按钮不与交叉按钮相交,而不仅仅是一个。

此外,初始化的按钮的帧是什么?也许这将是一个更好的解决方案:

for (int i=0; i<[squareArray count]; i++) {
    UIButton* button = [squareArray objectAtIndex:i];
    BOOL shouldContinue = NO;
    do {
        int randX = arc4random() % 321;
        int randY = arc4random() % 481;
        button.frame = CGRectMake(randX, randY, button.frame.size.width, button.frame.size.height);
        CGRect playerRect = CGRectMake(100, 180, 120, 120);
        for(int j=0; j<i; j++)
            UIButton *b = [squareArray objectAtIndex:j];
            if(CGRectIntersectsRect(b.frame, button.frame) || 
                CGRectIntersectsRect(button.frame, playerRect) || 
                !CGRectContainsRect(self.view.frame, button.frame)) {
                shouldContinue = YES;
            }
    } while (shouldContinue);
}

请注意,我根本没有测试过。此外,根据情况,如果按钮没有有效位置,这可能会永远循环。根据您的问题,可能有一个比完全随机放置所有内容更好的解决方案。

答案 1 :(得分:1)

假设squareArray包含三个带有这些框架的按钮A,B和C:

A.frame == CGRectMake(10,10,10,10)
B.frame == CGRectMake(10,10,10,10)
C.frame == CGRectMake(20,10,10,10)

请注意A和B重叠,但A和B不重叠C.现在考虑button == B时内循环中会发生什么。

在第一次通过内循环b == A时,您检测到CGRectIntersectsRect(b.frame, button.frame)并设置shouldContinue = YES

在第二次传递时,b == B表示[b isEqual:button],所以你什么都不做。

在第三次(也是最后一次)传球时,b == C。您发现CGRectIntersectsRect(b.frame, button.frame)为false(因为B.frame不与C.frame相交),CGRectIntersectsRect(button.frame, playerRect)为false,!CGRectContainsRect(CGRectMake(10, 10, 300, 460), button.frame)为false。所以你设置shouldContinue = NO

然后内循环退出。你测试shouldContinue,发现它是假的,然后退出do / while循环。您已将按钮B与按钮A重叠。

答案 2 :(得分:0)

最后,这有效:(结合Rob Lourens和rob mayoff的精彩答案 - 谢谢你们,在这里,你们每个人都有一个upvote!:)

for(int iii = 0; iii < [squareArray count]; iii++) {

    int randX = arc4random() % 321;
    int randY = arc4random() % 481;

    [(UIButton*)[squareArray objectAtIndex:iii] setFrame:CGRectMake(randX, randY, [(UIButton*)[squareArray objectAtIndex:iii] frame].size.width, [(UIButton*)[squareArray objectAtIndex:iii] frame].size.height)];

    CGRect playerRect = CGRectMake(40, 120, 150, 150);

    for(UIButton* b in squareArray)

        if(![b isEqual:[squareArray objectAtIndex:iii]]) {

            if(CGRectIntersectsRect(b.frame, [(UIButton*)[squareArray objectAtIndex:iii] frame]))
            {
                iii--;
                break;
            } else if(CGRectIntersectsRect([(UIButton*)[squareArray objectAtIndex:iii] frame], playerRect)) {
                iii--;
                break;
            } else if(![self checkBounds:[(UIButton*)[squareArray objectAtIndex:iii] frame]]) {
                iii--;
                break;
            }
        }
}