简体   繁体   中英

Setting collision bounding path of a UIView in iOS 9

In iOS 9 Apple introduced the collisionBoundsType to UIKit-Dynamics .

I have no issue when setting this UIDynamicItemCollisionBoundsTypeRectangle or when I set this to UIDynamicItemCollisionBoundsTypeEllipse .

The screenshot below is from a game I am making where the collisionBoundsType of the player is set to rectangle and the ball is set to ellipse:

在此输入图像描述

However, when I set the player's collisionBoundsType to path I get weird behavior as seen here:

在此输入图像描述

The view appears higher than it should and the collision body is to the right of where it should be.

Currently I have collisionBoundingPath set to this:

- (UIBezierPath *)collisionBoundingPath
{
    maskPath = [[UIBezierPath alloc] init];
    [maskPath addArcWithCenter:CGPointMake(SLIME_SIZE, SLIME_SIZE) radius:SLIME_SIZE startAngle:0*M_PI endAngle:M_PI clockwise:NO];
    return maskPath;
}

Additionally, my drawRect function looks like this:

- (void) drawRect:(CGRect)rect
{
    if (!_color){
    [self returnDefualtColor];
    }
    if (!maskPath) maskPath = [[UIBezierPath alloc] init];
    [maskPath addArcWithCenter:CGPointMake(SLIME_SIZE, SLIME_SIZE) radius:SLIME_SIZE startAngle:0*M_PI endAngle:M_PI clockwise:NO];
    [_color setFill];
    [maskPath fill];
}

Why is this happening? How do I set the path of the collision body to be the same as the drawing in the view?

Additionally, the red is just the background of the view (ie view.backgroundColor = [UIColor redColor]; ).

From the documentation on the UIDynamicItem here , the following statement about the coordinate system for paths seems to represent what is wrong:

The path object you create must represent a convex polygon with counter-clockwise or clockwise winding, and the path must not intersect itself. The (0, 0) point of the path must be located at the center point of the corresponding dynamic item. If the center point does not match the path's origin, collision behaviors may not work as expected.

Here it states that the (0,0) for the path MUST be the center point.

I would think that the center of your arc path should be (0,0) and not (SLIME_SIZE/2,SLIME_SIZE/2) . Have you perhaps set the width and height of the UIView frame to SLIME_SIZE rather than SLIME_SIZE*2 ?

SLIME_SIZE really seems to define the radius, so the frame width should be SLIME_SIZE*2 . If it is set as SLIME_SIZE , then that would explain why you need to translate by SLIME_SIZE/2 as a correction.

I was able to answer this by changing:

- (UIBezierPath *)collisionBoundingPath
{
    maskPath = [[UIBezierPath alloc] init];
    [maskPath addArcWithCenter:CGPointMake(SLIME_SIZE, SLIME_SIZE) radius:SLIME_SIZE startAngle:0*M_PI endAngle:M_PI clockwise:NO];
    return maskPath;
}

to:

- (UIBezierPath *)collisionBoundingPath
{
    maskPath = [[UIBezierPath alloc] init];
    [maskPath addArcWithCenter:CGPointMake(SLIME_SIZE / 2, SLIME_SIZE / 2) radius:SLIME_SIZE startAngle:0*M_PI endAngle:M_PI clockwise:NO];
    return maskPath;
}

The key difference is that I modified the center of the arc by dividing the x and y values by 2.

Debugging physics is a thing. It's probably not something that iOS users have tended to think a lot about as they've generally done very simple things with UIKit Dynamics. This is a bit of a shame, as it's one of the best aspects of the recent editions of iOS, and offers a truly fun way to make compelling user experiences.

So... how to debug physics?

One way is to mentally imagine what's going on, and then correlate that with what's going on, and find the dissonance between the imagined and the real, and then problem solve via a blend of processes of elimination, mental or real trial & error and deduction, until the problem is determined and solved.

Another is to have a visual depiction of all that's created and interacting presenting sufficient feedback to more rapidly determine the nature and extents of elements, their relationships and incidents/events, and resolve issues with literal sight.

To this end, various visual debuggers and builders of physics simulations have been created since their introduction.

Unfortunately iOS does not have such a screen based editor or "scene editor" for UIKit Dynamics, and what is available for this sort of visual debugging in Sprite Kit and Scene Kit is rudimentary, at best.

However there's CALayers, which are present in all UIKit Views, into which CAShapeLayers can be manually created and drawn to accurately represent any and all physical elements, their bounds and their anchors and relationships.

CAShapeLayers are a "container" for CGPaths, and can have different colours for outline and fill, and more than one CGPath element within a single CAShapeLayer.

And, to quote the great Rob:

"If you add a CAShapeLayer as a layer to a view, you don't have to implement any drawing code yourself. Just add the CAShapeLayer and you're done. You can even later change the path, for example, and it will automatically redraw it for you. CAShapeLayer gets you out of the weeds of writing your own drawRect or drawLayer routines."

If you have an enormous number of interacting elements and want to debug them, CAShapeLayer's performance issues might come into play, at which point you can use shouldRasterize to convert each to a bitmap, and get a significant performance improvement when hitting limits created by the "dynamic" capabilities of CAShapeLayers.

Further, for representing things like constraints and joints, there's a simple process of created dashed lines on CAShapeLayers, by simply setting properties. Here's the basics of setting up a CAShapeLayer's properties, and the way to use an array to create a 5-5-5 dashed outline with a block stroke, width of 3, no fill.

CAShapeLayer *shapeLayer = [CAShapeLayer layer];
[shapeLayer setBounds:self.bounds];
[shapeLayer setPosition:self.center];
[shapeLayer setFillColor:[[UIColor clearColor] CGColor]];
[shapeLayer setStrokeColor:[[UIColor blackColor] CGColor]];
[shapeLayer setLineWidth:3.0f];
[shapeLayer setLineJoin:kCALineJoinRound];
[shapeLayer setLineDashPattern:
 [NSArray arrayWithObjects:[NSNumber numberWithInt:10],
  [NSNumber numberWithInt:5],nil]];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM