2011-12-13 16 views
5

In cocos2d, è possibile semplificare in CCSprites e spostarli in tutti i modi. La cosa più importante è che possono facilitare l'entrata e l'uscita. Per maggior parte dei giochi è auspicabile movimenti fluidi eccSpostamento di corpi Box2d come oggetti CCSprite

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

Quando spostando un corpo box2d, lo sprite collegato ad esso viene aggiornato dopo la fase Box2D(). Spostare lo sprite e quindi aggiornare il corpo non è un'opzione qui, poiché sconfigge completamente lo scopo della struttura fisica.

Quindi l'altra opzione, che ho implementato con successo, consiste nel calcolare lo spostamento, la velocità e l'accelerazione di uno sprite trattandolo come un'entità meccanica a sé stante. Ogni volta che chiamo il mio update() sullo sprite in modo che il personaggio possa decidere dove spostarlo ecc., La mia superclasse memorizza anche la posizione e la velocità precedenti. Questi sono memorizzati come valori conformi a box2d dividendo per PTM_RATIO.

Nella sottoclasse di CCSprite, chiamato 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 { 

} 

ho quindi sottoclasse "FMSprite" in "FMObject", che memorizza un b2Body ecc

Per spostare il corpo , Devo prima spostare uno sprite e tracciarne l'accelerazione, attraverso il quale posso trovare la forza richiesta (usando la massa) necessaria per seguire il movimento dello sprite. Dato che non posso spostare lo sprite dell'oggetto (che è sincronizzato con il corpo), creo un altro sprite chiamato "faro", aggiungilo come un bambino all'oggetto e spostalo. Tutto quello che dobbiamo fare allora è avere una funzione per sincronizzare la posizione del corpo box2d con questo sprite beacon usando le forze che ho menzionato prima.

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

Il risultato è brillante, un movimento allentamento liscia del b2body in movimento dove mai si vuole, senza giocare in giro con una qualsiasi delle sue proprie forze, ma la copia di quella di un CCSprite e replicare il suo moto. Dal momento che sono tutte le forze, non causerà il jitter e le distorsioni quando si scontrano con altri oggetti b2Body. Se qualcuno ha altri metodi per farlo, si prega di inviare una risposta. Grazie!

+0

Ciao, grazie per questo post. Non ho capito una cosa però. Perché hai bisogno di un falò faro? se un oggetto di tipo FMObject (che è un CCSprite) viene spostato usando alcune azioni personalizzate, perché non fare in modo che b2Body in FMObject segua lo sprite genitore. Non sono sicuro di cosa significhi "sincronizzato con il corpo". Perché hai bisogno di uno sprite del faro e spostalo separatamente? – Aks

+0

Sono passati quasi 3 anni da quando ho postato questo, ma penso che tu abbia ragione. Non riesco a vedere la ragione per avere uno sprite di beacon. Penso che sia stato solo un dettaglio di implementazione. Dovresti essere in grado di sostituire il 'FMObject' stesso. –

risposta

4

Quello che faccio è diverso dal tuo, ma può anche spostare i corpi Box2d come gli oggetti CCSprite e persino usare la CCAction. La cosa più importante è creare un oggetto che contenga ccSprite e b2body.

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

E quindi, riscrivere il metodo 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; 
} 

Il metodo setPosition calcola quanto cambia la posizione e lo imposta sul corpo b2.

Spero di aver capito la tua domanda e la risposta è utile per voi ...

+0

Funziona per il posizionamento ma SetTransform imposterà la posizione del corpo ogni volta invece di utilizzare le forze.Ciò significa che quando due oggetti RigidBody si scontrano, creeranno un effetto jitter anziché rimbalzare l'un l'altro senza problemi. Il metodo addForce è più efficace, ma assicurerà che la fisica sia fluida. –

+0

Sì, ma usare la forza è difficile mantenere il corpo in una velocità costante e in una determinata posizione. Non ho mai commesso errori quando uso il mio metodo, ma non ho idea se entrambi i due corpi siano b2_dynamicBody. –

Problemi correlati