2011-12-13 24 views
5

En cocos2d, puede facilitar CCSprites y moverlos de muchas maneras. Lo más importante es que pueden tener una entrada/salida relajada. Para la mayoría de los juegos de esto es deseable para el movimiento suave etc.Moviendo cuerpos Box2d como objetos CCSprite

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

Cuando se mueve un cuerpo box2d, el sprite unido a él se actualiza después de la etapa box2d(). Mover el sprite y luego actualizar el cuerpo no es una opción aquí, ya que es totalmente contrario al propósito del marco de la física.

Así que la otra opción, que he implementado con éxito, es calcular el desplazamiento, la velocidad y la aceleración de un sprite, tratándolo como una entidad mecánica por derecho propio. Cada vez que llamo a mi actualización() en el sprite para que el personaje pueda decidir dónde moverme, etc., mi superclase también almacena la posición y la velocidad previas. Estos se almacenan como valores que cumplen con box2d dividiendo por el PTM_RATIO.

En la subclase de CCSprite, llamado 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 { 

} 

I han entonces subclase "FMSprite" en "FMObject", que almacena un b2Body etc.

Con el fin de mover el cuerpo , Primero debo mover un sprite y rastrear su aceleración, a través del cual puedo encontrar la fuerza requerida (usando la masa) necesaria para seguir el movimiento del sprite. Como no puedo mover el objeto del objeto (que está sincronizado con el cuerpo), hago otro objeto llamado "baliza", lo agrego como un niño al objeto y lo muevo. Todo lo que necesitamos hacer entonces es tener una función para sincronizar la posición del cuerpo de box2d con este sprite de beacon usando las fuerzas que mencioné antes.

-(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)]; 
} 

El resultado es brillante, un movimiento suave de la flexibilización b2body en movimiento donde cada vez que quiera que, sin jugar con cualquiera de sus propias fuerzas, sino más bien la copia de la de un CCSprite y replicar su movimiento. Como se trata de todas las fuerzas, no causará agitación y distorsiones al colisionar con otros objetos b2Body. Si alguien tiene otros métodos para hacer esto, publique una respuesta. ¡Gracias!

+0

Hola, gracias por esta publicación. No he entendido una cosa sin embargo. ¿Por qué necesitas un sprite de baliza? si un objeto de tipo FMObject (que es un CCSprite) se mueve con alguna acción personalizada, ¿por qué no hacer que el b2Body en FMObject siga al sprite padre? No estoy seguro de qué significa 'sincronizado con el cuerpo'. ¿Por qué necesita un sprite de baliza por separado y moverlo? – Aks

+0

Han pasado casi 3 años desde que publiqué esto, pero creo que tienes razón. No puedo ver el motivo para tener un sprite de baliza. Creo que fue solo un detalle de implementación. Debería poder sustituir el 'FMObject' en sí mismo. –

Respuesta

4

Lo que hago es diferente del tuyo, pero también puedo mover cuerpos de Box2d como CCSprite Objects e incluso utilizar CCAction. Lo más importante es crear un objeto que contenga ccSprite y b2body.

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

Y a continuación, vuelva a escribir el método 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; 
} 

El método setPosition calcular cuánto el cambio de posición, y la pusieron a la b2body.

Espero haber entendido su pregunta y la respuesta es útil para usted ...

+0

Esto funciona para el posicionamiento pero SetTransform establecerá la posición del cuerpo cada vez en lugar de usar fuerzas.Esto significa que cuando dos objetos RigidBody colisionan, crearán un efecto de oscilación en lugar de rebotar el uno contra el otro sin problemas. El método addForce es más trabajo, pero asegurará que la física sea fluida. –

+0

Sí, pero el uso de la fuerza es difícil de mantener el cuerpo en una velocidad constante y en una posición determinada. Nunca uso ningún error cuando uso mi método, pero no tengo idea si ambos cuerpos son b2_dynamicCuerpo. –

Cuestiones relacionadas