我有两个UIViews,其中一个使用以下代码每0.01秒旋转一次:
self.rectView.transform = CGAffineTransformRotate(self.rectView.transform, .05);
现在,我希望能够判断另一个名为view的UIView是否与rectView相交。我用了这段代码:
if(CGRectIntersectsRect(self.rectView.frame, view.frame)) {
//Intersection
}
然而,你可能知道,这有一个问题。这是一个截图:
在这种情况下,即使显然它们没有碰到,也会检测到碰撞。我环顾四周,但我似乎无法找到真正的代码来检测这种碰撞。如何才能做到这一点?在这种情况下检测碰撞的工作代码将不胜感激!或者,除了UIView之外,还有更好的课程可以使用吗?
答案 0 :(得分:2)
旋转视图时,其边界不会更改but its frame changes.
所以,对于我的backgroundColor蓝色视图,
我设置的初始帧是
frame =(30,150,150,35);
bounds = {{0,0},{150,35}};
但旋转45度后,框架变为
frame =(39.5926 102.093; 130.815 130.815);
bounds = {{0,0},{150,35}};
因为框架始终返回该视图的最小的包围矩形。
因此,在您的情况下,即使它看起来两个视图都不相交,它们的帧也相交。
要解决此问题,您可以使用分离轴测试。 如果您想了解它,link here
我试图解决它,最后得到了解决方案。 如果您想查看,下面是代码。 将以下代码复制粘贴到一个空项目中进行检查。
在.m文件中
@implementation ViewController{
UIView *nonRotatedView;
UIView *rotatedView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
nonRotatedView =[[UIView alloc] initWithFrame:CGRectMake(120, 80, 150, 40)];
nonRotatedView.backgroundColor =[UIColor blackColor];
[self.view addSubview:nonRotatedView];
rotatedView =[[UIView alloc] initWithFrame:CGRectMake(30, 150, 150, 35)];
rotatedView.backgroundColor =[UIColor blueColor];
[self.view addSubview:rotatedView];
CGAffineTransform t=CGAffineTransformMakeRotation(M_PI_4);
rotatedView.transform=t;
CAShapeLayer *layer =[CAShapeLayer layer];
[layer setFrame:rotatedView.frame];
[self.view.layer addSublayer:layer];
[layer setBorderColor:[UIColor blackColor].CGColor];
[layer setBorderWidth:1];
CGPoint p=CGPointMake(rotatedView.bounds.size.width/2, rotatedView.bounds.size.height/2);
p.x = -p.x;p.y=-p.y;
CGPoint tL =CGPointApplyAffineTransform(p, t);
tL.x +=rotatedView.center.x;
tL.y +=rotatedView.center.y;
p.x = -p.x;
CGPoint tR =CGPointApplyAffineTransform(p, t);
tR.x +=rotatedView.center.x;
tR.y +=rotatedView.center.y;
p.y=-p.y;
CGPoint bR =CGPointApplyAffineTransform(p, t);
bR.x +=rotatedView.center.x;
bR.y +=rotatedView.center.y;
p.x = -p.x;
CGPoint bL =CGPointApplyAffineTransform(p, t);
bL.x +=rotatedView.center.x;
bL.y +=rotatedView.center.y;
//check for edges of nonRotated Rect's edges
BOOL contains=YES;
CGFloat value=nonRotatedView.frame.origin.x;
if(tL.x<value && tR.x<value && bR.x<value && bL.x<value)
contains=NO;
value=nonRotatedView.frame.origin.y;
if(tL.y<value && tR.y<value && bR.y<value && bL.y<value)
contains=NO;
value=nonRotatedView.frame.origin.x+nonRotatedView.frame.size.width;
if(tL.x>value && tR.x>value && bR.x>value && bL.x>value)
contains=NO;
value=nonRotatedView.frame.origin.y+nonRotatedView.frame.size.height;
if(tL.y>value && tR.y>value && bR.y>value && bL.y>value)
contains=NO;
if(contains==NO){
NSLog(@"no intersection 1");
return;
}
//check for roatedView's edges
CGPoint rotatedVertexArray[]={tL,tR,bR,bL,tL,tR};
CGPoint nonRotatedVertexArray[4];
nonRotatedVertexArray[0]=CGPointMake(nonRotatedView.frame.origin.x,nonRotatedView.frame.origin.y);
nonRotatedVertexArray[1]=CGPointMake(nonRotatedView.frame.origin.x+nonRotatedView.frame.size.width,nonRotatedView.frame.origin.y);
nonRotatedVertexArray[2]=CGPointMake(nonRotatedView.frame.origin.x+nonRotatedView.frame.size.width,nonRotatedView.frame.origin.y+nonRotatedView.frame.size.height);
nonRotatedVertexArray[3]=CGPointMake(nonRotatedView.frame.origin.x,nonRotatedView.frame.origin.y+nonRotatedView.frame.size.height);
NSInteger i,j;
for (i=0; i<4; i++) {
CGPoint first=rotatedVertexArray[i];
CGPoint second=rotatedVertexArray[i+1];
CGPoint third=rotatedVertexArray[i+2];
CGPoint mainVector =CGPointMake(second.x-first.x, second.y-first.y);
CGPoint selfVector =CGPointMake(third.x-first.x, third.y-first.y);
BOOL sign;
sign=[self crossProductOf:mainVector withPoint:selfVector];
for (j=0; j<4; j++) {
CGPoint otherPoint=nonRotatedVertexArray[j];
CGPoint otherVector = CGPointMake(otherPoint.x-first.x, otherPoint.y-first.y);
BOOL checkSign=[self crossProductOf:mainVector withPoint:otherVector];
if(checkSign==sign)
break;
else if (j==3)
contains=NO;
}
if(contains==NO){
NSLog(@"no intersection 2");
return;
}
}
NSLog(@"intersection");
}
-(BOOL)crossProductOf:(CGPoint)point1 withPoint:(CGPoint)point2{
if((point1.x*point2.y-point1.y*point2.x)>=0)
return YES;
else
return NO;
}
希望这有帮助。
答案 1 :(得分:0)
这可以比建议的方法更有效、更容易地完成……如果需要,黑色和蓝色视图都可以旋转。
只需将旋转后的 blueView 的 4 个角转换为它们在 superview 中的位置,然后将这些点转换为它们在旋转后的 blackView 中的位置,然后检查这些点是否在 blackView 的边界内。
UIView *superview = blueView.superview;//Assuming blueView.superview and blackView.superview are the same...
CGPoint blueView_topLeft_inSuperview = [blueView convertPoint:CGPointMake(0, 0) toView:superview];
CGPoint blueView_topRight_inSuperview = [blueView convertPoint:CGPointMake(blueView.bounds.size.width, 0) toView:superview];
CGPoint blueView_bottomLeft_inSuperview = [blueView convertPoint:CGPointMake(0, blueView.bounds.size.height) toView:superview];
CGPoint blueView_bottomRight_inSuperview = [blueView convertPoint:CGPointMake(blueView.bounds.size.width, blueView.bounds.size.height) toView:superview];
CGPoint blueView_topLeft_inBlackView = [superview convertPoint:blueView_topLeft_inSuperview toView:blackView];
CGPoint blueView_topRight_inBlackView = [superview convertPoint:blueView_topRight_inSuperview toView:blackView];
CGPoint blueView_bottomLeft_inBlackView = [superview convertPoint:blueView_bottomLeft_inSuperview toView:blackView];
CGPoint blueView_bottomRight_inBlackView = [superview convertPoint:blueView_bottomRight_inSuperview toView:blackView];
BOOL collision = (CGRectContainsPoint(blackView.bounds, blueView_topLeft_inBlackView) ||
CGRectContainsPoint(blackView.bounds, blueView_topRight_inBlackView) ||
CGRectContainsPoint(blackView.bounds, blueView_bottomLeft_inBlackView) ||
CGRectContainsPoint(blackView.bounds, blueView_bottomRight_inBlackView));