Changing scale on an axis to -1 gives the wrong bounding box
I am doing something trivial like flipping the sprite based on the direction it’s moving. Given that the anchor point is at (0.5,0.5) and that the base scaleX is 1.0, what I’m doing is setting the scaleX to -1.0 when the CCSprite is moving the opposite direction. What actually happens is that the boundingBox has an offset that is equal to the contentSize. i.e. if the boundingBox is {{258.35492, 239.66747}, {16.159908, 16.159908}} as soon as I scale the X it becomes {{244.39485, 239.82852}, {16.159908, 16.159908}} (keep in mind that in this example I’m using a moving sprite).
Is this a bug of v3 by any chance?
There were some minor changes to the boundingBox method for the new position code, but I don't see how it would have broken anything new. Is this with or without a CCPhysicsBody attached?
With the CCPhysicsBody attached. With physics debug turned on I can clearly see that the physics body stays in the right position, while the sprite gets pushed to the left by its width.
As suggested by @Birkemose I tried the following:
I tried adding a new CCNode, adding the CCSprite as child of the CCNode and added that CCNode to the CCPhysicsNode. Switching the scaleX of the CCNode has an even worse effect. The bounding box goes from {{259.1871, 15.75098}, {16.043797, 16.043797}} to {{-276.5162, 15.751305}, {16.043797, 16.043797}}.
I've been trying to debug this problem but I haven't yet been able to determine where things break. Here's a video of what I'm talking about. At the bottom you can see the sprite position and bounding box printed to the console as the sprite moves.
http://www.youtube.com/watch?v=uOhJXz1g-VQ
It really looks like when I multiply the scaleX * -1, the position changes as well.. but the physics body stays in the correct position. The anchor point of the sprite you see moving is at 0.5, 0.5 btw.
I kept debugging this and it looks like it's happening only when I add a physics body to the CCSprite. Here's a ccb file that shows the problem: https://dl.dropboxusercontent.com/u/3098924/CCSprite-scale-problem.zip Just load it and through CCBReader, add it as a child of a layer and do a self.scaleX *= -1 and you'll see the problem.
@slembcke I managed to create a simple project that has this very same issue. You can check it out here: https://github.com/tanis2000/test-scale
Please let me know if you need more info.
I can confirm, that setting scaleX to -1, moved the sprite out of position. This could be related to https://github.com/cocos2d/cocos2d-iphone/issues/436
In my case, I fixed it by adding an extra node (which was not required in 1.x or 2.x), however, this is not possible when the objects are created automatically.
Note: @tanis2000, remember to call onEnter first, and onExit last when overriding.
@Birkemose I can't remember why I started calling onEnter last when overriding it, but I think it was something related to some problem with physics with the first RC of v3. I'll get them back to where they belong and check if there's any weird behavior going on.
As for the extra node, I think I tried that too but with no difference in the result. I'll try it again with this test project to make sure it's not something else messing it up in my game. This could still be a problem if the sprite is being created by SpriteBuilder.. unless I start adding ghost nodes all over the place, maybe?
Any idea what is causing this to happen so that I can try fixing it at the root of the problem?
Argh. I thought I had a simple partial fix for it, but it ended up breaking an even more common use case. I think the final solution is going to be to cache the node's transform to the body when it's first set up so it can use it as a reference point for when it's modified later. That's kind of involved though so it will probably have to wait until after GDC. :-\
I think that's ultimately what I'll need to do to implement https://github.com/cocos2d/cocos2d-iphone/issues/594 also.
@jtwigg was looking at this issue when he made https://github.com/cocos2d/cocos2d-iphone/pull/692 Pretty sure he fixed the issue, but we'll want to add a test to verify it.
That sounds very good. I'll update the cocos2d lib of my test case and check if this fixed the issue!
@slembcke I tried updating cocos2d-iphone to the latest v3.0 branch but the issue is still there.
You can check it out at my test project there: https://github.com/tanis2000/test-scale
Err, sorry. The fix is in the develop branch.
@slembcke right now I'm at a dead end with my test project. I wanted to give it a quick try but updating to the develop branch breaks CCBReader as it cannot read version 6 of .ccbi files. See https://github.com/cocos2d/cocos2d-iphone/issues/703
Another related issue: https://github.com/cocos2d/cocos2d-iphone/issues/703#issuecomment-40523330
Possibly introduced by #692?
I can recreate the issue by setting density = 0.0 in SpriteBuilder.
I'll contact slembcke about what the solution should be.
@jtwigg I still experience this problem even with the release-3.1.0-beta branch. And all of my sprites in SB are set to 1.0 density. Is there a recently compiled beta version of SB that I can try out by any chance?
@jtwigg @slembcke I have a different theory as well. I have a class that takes the tiles of a tilemap to build the physics convex hulls of the platforms.
The relevant code is the following and it sets the density as well as other parameters of the body, but please have a look anyway.
for (int j = 0; j < [_allPoints count]; j++) {
NSMutableArray *points = [_allPoints objectAtIndex:j];
CGPoint *pp = calloc(sizeof(CGPoint), [points count]);
for (int i = 0; i < [points count]; i++) {
NSDictionary *v = [points objectAtIndex:i];
NSNumber *x = [v objectForKey:@"x"];
NSNumber *y = [v objectForKey:@"y"];
pp[i] = ccp([x floatValue], [y floatValue]);
}
CCPhysicsBody *body = [CCPhysicsBody bodyWithPolylineFromPoints:pp count:[points count] cornerRadius:1 looped:YES];
//CCPhysicsBody *body = [CCPhysicsBody bodyWithPolygonFromPoints:pp count:[points count] cornerRadius:0.5];
//body.affectedByGravity = NO;
//body.allowsRotation = NO;
body.type = CCPhysicsBodyTypeStatic;
body.density = 1.0;
body.elasticity = 0;
body.friction = 0.30;
body.collisionCategories = @[@"floor"];
body.collisionMask = @[@"player", @"enemy", @"bullet", @"shell", @"coin", @"powerup"];
[_shapes addObject:body];
}
BTW I tried removing this code from my project but I still keep getting the same error, so I suppose it's not due to this, but more likely due to the objects created by SB :(
@tanis2000 Is the project https://github.com/tanis2000/test-scale still relevant in demonstrating this error? When I run that project, I get an exception
cpAssertSoft(body->m > 0.0f && body->i > 0.0f, "Body's mass and moment must be positive to simulate. (Mass: %f Moment: %f)", body->m, body->i);
which I've seen before. Changing the scale on a physics body doesn't work very well at all and I don't think it will for the near future.
I don't know if this helps either, but here's a little platformer game I put together thats easy to understand and uses some physics possibly in the fashion you're trying todo.
https://github.com/jtwigg/Platformer.spritebuilder
I get the player to scaleX *= -1 NOT by scaling the PhysicsBody, but by scaling the sprite that's nested under the PhysicsBody.
@jtwigg I'll try commenting out the scale part on my current project and let you know if that's what's causing the error.
The project you're referring to used to work but the sprite was being positioned in the wrong place when scaled by -1.
The error you're seeing is something new that appeared only recently.
Do you mean 'appears in the wrong place' like in the below image? The box is on the right, and the sprite is facing left (scaleX = -1) but they're not overlapping? If so I can explain, but I'll wait for your confirmation that this is the error you're seeing.

