Domanda

Questo è probabilmente un problema di base ma non riesco a trovare altri articoli su di esso.

In ogni caso, ho scritto un piccolo programma di palla che rimbalza su Java per cercare di espandere le mie abilità di base. Il programma è solo una semplice palla che rimbalza e che si spera rimbalza per un po '. Il programma originale ha funzionato bene, ma ora ho provato ad aggiungere gravità al programma. La gravità in realtà funziona bene per un po 'ma poi, una volta che i rimbalzi diventano molto piccoli, l'animazione diventa irregolare per un tempo molto breve, quindi la posizione della palla diminuisce costantemente. Ho provato a capire il problema ma non riesco proprio a vederlo. Qualsiasi aiuto sarebbe il benvenuto.

public final class Ball extends Rectangle {
float xspeed = 1.0f; float yspeed = 1.0f; float gravity = 0.4f;


public Ball(float x, float y, float width, float height) {
    super(x, y, width, height);
}

public void update(){
    yspeed += gravity;

    move(xspeed, yspeed);

    if(getX() < 0){
        xspeed = 1;
    }
    if(getX() + getWidth() > 320){
        xspeed = -1;
    }
    if(getY() < 0){
        yspeed = 1;
    }
    if(getY() + getHeight() > 200 && yspeed > 0){
        yspeed *= -0.98f;
    }
    if(getY() + getHeight() > 200 && yspeed < 0){
        yspeed *= 0.98f;
    }

}

public void move(float x, float y){
    this.setX(getX()+x);
    this.setY(getY()+y);
}

}

EDIT: grazie che sembra aver risolto il movimento irregolare. Faccio ancora fatica a vedere come posso impedire alla mia palla di muoversi verso il basso quando ha smesso di rimbalzare. In questo momento si sposterà smettendo di rimbalzare, quindi continuerà a spostarsi verso il basso superato il & Quot; piano & Quot ;. Penso che abbia a che fare con la mia yspeed + = linea di gravità. Non riesco proprio a capire come farei per fermare il movimento.

È stato utile?

Soluzione

Quando lo fai

yspeed += gravity;

stai assumendo che la palla abbia spazio muoviti attraverso una distanza dx = v_i * t + 1/2 (-g) t ^ 2. Quando sei molto vicino al pavimento, questo potrebbe non essere vero. Fallisce se:

  • Sei abbastanza vicino al pavimento e ti stai spostando verso il basso
  • Sei molto vicino al pavimento e hai una bassa velocità (come quando la palla ha perso gran parte della sua energia)

Questo errore fa sì che la tua simulazione smetta di conservare energia , causando un comportamento irregolare che vedi a bassa ampiezza.

Puoi ridurre il problema usando piccoli passi temporali e puoi liberartene completamente se esegui il calcolo del test per notare quando sei fuori stanza e selezionare un passaggio temporale sicuro per che iterazione (ovvero utilizza sempre il valore predefinito a meno che non si verifichi un problema, quindi calcola il passaggio temporale migliore).

Tuttavia, l'approssimazione di base che stai usando qui ha anche altri problemi. Cerca in qualsiasi testo di analisi numerica una discussione sulla risoluzione numerica di equazioni differenziali.

Altri suggerimenti

Per prima cosa: impostare y-speed su 1 quando si rimbalza nella parte superiore della finestra non è corretto, è necessario impostare yspeed su -speed (ma se si inizia all'interno dei bordi, non dovrebbe mai rimbalzare in alto in ogni caso).

In secondo luogo, la tua moltiplicazione per -0,981 quando si rimbalza sul fondo va bene, ma mi preoccupo per la costante gravità 0,4 che viene aggiunta alla velocità ad ogni iterazione. Penso che sia ciò che ti sta causando oscillazioni in basso poiché fai la mossa prima di controllare che può far cadere la palla sotto il livello del suolo.

Vorrei provare a garantire che il valore y non possa mai scendere al di sotto del livello del suolo sostituendo lo spostamento con:

if (getY() + getHeight() + yspeed > 200) {
    move(xspeed, 200 - getY() - getHeight());
} else {
    move(xspeed, yspeed);
}

Il problema è che quando i rimbalzi diventano veramente piccoli,

yspeed *= -0.981;
La linea

verrà chiamata in breve successione. La palla andrà sotto il fondo, inizierà a risalire, ma sarà comunque sotto il fondo (perché 0.981 & Lt; 1.0) alla fine, e si comporterà in modo eradico. Ecco come risolverlo:

if(getY() + getHeight() > 200){
  yspeed *= -0.981;
  setY(400 - getY() - getHeight()); // I believe this is right.
}

Fissando la posizione, non si alternerà tra diminuzione e aumento più rapidamente e non rimarrete bloccati nella situazione in cui diminuisce sempre perché è sempre al di sotto dei limiti.

[EDIT: penso di aver frainteso, quindi probabilmente questo non è molto utile :)]

if(getY() + getHeight() > 200){
  yspeed *= -0.981;
}

Stai negando la velocità verticale ad ogni aggiornamento. Probabilmente proverei a gestire la gravità in sezioni di dimensioni aggiornate. Supponendo che stai facendo 30 aggiornamenti al secondo (per 30 fps), forse qualcosa del genere

// Define some constants
SecondsPerUpdate = (1.0f / 30);
AccelDueToGravity = 0.981;

if(getY() + getHeight() > 200){
  yspeed -= (AccelDueToGravity * SecondsPerUpdate);
}

Sospetto sia perché quando la palla rimbalza, sarà in realtà leggermente al di sotto del " ground " ;, ea basse velocità, non si sposterà di nuovo sopra il terreno in un tick - quindi il prossimo aggiornamento () lo vedrà ancora sotto terra e rimbalzerà di nuovo - ma verso il basso questa volta, quindi il ciclo continua.

Devi rimettere la palla al livello del suolo quando rimbalza, qualcosa del genere:

    if(getY() + getHeight() > 200){
            yspeed *= -0.981;
            setY(200 - getHeight());
    }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top