Box2d 和 Cocos2d 在 iOS 上的精灵和定位问题

Posted

技术标签:

【中文标题】Box2d 和 Cocos2d 在 iOS 上的精灵和定位问题【英文标题】:Box2d and Cocos2d on iOS issues with sprites and positioning 【发布时间】:2013-03-04 18:13:00 【问题描述】:

我在触摸屏幕时创建新的精灵/身体:

-(void) addNewSpriteAtPosition:(CGPoint)pos

    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position=[Helper toMeters:pos];
    b2Body* body = world->CreateBody(&bodyDef);

    b2CircleShape circle;
    circle.m_radius = 30/PTM_RATIO;

    // Define the dynamic body fixture.
    b2FixtureDef fixtureDef;
    fixtureDef.shape=&circle;
    fixtureDef.density=0.7f;
    fixtureDef.friction=0.3f;
    fixtureDef.restitution = 0.5;
    body-> CreateFixture(&fixtureDef);

    PhysicsSprite* sprite = [PhysicsSprite spriteWithFile:@"circle.png"];
    [self addChild:sprite];
    [sprite setPhysicsBody:body];
    body->SetUserData((__bridge void*)sprite);

这是我的定位助手:

+(b2Vec2) toMeters:(CGPoint)point

    return b2Vec2(point.x / PTM_RATIO, point.y / PTM_RATIO);

PhysicsSprite 是与 Box2D 一起使用的典型方法,但我将包含相关方法:

-(CGAffineTransform) nodeToParentTransform

    b2Vec2 pos = physicsBody->GetPosition();

    float x = pos.x * PTM_RATIO;
    float y = pos.y * PTM_RATIO;

    if (ignoreAnchorPointForPosition_)
    
        x += anchorPointInPoints_.x;
        y += anchorPointInPoints_.y;
    

    float radians = physicsBody->GetAngle();
    float c = cosf(radians);
    float s = sinf(radians);

    if (!CGPointEqualToPoint(anchorPointInPoints_, CGPointZero))
    
        x += c * -anchorPointInPoints_.x + -s * -anchorPointInPoints_.y;
        y += s * -anchorPointInPoints_.x + c * -anchorPointInPoints_.y;
    

    self.position = CGPointMake(x, y);

    // Rot, Translate Matrix
    transform_ = CGAffineTransformMake(c, s, -s, c, x, y);
    return transform_;

现在,我有两个问题,下面两张图片显示了精灵的调试绘制。视网膜和非视网膜版本:

问题 #1 - 正如您在两张图片中看到的那样,对象离 (0,0) 越远,精灵与物理主体的偏移越远。

问题 #2 - 红色圆圈图像文件为 60x60(视网膜),白色圆圈为 30x30(非视网膜)。为什么它们在屏幕上的大小不同? Cocos2d 应该使用点,而不是像素,所以它们在屏幕上不应该是相同的大小吗?

【问题讨论】:

【参考方案1】:

使用 contentSize,而不是硬编码大小。

circle.m_radius = sprite.contentSize.width*0.5f/PTM_RATIO;

这适用于所有 SD 和 Retina 模式。

您可以使用此样式在 box2d 和 cocos2d 位置之间进行同步:

body->SetTransform([self toB2Meters:sprite.position], 0.0f);    //box2d<---cocos2d

//OR
sprite.position = ccp(body->GetPosition().x * PTM_RATIO,
                     body->GetPosition().y * PTM_RATIO);  //box2d--->cocos2d

【讨论】:

关于 contentSize - 您的代码导致非视网膜物理主体与非视网膜精灵大小相同,这很好。然而,在视网膜模式下大约有 9 个圆圈填充了屏幕的宽度,而在非视网膜模式下,大约有 18 个圆圈填充了屏幕。每个都应该是 9,这样体验是一样的。我仍然不明白为什么会这样。在典型的 ios 开发中,30 点半径在任何一种模式下都是相同的,您只是在视网膜模式下获得更高的分辨率。 关于同步码,是否需要手动更新每一帧的定位?我希望它在 PhysicsSprite 中是独立的。换句话说,我该把代码放在哪里? 抱歉,我只使用了带有 b2body 成员和覆盖更新功能的自定义 CCSprite。那你的问题又来了…… 你能发布你的精灵类吗?我迫切希望让这项工作发挥作用,并且会尝试任何事情(现在已经尝试了一个多星期)。 yes..来自laserManager类,并且从主游戏场景调用经理的更新:tick方法。我只使用了一种打勾方法是游戏。

以上是关于Box2d 和 Cocos2d 在 iOS 上的精灵和定位问题的主要内容,如果未能解决你的问题,请参考以下文章

单面平台(Box2D/Cocos2D)

cocos2d + box2d:向点旋转

创建身体 - Cocos2d/Box2d

边缘 - Cocos2d/Box2D

炸弹 - Cocos2d/Box2d

重置精灵 - Box2d(Cocos2d)