Collision detection (CGRectIntersectRect)

点点圈 提交于 2019-12-13 08:19:37

问题


I have two images: first image size is 50x85 and second image size is 50x113. When I touch the screen image goes up and second image is shown and when I release the screen image goes down and first image is shown. Now the problem is when I'm touching the screen collision happens earlier than when I'm not touching the screen.

How could I make that in second image about 30px at bottom won't collide, but image will still be there?


Edit: Here is some of the code:

-(void)AstronautMove
{
    [self Collision];
    Astronaut.center = CGPointMake(Astronaut.center.x, Astronaut.center.y + Y);
}

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    Y = -10;
    x.image = [UIImage imageNamed:@"y.png"];
}

-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    Y = 17;
    x.image = [UIImage imageNamed:@"x.png"];
}

-(void)Collision
{
    if (CGRectIntersectsRect(Astronaut.frame, Landingarea.frame)) {
        [self EndGame];
        AstronautFire.hidden = YES;
        RedBorder.hidden = NO;
        AstronautCrashed.hidden = NO;
    }

    if (CGRectIntersectsRect(AstronautFire.frame, Landingarea.frame)) {
        [self EndGame];
        AstronautFire.hidden = YES;
        RedBorder.hidden = NO;
        AstronautCrashed.hidden = NO;
    }
}

I'm just moving the frame up and down. At the bottom is landing area. When Astronaut and landing area frames touch, collision happens. But when I'm moving Astronaut up bigger image is shown (50x113) and when I'm moving Astronaut down smaller image is shown (50x85). When I'm near landing area and I press to go up bigger image shows and collision happens.


回答1:


From the code samples, it really is hard to follow what you're trying to do. Notably, it's unclear how (or even if) you're animating the moving of the various views.

Whether you're animating or not, it's not clear from your code sample as to where AstronautMove is called. Did you mean to call that from touchesBegan and touchesEnded? But on the basis of what's been shared thus far, I don't see you calling AstronautMove and therefore don't see how you could possibly detect collisions.

Personally, I would have thought that you'd want to animate the moving of the views (it will render a more realistic and engaging moving of the views). And then, while an animation is underway, keep checking for a collision. In terms of how to "keep checking", you can use either a NSTimer or, even better, us a CADisplayLink (a mechanism to call a method each and every time the screen updates).

For example, you could do something like:

@interface ViewController ()

@property (nonatomic, strong) UIView *view1;
@property (nonatomic, strong) UIView *view2;

@property (nonatomic, strong) CADisplayLink *displayLink;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
    view1.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:view1];
    self.view1 = view1;

    UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(50, 150, 50, 50)];
    view2.backgroundColor = [UIColor darkGrayColor];
    [self.view addSubview:view2];
    self.view2 = view2;
}

#pragma mark - Handle touches

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self startAnimationTo:CGPointMake(50, 250) collisionChecking:YES];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self startAnimationTo:CGPointMake(50, 50) collisionChecking:NO];
}

#pragma mark - Handle starting and stopping of animation

- (void)startAnimationTo:(CGPoint)point collisionChecking:(BOOL)collisionChecking
{
    if (collisionChecking)
        [self startDisplayLink];

    [UIView animateWithDuration:2.0 delay:0.0 options:0 animations:^{
        CGRect frame = self.view1.frame;
        frame.origin = point;
        self.view1.frame = frame;
    } completion:^(BOOL finished) {
        // in case we never have collision, let's make sure we stop the display link
        if (collisionChecking)
            [self stopDisplayLink];
    }];
}

- (void)stopAnimation
{
    CALayer *layer = self.view1.layer.presentationLayer;

    [self.view1.layer removeAllAnimations];
    self.view1.frame = layer.frame;
    [self stopDisplayLink];
}

#pragma mark - Handle the display link & check for collisions

- (void)startDisplayLink
{
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(checkForCollision:)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

- (void)stopDisplayLink
{
    [self.displayLink invalidate];
    self.displayLink = nil;
}

- (void)checkForCollision:(CADisplayLink *)displayLink
{
    // Note, when checking for collision while an animation is underway, the `frame` of the
    // view represents the final location of the view, not the current location. To get the
    // current location, one has to grab the `presentationLayer`. So, we're going to get the
    // `presentationLayer` of each of the views and use those to determine a collision.

    CALayer *layer1 = self.view1.layer.presentationLayer;
    CALayer *layer2 = self.view2.layer.presentationLayer;

    if (CGRectIntersectsRect(layer1.frame, layer2.frame)) {
        [self stopAnimation];
    }
}

@end

Or, in iOS 7, you can use UIKit Dynamics to animate the movement of the views, identifying collisions programmatically using a UICollisionBehavior and assigning a collisionDelegate:

@interface ViewController () <UICollisionBehaviorDelegate>

@property (nonatomic, strong) UIView *view1;
@property (nonatomic, strong) UIView *view2;

@property (nonatomic, strong) UIDynamicAnimator *animator;
@property (nonatomic, strong) UISnapBehavior *snap;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 50, 50)];
    view1.backgroundColor = [UIColor lightGrayColor];
    [self.view addSubview:view1];
    self.view1 = view1;

    UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(50, 150, 50, 50)];
    view2.backgroundColor = [UIColor darkGrayColor];
    [self.view addSubview:view2];
    self.view2 = view2;

    self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];

    // create behavior that will detect collisions, calling the `UICollisionBehaviorDelegate`
    // methods if and when collisions are detected

    UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[view1, view2]];
    collision.translatesReferenceBoundsIntoBoundary = YES;
    collision.collisionDelegate = self;
    [self.animator addBehavior:collision];

    // in this example, I'm going to fix `view2` where it is, so it doesn't move when 
    // `view1` collides with it

    UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:self.view2 attachedToAnchor:self.view2.center];
    [self.animator addBehavior:attachment];

    // finally, let's specify that neither view1 nor view2 should rotate when 
    // snapping, colliding, etc.

    UIDynamicItemBehavior *noRotate = [[UIDynamicItemBehavior alloc] initWithItems:@[view1, view2]];
    noRotate.allowsRotation = NO;
    [self.animator addBehavior:noRotate];
}

- (void)addSnap:(CGPoint)point
{
    [self removeSnap];

    self.snap = [[UISnapBehavior alloc] initWithItem:self.view1 snapToPoint:point];
    [self.animator addBehavior:self.snap];
    [self.animator updateItemUsingCurrentState:self.view1];
}

- (void)removeSnap
{
    if (self.snap) {
        [self.animator removeBehavior:self.snap];
        self.snap = nil;
    }
}

#pragma mark - Handle touches

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self addSnap:CGPointMake(75, 225)];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self addSnap:CGPointMake(75, 75)];
}

#pragma mark - UICollisionBehaviorDelegate

// you can use these to be informed when there is a collision

- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p
{
    NSLog(@"%s", __FUNCTION__);

    [self removeSnap];
}

- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item1 withItem:(id<UIDynamicItem>)item2 atPoint:(CGPoint)p
{
    NSLog(@"%s", __FUNCTION__);

    [self removeSnap];
}
@end

Or, for a game, SpriteKit might be even better. You can google "SpriteKit example" and you'll probably find plenty of good introductions to SpriteKit.

I know that neither of the above examples are quite what you're doing, but hopefully it illustrates a couple of techniques for identifying collisions, which you could adapt for your app.



来源:https://stackoverflow.com/questions/21646295/collision-detection-cgrectintersectrect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!