碰撞检测(CGRectIntersectRect) [英] Collision detection (CGRectIntersectRect)

查看:102
本文介绍了碰撞检测(CGRectIntersectRect)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个图像:第一个图像尺寸为50x85,第二个图像尺寸为50x113。当我触摸屏幕图像时,屏幕图像会上升并显示第二张图像;当我释放屏幕图像时,屏幕图像会下降并显示第一幅图像。现在的问题是,当我触摸屏幕时,碰撞发生的时间比不触摸屏幕时要早。

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.

如何在第二个图像中使底部约30px的图像不会发生碰撞,但是图像仍然存在?

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

编辑:以下是一些代码:

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

我只是上下移动框架。底部是着陆区。当宇航员和着陆区框架接触时,就会发生碰撞。但是,当我将宇航员向上移动时,会显示较大的图像(50x113),而当我将宇航员向下移动时,则会显示较小的图像(50x85)。当我靠近着陆区时,按可以放大图像,并发生碰撞。

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.

推荐答案

从代码示例中确实很难遵循您要执行的操作。值得注意的是,目前尚不清楚您是如何(或即使)对各种视图的移动进行动画处理。

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.

无论您是否进行动画处理,代码中都不清楚有关调用 AstronautMove 的位置的示例。您是说从 touchesBegan touchesEnded 来称呼它吗?但是基于到目前为止的共享,我看不到您调用 AstronautMove ,因此也看不到如何检测到碰撞。

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.

就我个人而言,我本以为您想对视图的移动进行动画处理(它将使视图的移动更加逼真有趣)。然后,在进行动画制作时,请继续检查是否有碰撞。就如何保持检查而言,您可以使用 NSTimer ,甚至更好的是,我们可以使用 CADisplayLink (一种在每次屏幕更新时都会调用方法的机制)。

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

或,在iOS 7中,您可以使用UIKit Dynamics动画化视图的运动,使用 UICollisionBehavior 以编程方式识别碰撞,并分配 collisionDelegate

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

或者,对于游戏, SpriteKit 可能更好。您可以在Google上搜索 SpriteKit示例,然后可能会发现很多关于SpriteKit的很好的介绍。

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.

这篇关于碰撞检测(CGRectIntersectRect)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