Come potrei spostare un personaggio in un gioco di ruolo con Bullet Physics / Ogre3D?


9

ultimamente ho avuto problemi con lo spostamento del mio personaggio nel mio gioco Ogre3D. Fondamentalmente sto spostando il personaggio con la RigidBody->translate()funzione proiettile , ma quando lo faccio e sbatto contro un muro, lo percorro leggermente e poi rimbalzo. Mi chiedo se c'è un altro buon modo per spostare il mio personaggio (che ha una forma di collisione a sfera) in un semplice mondo di tipo aereo con pareti?

Le librerie che sto usando che sono relative a questo sono 'Ogre3D' e 'Bullet Physics'.

Risposte:


9

Anche se non ho lavorato specificamente con il motore di fisica dei proiettili, ho fatto qualcosa di molto simile in un altro motore di fisica. Il modo in cui l'ho risolto è stato quello di impostare la velocità lineare del corpo rigido invece di tradurla direttamente. Il movimento e le collisioni sono stati quindi gestiti automaticamente dalla fase di aggiornamento del motore fisico.

Dalla documentazione sembra esserci un btRigidBody::setLinearVelocitymetodo che puoi usare. Quindi, ad esempio, se non si desidera che si verifichino accelerazioni, è sufficiente impostare la velocità lineare su un valore appropriato ogni volta che il personaggio si sta muovendo e riportarlo su (0,0,0) quando il personaggio dovrebbe fermarsi (es. quando il giocatore rilascia la chiave).

Per quanto riguarda quali valori usare, l'approccio abituale sarebbe iniziare con la velocità desiderata del tuo personaggio (come un float / scalare) e poi moltiplicarlo per un vettore normalizzato che punta nella direzione in cui vuoi muoverti. Da quello che posso vedere la btVector3classe ha già dei metodi per tutto questo.

In alternativa, potresti considerare di trattare il personaggio come un oggetto fisico completo e gestire il movimento usando il metodo applyForceo applyImpulse. Ciò comporterebbe un'accelerazione del corpo, quindi i tuoi personaggi avranno slancio e i risultati probabilmente sembreranno più belli in questo modo. Ma devi prendere alcune misure extra, ad esempio, assicurandoti che la velocità lineare non superi mai un certo limite, o bloccandola o giocando con smorzamento / attrito. Quindi sarà un po 'più difficile da implementare e perfezionare.

Sperimenta con entrambi gli approcci e poi scegli quello che si comporta più vicino alle tue esigenze.


Bene, grazie per la rapida risposta, ho intenzione di provarlo subito.
Molmasepic

Il trucco LinearVelocity ha funzionato esattamente come un incantesimo! Ci sono stati alcuni scherzi che ho dovuto risolvere, ma funziona al 100% Grazie mille per la risposta!
Molmasepic

9

Per la cronaca, la mia esperienza con la fisica sta usando Chimpunk in un motore di gioco 2D, ma sono abbastanza sicuro che questo concetto si traduca perfettamente in 3D.

Suppongo che il tuo personaggio sia un corpo fisico con peso e così via. Il modo migliore per farlo è fare una simulazione del camminare molto semplificata. Pensala in questo modo: se stai in piedi, i tuoi piedi hanno un sacco di attrito, quindi non scivoli semplicemente. Quando ti muovi, è all'incirca equivalente a rimuovere quell'attrito (poiché non resisti al movimento con i piedi) e applicare una forza di direzione. Sto Non dicendo che si dovrebbe simulare singolarmente ogni piede spingendo a terra - un corpo rigido è ciò che si desidera.

  • Quando il tuo personaggio non sta attivamente cercando di muoversi, aumenta la velocità di smorzamento in modo che rimangano fermi.
  • Quando il tuo personaggio si sta muovendo, abbassa lo smorzamento della velocità e applica una forza nella direzione del movimento. Imposta lo smorzamento e la forza in modo che il personaggio si muova a una velocità ragionevole.
  • Se il personaggio è in aria, imposta lo smorzamento molto, molto basso. Se vuoi essere realistico, non permettere loro di applicare alcuna forza per cambiare direzione mentre sono in volo. Puoi colpire un mezzo felice qui permettendo loro di applicare una forza molto più piccola, dando loro una capacità limitata di regolare la loro traiettoria durante il parto.

