1

I'm trying to make a cocos2d/box2d game work on iPad, iPhone and iPhone retina. My problem is, that the fixture and body don't line up on the retina simulator, please click on screenshots below for illustration (as a new stackoverflow member, it won't allow me to post the screenshot here).

screenshot

(please disregard the different shapes, I want the 4 corners to line up) I've done quite a bit of research on this over the last couple of days, and the closest I found was this:

link

But the solution offered there with PTM_RATIO and CC_CONTENT_SCALE_FACTOR() doesn't seem to work in my case. I think it has to do with the fact that I don't load an image from file into my sprite. Most solutions to this problem are based on loading -hd image files for the retina display, but I don't want to use files in my game at all. I basically want to draw the polygons myself at runtime,

My code looks as follows:

-(CCSprite*)addSprite
{
    CGSize contextsize = CGSizeMake(200, 200); 
    UIGraphicsBeginImageContext(contextsize);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextFlush(context);
    CGContextSetAllowsAntialiasing(context, true);
    CGContextTranslateCTM(context, 0, contextsize.height);
    CGContextScaleCTM(context, 1.0, -1.0);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
    CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
    CGColorRef color = CGColorCreate(colorspace, components);
    CGContextSetStrokeColorWithColor(context, color);

    UIBezierPath* aPath;

    aPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 100)
                                           radius:100
                                       startAngle:0 
                                         endAngle:1.57 
                                        clockwise:YES];
    [aPath addArcWithCenter:CGPointMake(100, 100) 
                     radius:50
                 startAngle:1.57
                   endAngle:0
                  clockwise:NO];

    [aPath stroke];

    CGContextStrokePath(context);
    CGColorSpaceRelease(colorspace);
    CGColorRelease(color);

    UIImage *graphImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    CCTexture2D *tex = [[[CCTexture2D alloc] initWithImage:graphImage] autorelease];
    CCSprite *sprite = [CCSprite spriteWithTexture:tex];
    return sprite;
}

-(void) addFixture:(CCSprite *)fixsprite
{
    b2Vec2 arcdots[] = {
        b2Vec2(50.0f / PTM_RATIO, 0.0f / PTM_RATIO),
        b2Vec2(100.0f / PTM_RATIO, 0.0f / PTM_RATIO),
        b2Vec2(0.0f / PTM_RATIO, 100.0f / PTM_RATIO),
        b2Vec2(0.0f / PTM_RATIO, 50.0f / PTM_RATIO)
};

    b2PolygonShape p_shape;
    b2FixtureDef fixtureDef;

    b2BodyDef bodyDef;
    bodyDef.type = b2_kinematicBody;

    bodyDef.position.Set(100/PTM_RATIO, 100/PTM_RATIO);
    bodyDef.userData = fixsprite;
    b2Body *body = world->CreateBody(&bodyDef);

    p_shape.Set(arcdots, 4);
    fixtureDef.shape = &p_shape;    
    fixtureDef.density = 1.0f;
    fixtureDef.friction = 0.3f;
    body->CreateFixture(&fixtureDef);
}   

And I call these functions from the main routine as follows:

CCSprite *sprite2 = [self addSprite];
sprite2.position = ccp(0, 0);
[self addChild:sprite2 z:0];        
[self addFixture:sprite2];

I have these lines uncommented in the delegate file:

if( ! [director enableRetinaDisplay:YES] )
    CCLOG(@"Retina Display Not supported");

Please let me know if further information is required. And please be gentle, I'm only starting to learn this. Thanks for your time.

Community
  • 1
  • 1
Matt M
  • 11
  • 1

1 Answers1

0

Unless otherwise mentioned, all coordinates in cocos2d (and most of UIKit) are given in points, not pixels. On a Retina display device you still have a point resolution of 480x320 points (960x640 pixels).

From that follows: when you calculate in actual pixels, multiply or divide by CC_CONTENT_SCALE_FACTOR. If you deal with point coordinates, do nothing. Since you're rendering your own polys I assume you know whether you use actual pixel coordinates or not. If you use OpenGL directly, then you'll be working with pixel coordinates.

I'm not sure if enabling Retina display mode does anything for you if you don't use cocos2d to render your content.

Lastly, a common misunderstanding is that the Box2D world is using point coordinates and must be transformed to pixels or vice versa. Neither is the case. The Box2D world is completely oblivious to a specific coordinate system. The use of PTM_RATIO is done only to ensure that Box2D coordinates are within reasonable ranges for the Box2D engine, since it works best with objects that are 1 meter in size/diameter, and most objects should range from 0.1 to 10 meters in diameter.

CodeSmile
  • 64,284
  • 20
  • 132
  • 217
  • Thank you for the quick reply. As far as I understand it, I don't seem to have a box2d problem, since the debug draw renders correctly in retina. My problem is that the actual sprite has the correct size, but is in the wrong location. Looking at the UIGraphics part in my code, I don't even set its position, so I'm not sure where I could apply the scale factor. If I disable retina display mode as per your suggestion, it renders correctly, but with low-res, i.e. it's the same as normal iPhone simulator. I guess I could rephrase my question to "how can I use full retina resolution with cocos2d?" – Matt M Jul 11 '12 at 04:29
  • If you disable Retina and it looks correct, but it's wrong when you enable Retina mode, then you're not supplying Retina graphics (ie the same image with twice the width and height). For cocos2d to correctly recognize the Retina files, you have to give them the -hd suffix. So instead of image.png use image-hd.png. Normally you have both in a project to support Retina and non-Retina devices at the same time. – CodeSmile Jul 13 '12 at 11:47
  • I am aware of that. As per my original post, I don't load images from file into sprites. I want to draw the sprites at runtime. – Matt M Jul 14 '12 at 03:23