2011-12-13 35 views
5

在cocos2d中,您可以在CCSprites中放松并以各种方式移动它们。最重要的是 - 他们可以放宽/缩小。对于大多数游戏这是理想的平稳运动等像CCSprite对象一样移动Box2d实体

id action = [CCMoveTo actionWithDuration:dur position:pos]; 
move = [CCEaseInOut actionWithAction:action rate:2]; 
[self runAction: move]; 

当移动box2d的身体,与它相连的子画面的Box2D的步骤之后被更新()。移动精灵然后更新正文并不是一个选项,因为它完全违背了物理框架的目的。

因此,我已经成功实现的另一个选项是通过将精灵当作一个机械实体来计算精灵的位移,速度和加速度。每次我在精灵上调用我的update()以便角色可以决定在哪里移动等,我的超类也会存储以前的位置和速度。这些通过除以PTM_RATIO而被存储为符合box2d的值。

在CCSprite的亚类,称为FMSprite:

-(CGPoint) displacement { 
    return ccpSub(self.position, lastPos); 
} 

-(b2Vec2) getSpriteVelocity:(ccTime)dt { 
    return b2Vec2(self.displacement.x/dt/PTM_RATIO, 
        self.displacement.y/dt/PTM_RATIO); 
} 

-(b2Vec2) getSpriteAccel:(ccTime)dt { 
    b2Vec2 currVel = [self getSpriteVelocity:dt]; 
    if (dt == 0) { 
     return b2Vec2(0,0); 
    } else {  
     float accelX = (currVel.x - lastVel.x)/dt; 
     float accelY = (currVel.y - lastVel.y)/dt; 
     return b2Vec2(accelX, accelY); 
    } 
} 

// This is called each update() 
-(void) updateLast:(ccTime)dt { 
    // MUST store lastVel before lastPos is updated since it uses displacement 
    lastVel = [self getSpriteVelocity:dt]; 
    lastPos = ccp(self.X, self.Y); 
} 

// Leave this method untouched in subclasses 
-(void) update:(ccTime)dt { 
    [self updateObject:dt]; 

    // Store previous update values 
    [self updateLast:dt]; 
} 

// Override this method in subclasses for custom functionality 
-(void) updateObject:(ccTime)dt { 

} 

我已经然后子类 “FMSprite” 到 “FMObject”,其存储b2Body等

为了移动所述主体,我必须先移动一个精灵并跟踪它的加速度,通过它我可以找到跟随精灵运动所需的力(使用质量)。由于我无法移动对象的精灵(它与身体同步),因此我将另一个精灵称为“信标”,将它作为孩子添加到对象,然后移动它。我们所需要做的就是使用我之前提到的力量来使一个box2d主体的位置与这个信标精灵同步。

-(void) followBeaconWithDelta:(ccTime)dt { 
    float forceX = [beacon getSpriteAccel:dt].x * self.mass; 
    float forceY = [beacon getSpriteAccel:dt].y * self.mass; 
    [self addForce:b2Vec2(forceX, forceY)]; 
} 

结果是辉煌的,移动b2body平稳宽松运动在任何你想要它,没有任何自己的力量打转转,而是复制一个CCSprite和复制它的运动。由于它是所有的力量,所以当碰撞其他b2Body物体时不会引起抖动和扭曲。如果有人有任何其他方法来做到这一点,请发表一个答案。谢谢!

+0

嗨,感谢您发布此信息。我还没有理解一件事。你为什么需要一个灯塔精灵?如果FMObject类型的对象(它是CCSprite)正在使用某个自定义动作移动,为什么不使FMObject中的b2Body跟随父Sprite。我不确定'同步化到身体'的含义。你为什么分别需要一个灯塔精灵并移动它? – Aks

+0

我发布这个已经有近3年了,但我认为你可能是对的。我看不到有灯塔精灵的原因。我认为那只是一个实现细节。你应该能够替代'FMObject'本身。 –

回答

4

我所做的与你的不同,但也可以像CCSprite对象一样移动Box2d Body,甚至使用CCAction。 最重要的是创建一个包含ccSprite和b2body的对象。

@interface RigidBody : CCNode { 
    b2Body *m_Body; 
    CCSprite *m_Sprite; 
} 

然后重写setPosition方法。

-(void)setPosition:(CGPoint)position 
{ 
    CGPoint currentPosition = position_; 
    b2Transform transform = self.body->GetTransform(); 
    b2Vec2 p = transform.p; 
    float32 angle = self.body->GetAngle(); 
    p += [CCMethod toMeter:ccpSub(position, currentPosition)]; 
    self.body->SetTransform(p, angle); 
    position_ = position; 
} 

setPosition方法计算位置变化多少,并将其设置为b2body。

我希望我已理解您的问题,答案对您有所帮助...

+0

这适用于定位,但SetTransform将每次设置身体位置而不是使用力。这意味着当两个刚体对象碰撞时,它们将产生抖动效果而不是平滑地反弹。 addForce方法是更多的工作,但会确保物理流畅。 –

+0

是的,但是使用力量很难让身体保持稳定的速度和确定的姿势。当我使用我的方法时,我从不会犯任何错误,但我不知道两个身体是否都是b2_dynamicBody。 –