Setting a path to limit UIView collisions in iOS 9

In iOS 9, Apple introduced collisionBoundsType in UIKit-Dynamics .

I have no problem installing this UIDynamicItemCollisionBoundsTypeRectangle or when I install it on UIDynamicItemCollisionBoundsTypeEllipse .

The screenshot below is from the game I'm doing, where the player’s collisionBoundsType set to a rectangle and the ball is set to an ellipse:

enter image description here

However, when I install the collisionBoundsType player on the path, I get strange behavior, as shown here:

enter image description here

The view looks taller than necessary, and the collision body is to the right of where it should be.

I currently have collisionBoundingPath set to the following:

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

In addition, 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 to set the collision body path the same as the picture in the view?

In addition, red is only the background of the view (ie view.backgroundColor = [UIColor redColor]; ).

+7
ios objective-c tvos uikit-dynamics uicollisionbehavior
source share
3 answers

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

The created path object must be a convex polygon with a counterclockwise or clockwise direction, and the path should not intersect. The point (0, 0) of the path should be located on the center point of the corresponding dynamic element. If the center point does not match the origin of the paths, collision behavior may not work as expected.

It is indicated here that (0,0) for the path MUST be the center point.

I think the center of your arc path should be (0,0) and not (SLIME_SIZE/2,SLIME_SIZE/2) . Perhaps you set the width and height of the UIView frame for SLIME_SIZE, not 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 , this explains why you need to translate to SLIME_SIZE/2 as a correction.

+2
source share

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

in

 - (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 changed the center of the arc by dividing the x and y values ​​by 2.

+1
source share

Debugging physics is a thing. This is probably not something that iOS users tend to think a lot, as they usually did very simple things using UIKit Dynamics. This is a bit of a shame, as it is one of the best aspects of the latest iOS releases, and offers a really interesting way to make an impressive user experience.

So ... how to debug physics?

One way is to mentally imagine what is happening, and then compare it with what is happening, and find the dissonance between the imaginary and the real, and then solve the problem through a combination of elimination processes, mental or real trial and error and deduction, until the problem is defined and not resolved.

Another is a visual image of everything that is created and interacts, presenting sufficient feedback to more quickly determine the nature and extent of elements, their relationships and incidents / events, as well as solve problems with a literal sight.

To this end, from the moment of their creation, various visual debuggers and developers of physical modeling have been created.

Unfortunately, iOS does not have such an on-screen editor or “scene editor” for UIKit Dynamics, and what is available for this kind of visual debugging in the sprite set and scene set is rudimentary at best.

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

CAShapeLayers are a “container” for CGPaths and can have different colors for outline and fill and more than one CGPath element within the same CAShapeLayer.

And to quote the great Rob:

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

If you have a huge number of interacting elements and you want to debug them, you may experience CAShapeLayer performance problems, after which you can use shouldRasterize to convert each to a bitmap and achieve a significant increase in performance when you reach the set limits for the "dynamic" capabilities of CAShapeLayers.

In addition, to represent things like restraints and joints, there is a simple process for creating dashed lines on CAShapeLayers by simply setting properties. Here are the basics of setting CAShapeLayer properties and how to use the array to create a 5-5-5 dashed outline with a block pitch of 3 width without filling.

 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]]; 
+1
source share

All Articles