Ecco dove ottenere diventa un po 'complicato:

  • Se il personaggio si sta già muovendo e cambiano direzione, dovrai compensare il tuo slancio regolando la direzione in cui applichi la forza. Ad esempio, se il tuo personaggio si sta muovendo verso nord e gira verso est, devi applicare la tua forza in una direzione che si trova a metà strada tra l'opposto dell'attuale direzione di viaggio del personaggio e la direzione di viaggio prevista. Man mano che la direzione di viaggio cambia, regola la forza in modo che sia sempre a metà strada tra i due, e il tuo personaggio cambierà rapidamente e senza intoppi.

Se ottimizzi la tua forza e smorza correttamente, l'applicazione di una forza ti darà sempre il risultato più realistico, in particolare se il personaggio spingerà gli oggetti in giro. La traduzione sarà il modo peggiore per farlo, dal momento che il motore fisico non lo considera realmente movimento. L'impostazione diretta della velocità è leggermente migliore, ma nella mia esperienza i risultati migliori possono essere ottenuti usando la forza e lo smorzamento.

Spero di averlo spiegato abbastanza bene. Sentiti libero di chiedere se hai bisogno di chiarimenti. :)


0

Per il proiettile 2.87 sembra che il metodo corretto sia quello di avere un tick callback che si aggiorni alla frequenza di aggiornamento della simulazione interna (probabilmente molti 100s di Hz), e setWorldTransform () su corpi cinematici aggiornerà senza problemi la posizione:

Questa parte è nel manuale:

// set the rigid body as kinematic
rigid_body->setCollisionFlags(
    rigid_body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
rigid_body->setActivationState(DISABLE_DEACTIVATION);
...

Questa parte è stata più difficile da capire:

void externalTickCallback(btDynamicsWorld *world, btScalar timeStep)
{
  // get object passed into user data point
  Foo* foo = static_cast<Foo*>(world->getWorldUserInfo());
  ... loop through all the rigid bodies, maybe foo has them
  {
    if (rigid_body->getCollisionFlags() & btCollisionObject::CF_KINEMATIC_OBJECT)
    {
      btVector3 kinematic_linear_vel = ... // get velocity from somewhere
      btTransform trans;
      rigid_body->getMotionState()->getWorldTransform(trans);
      trans.setOrigin(trans.getOrigin() + kinematic_linear_vel * time_step);
      // TODO support angular velocity
      rigid_body_->getMotionState()->setWorldTransform(trans);
    }
  }
}
...
my_dynamics_world->setInternalTickCallback(tickCallback, static_cast<void*>(this), true);

Questa è stata una documentazione utile in btRigidBody.h https://github.com/bulletphysics/bullet3/blob/master/src/BulletDynamics/Dynamics/btRigidBody.h :

/// - C) Oggetti cinematici, che sono oggetti senza massa, ma l'utente può spostarli. Esiste un'interazione a senso unico e Bullet calcola una velocità in base al timestep e alla trasformazione del mondo precedente e attuale.

setLinearVelocity () non funziona per gli oggetti cinematici (forse era usato nelle versioni precedenti?). Ma il mondo della dinamica comprenderà setWorldTransform () e le chiamate a getLinearVelocity () sull'oggetto cinematico restituiranno la velocità impostata nel callback tick (probabilmente restituirà una media se tali velocità dovessero cambiare da tick interno a tick).

https://github.com/bulletphysics/bullet3/issues/1204 - il poster del problema ha l'idea giusta ma la risposta non è utile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.