Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying Box2D physics to UIView vs. CALayer

I've used this excellent tutorial to kickoff a small project I'm working on involving physics:

http://www.cocoanetics.com/2010/05/physics-101-uikit-app-with-box2d-for-gravity/

Basically, it creates a world and applies the physics of B2D to whichever views you have. Very simple and it works. However, I tried to apply the same logic by using CALayers, i.e., I programmatically create layers, add them to the main view.layer and try to animate them.

Sample code for creating the layer:

CALayer *layer = [CALayer layer];
layer.backgroundColor = [UIColor blackColor].CGColor;
layer.frame = CGRectMake(50, 100, 30, 30);
layer.name = @"square";
[self.view.layer addSublayer:layer];

And the applied physics in the ticker:

CALayer *oneLayer = (CALayer *)b->GetUserData();
// y Position subtracted because of flipped coordinate system
CGPoint newCenter = CGPointMake(b->GetPosition().x * PTM_RATIO, self.view.bounds.size.height - b->GetPosition().y * PTM_RATIO);
oneLayer.position = newCenter;
CGAffineTransform transform = CGAffineTransformMakeRotation(- b->GetAngle());
oneLayer.affineTransform = transform;

Notice that I adapted the affine transform call to the CALayer class.

I've checked and double-checked the variables, and the numbers seem to match. What I get is a weird bounce from the CALayer animation, and a perfect animation from the UIView. Anyone experienced in Box2D and UIKit to answer why this can be happening?

like image 589
hcabral Avatar asked Aug 16 '12 16:08

hcabral


1 Answers

Unlike UIViews, CALayers have built-in implicit animations. Every time you change a value of an animatable property a short animation will be introduced. You have to wrap your code in CATransaction and disable actions to get rid of this effect:

[CATransaction begin];
[CATransaction setDisableActions:YES]; // implicit animations get disabled

CALayer *oneLayer = (CALayer *)b->GetUserData();
// y Position subtracted because of flipped coordinate system
CGPoint newCenter = CGPointMake(b->GetPosition().x * PTM_RATIO, self.view.bounds.size.height - b->GetPosition().y * PTM_RATIO);
oneLayer.position = newCenter;
CGAffineTransform transform = CGAffineTransformMakeRotation(- b->GetAngle());
oneLayer.affineTransform = transform;

[CATransaction commit];
like image 182
Bartosz Ciechanowski Avatar answered Nov 10 '22 13:11

Bartosz Ciechanowski