Yes this is the error I'm seeing when scaling that CCSprite X by -1.
@jtwigg as a side note, I commented out the line that changes the scaleX property of the sprite but it still keeps giving me the same error about mass being 0.
Can you post a test project that produces the error about mass?
@tanis2000 Here's the reason that the image is not in the same place as the body. Currently the you cannot SCALE or SKEW any physicsBody OR the parent of any physics body AFTER it has been added to the scene:
Why? Its due to it being an extremely complicated calculation. If you scale a physics body larger, its mass is changing, likewise it vertices now have an expansionary velocity which is complicated to calculate.
There are some differences between what happens if you use STATIC vs DYNAMIC bodies too. Static : If you scale/skew the body, it will throw an exception. Dynamic: The CCNode will obey operation, but the body will not, hence why you're sprite was reversed, but the physics body displayed was not.
If you want to perform this type of operation, take a look at my posted example project which successfully flips a player character, without it leaving the PhysicsBody's dimensions.
https://github.com/jtwigg/Platformer.spritebuilder
In my example I have a CCNode (Physics: with physics body) => CCSprice (Alien) as a child
I can flip the CCSprite without flipping the CCNode(Physics)
in your example, you have CCSprite(PhysicsBody && Alien.png) and you're trying to scale both the body && the png (bad).
@jtwigg ok what you say makes sense. I actually tried doing the opposite by adding a parent CCNode to my CCSprite and scaling that parent but it didn't work and now I understand why.
I'll try your solution and let you know how it goes.
For the mass problem, it's going to be hard to isolate the part of the project that is causing it because I cannot find a direct reference to the object whose physics body is breaking.
What I can do id share my game project as long as you agree not to share it with others. Would that be ok?
@jtwigg I tried doing like you said and making my Player class a CCNode with Physics and adding the CCSprite with the actual texture as a child of the CCNode. It works fine.
Now I fear that I should do that for all of my physics objects as they're all CCSprite and even if I'm not scaling or skewing them, I keep getting errors about mass or about their velocity being INFINITY.
This never happened before.. it's a new thing that happened only with 3.1
@jtwigg Update: I switched my Bullet and Shell class to be just like the Player one and that solved the issues with Chipmunk apparently. But as a side effect, now everything is colliding with everything else.. it looks like my collisionCategories and collisionMask are being ignored.
They're setup as follows:
Bullet
-(void)onEnter {
[super onEnter];
self.physicsBody.collisionCategories = @[@"bullet"];
self.physicsBody.collisionMask = @[@"enemy", @"floor"];
}
Shell
-(void)onEnter {
[super onEnter];
self.physicsBody.collisionCategories = @[@"shell"];
self.physicsBody.collisionMask = @[@"floor"];
}
Player
self.physicsBody.collisionCategories = @[@"player"];
self.physicsBody.collisionMask = @[@"floor", @"coin", @"flag", @"powerup"];
@tanis2000 Hey Tanis. If you're having new problems, would you mind opening a new issue? Did you figure out the collisionsCategories vs Masks issue? I remember getting confused about it too but I read the code and figured it out eventually. It could need improved documentation.