Il rilevamento delle collisioni rallenta il disegno dello schermo


8

Recentemente ho perseguito lo sviluppo del gioco come un hobby e ho deciso che, per imparare lo sviluppo del gioco, avrei dovuto creare un gioco e renderizzare tutto da solo (senza l'uso di un motore di gioco). Ciò si è rivelato piuttosto complicato, tuttavia sto facendo grandi progressi. Tuttavia, ho riscontrato un problema che penso possa essere correlato al modo in cui i telefoni Android visualizzano la loro grafica e avrò bisogno di alcuni chiarimenti su questo problema.

Il problema

Il mio gioco contiene una serie di palline in un cannone; quando l'utente preme lo schermo, il cannone lancia le palline e il motore (che sto implementando) gestisce gli aggiornamenti delle informazioni sulla posizione e il rilevamento delle collisioni da lì. Ora, prima che avessi implementato il rilevamento delle collisioni, il mio gioco funzionava in modo molto fluido e reattivo, tuttavia quando ho detto al motore di disegnare il tallone solo se è entro i limiti e "rimbalzarlo" dal muro, sembrerebbe che il motore il ciclo ora richiede molto più tempo per essere eseguito.

Questo andrebbe bene, se non fosse per la latenza che sta fornendo all'utente l'esperienza. Ad esempio, quando lo schermo viene toccato ora , occorrono ~ 2 secondi per visualizzare la palla mentre si muove attorno allo schermo, e talvolta non appare affatto . In precedenza, la reazione era istantanea.

Inoltre, quando commento la parte di rilevamento delle collisioni del mio motore fisico, riprende il suo solito comportamento reattivo.

Quello che penso sta causando questo comportamento

Nota: ho ripreso questo presupposto (vedere "Informazioni sul debug" di seguito)

Penso che dal momento che non ho implementato un limitatore di frame per il mio gioco e che il rendering è veloce quanto l'hardware lo consentirà, che sta disegnando sullo schermo così tanti vecchi frame (in qualche buffer, forse?) Che è impegnato a disegnare mentre dovrebbe aggiornare la fisica. Sebbene il mio debug finora non abbia indicato che sia così, non riesco a giungere ad alcuna altra conclusione.

Qualche codice

Nota che questo codice sarà piuttosto confuso per capire non sapere cosa fa tutto. L'ho semplicemente incluso nel caso in cui qualcuno fosse particolarmente interessato ad avere del codice con cui lavorare. Le variabili sono chiarite sotto l'estratto.

PhysicsEngine.updateBeadPositions (float) :

private void updateBeadPositions(float delta){

    //Update all of the beads currently on the board.
    beads = control.getBoard().getValues();

    temp_x = 0.0f;
    temp_y = 0.0f;

    //For each row...
    for(Bead[] row : beads){

        //For each bead...
        for(Bead bead : row){

            //If this bead exists...
            if(bead != null){

                temp_y = (float) (bead.getYCoordinate() * bead.getYVelocity() * delta);

                //If the coordinates are within the bounds of the game
                if(outwithVerticalBounds(temp_y, control.getBoard())){

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    bead.setXCoordinate(temp_x);

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    bead.setYCoordinate(temp_y);
                }
            }
        }
    }

    //If the cannon Bead has been set...
    if(control.getCannon().getReleased() != null){

        //Update the cannon bead
        if(control.getCannon().getReleased().getXVelocity() == PhysicsEngine.VELOCITY_STATIC && control.getCannon().getReleased().getYVelocity() == PhysicsEngine.VELOCITY_STATIC){

            control.getCannon().getReleased().setXCoordinate(control.getCannon().getX());
            control.getCannon().getReleased().setYCoordinate(control.getCannon().getY() - Cannon.PIVOT_Y_OFFSET);
        }
        else{

            temp_x = control.getCannon().getReleased().getXCoordinate() + (control.getCannon().getReleased().getXVelocity() * delta);
            temp_y = control.getCannon().getReleased().getYCoordinate() + (control.getCannon().getReleased().getYVelocity() * delta);

            //TODO: Commented out collision checkers!

            //If the horizontal coordinates are within the bounds of the game
            if(!outwithHorizontalBounds(temp_x, control.getBoard())){

                //If the vertical coordinates are within the bounds of game
                if(!outwithVerticalBounds(temp_y, control.getBoard())){

                    //Set the X coordinate equal to the distance * the time differential (delta).       
                    control.getCannon().getReleased().setXCoordinate(temp_x);

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    control.getCannon().getReleased().setYCoordinate(temp_y);
                }
                //Otherwise...
                else{

                    //Bounds off the wall in the y direction
                    control.getCannon().getReleased().setYVelocity(-1.0f * control.getCannon().getReleased().getYVelocity());
                }
            }
            //Otherwise...
            else{

                //Bounce off the wall in the x direction (flip the x velocity)
                control.getCannon().getReleased().setXVelocity(-1.0f * control.getCannon().getReleased().getXVelocity());
            }
        }
    }
}

Qui, le variabili sono definite come:

  • controlè un riferimento al mio controller di gioco. Confeziona la maggior parte del codice di gioco.

  • beads è un riferimento all'array 2D che contiene attualmente le perline sulla scheda (escluso quello che si sta muovendo)

  • delta è la differenza di tempo tra le chiamate precedenti al motore fisico e la chiamata corrente

Vedi i commenti all'interno del codice per qualsiasi altra spiegazione.

PhysicsEngine.outwithHorizontalBounds (float, Board) :

private boolean outwithHorizontalBounds(float x, Board board){

    //If the horizontal values are within the bounds...
    if(x > (board.getRight() - bead_radius)){

        return true;
    }

    if(x < (board.getLeft() + bead_radius)){

        return true;
    }

    //Otherwise, it is not.
    return false;
}

Il metodo ha outwithVerticalBounds(float, Board)funzionalità equivalenti, ma nella direzione y.


La mia domanda

Che dire del rilevamento delle collisioni causerebbe l'inibizione così drastica del rendering dello schermo? So che è un'operazione molto intensa, ma il mio debug ha dimostrato che gli aggiornamenti della fisica si stanno completando contemporaneamente ai sorteggi.

Informazioni sul debug

Ultimo aggiornamento: 29 gen 2013 16:27 EST

Ecco un'aggregazione delle informazioni di debug che ho ottenuto finora. Aggiornerò questo col passare del tempo:

  • Il update()metodo all'interno del mio motore richiede in media solo .018 msl'esecuzione. Di solito, il ritardo passa a 0.020 msquando tocco lo schermo per rilasciare il tallone.

  • Dopo aver confrontato i tempi dei sorteggi e gli aggiornamenti del gioco, sembrerebbe che io avessi ragione: si stanno verificando contemporaneamente . Quindi, questo non potrebbe essere il problema, giusto?

  • Il FPSgioco è approssimativamente 87, spike casualmente a (nella fascia bassa) 60 FPS, tuttavia questo spike non è correlato al rilascio del tallone. Non ci sono FPSsvantaggi nel fare questo. Ciò ha senso poiché l'unica parte che aumenta la sua complessità dopo il rilascio del cordone è la update()chiamata, il disegno avviene comunque il più velocemente possibile.

  • Dopo ulteriori test, è diventato evidente che non è così che lo schermo è in ritardo rispetto alla fisica. Ho provato questo con una semplice bandiera booleana in cui lo sfondo dello schermo diventava bianco quando lo toccavo, e questo accade immediatamente . Quindi, ci deve essere qualche altra causa per il tallone che non si disegna. Aggiornerò presto.

Informazioni supplementari

Ecco alcune informazioni supplementari che dovrebbero aiutarti a capire le mie circostanze:

  • Sto testando questo su un Google Nexus 7.

  • Ci sono alcune perline sulla mappa che vengono aggiornate contemporaneamente (circa 30), ma solo una di esse si sta muovendo.

  • Di solito, dopo che il tallone inizia a muoversi (dopo il ritardo iniziale e se effettivamente disegna), continua a muoversi in modo molto regolare.

  • È importante notare che sullo schermo sono presenti altri elementi dell'interfaccia utente che si aggiornano in risposta all'evento touch. Ad esempio, il tallone caricato nel cannone diventa un nuovo tallone quando viene toccato lo schermo (a indicare che è stato rilasciato), ma il tallone mobile non viene semplicemente disegnato.


Pensi che il tuo debug che mostra gli aggiornamenti della fisica in linea con le estrazioni potrebbe essere impreciso? Hai fatto altri profili con questo codice?
MichaelHouse

Ho effettuato un ampio debug utilizzando gli output per la console (LogCat), ma nulla di più complicato di così. È possibile che le mie dichiarazioni di debug siano errate, le esaminerò ora.
Squagem,

Inoltre è interessante sapere se l'FPS (frame per secondo) cambia quando si aggiunge il caso limite o che il problema non è correlato alla velocità di esecuzione del programma.
Qqwy,

Ho modificato la mia domanda per rispondere ai punti sollevati.
Squagem,

Risposte:


8

Francamente, sono piuttosto imbarazzato nell'annunciare la soluzione al mio problema mentre trascorrevo molte ore alla ricerca di esso, ed era così semplice e avrebbe potuto essere evitato così facilmente con un po 'meno negligenza da parte mia. Il lato positivo è che ho trovato alcuni altri pezzi di codice che ora posso ottimizzare per prestazioni ancora migliori!

La soluzione

Il cannone che lanciava il tallone era sotto il limite inferiore della mia area giocabile.

Questo è stato fuorviante perché il limite inferiore della mia area di gioco è un po 'sopra la parte inferiore dello schermo reale del telefono. Quindi, fondamentalmente, il motore fisico lo stava rimbalzando indietro e il quarto in modo così lieve (invisibile all'ispezione umana) per circa 5 secondi prima che fosse reso sullo schermo.

Ho spostato il cannone di 50 pixel più in alto e ora funziona come previsto.


Grazie a tutti per il vostro aiuto! Non sarei arrivato qui senza i tuoi suggerimenti ponderati.


3
+1 per una domanda ben formattata e +1 per la risposta autonoma
RoughPlace

Spiacenti, ho dimenticato questa domanda! Grazie ragazzi :)
Squagem
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.