Recentemente, tenho buscado o desenvolvimento de jogos como um hobby e decidi que, para aprender as vantagens e desvantagens do desenvolvimento de jogos, eu deveria criar um jogo e renderizar tudo sozinho (sem o uso de um mecanismo de jogo). Isso se mostrou um pouco complicado, mas estou fazendo um grande progresso. No entanto, eu me deparei com um problema que acho que pode estar relacionado à maneira como os telefones Android renderizam seus gráficos e precisará de alguns esclarecimentos sobre esse assunto.
O problema
Meu jogo contém uma série de bolas em um canhão; quando o usuário pressiona a tela, o canhão lança as bolas e o mecanismo (que estou implementando) lida com as atualizações das informações de localização e da detecção de colisão a partir daí. Agora, antes de implementar a detecção de colisão, meu jogo era executado de maneira muito suave e responsiva, no entanto, quando eu disse ao mecanismo para desenhar a conta apenas dentro dos limites e "rebatê-la" da parede, caso contrário, parece que o mecanismo O loop agora leva uma quantidade significativamente maior de tempo para ser executado.
Isso seria bom, se não fosse a latência que está fornecendo à experiência do usuário. Por exemplo, quando a tela é tocada agora , leva aproximadamente 2 segundos para que a bola seja exibida se movendo pela tela e, às vezes, ela não aparece . Anteriormente, a reação era instantânea.
Além disso, quando eu comento a parte de detecção de colisão do meu mecanismo de física, ele retoma seu comportamento responsivo usual.
O que eu acho que está causando esse comportamento
Nota: Recusei essa suposição (consulte 'Informações sobre depuração' abaixo)
Eu acho que, como não tenho um limitador de quadro implementado para o meu jogo, e ele está renderizando o mais rápido que o hardware permitir, está desenhando tantos quadros antigos (em algum buffer, talvez?) Na tela que ele está ocupado desenhando enquanto deveria estar atualizando a física. Embora minha depuração até o momento não tenha indicado que esse é o caso, não consigo chegar a nenhuma outra conclusão.
Some Code
Observe que esse código será um pouco confuso para entender sem saber o que tudo faz. Eu simplesmente o incluí no caso de alguém ser específico sobre ter algum código para trabalhar. As variáveis são esclarecidas abaixo do trecho.
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());
}
}
}
}
Aqui, as variáveis são definidas como:
control
é uma referência ao meu controlador de jogo. Empacota a maioria do código do jogo.beads
é uma referência à matriz 2D que contém as contas no quadro atualmente (excluindo a que está em movimento)delta
é o diferencial de tempo entre as chamadas anteriores para o mecanismo de física e a chamada atual
Veja os comentários no código para outras explicações.
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;
}
O método outwithVerticalBounds(float, Board)
é de funcionalidade equivalente, mas na direção y.
Minha pergunta
E a detecção de colisão faria com que a renderização da tela fosse inibida de maneira tão drástica? Eu sei que é uma operação muito intensiva, mas minha depuração mostrou que as atualizações físicas estão sendo concluídas nos mesmos horários que os sorteios.
Informações de depuração
Última atualização: 29 de janeiro de 2013 16:27 EST
Aqui está uma agregação das informações de depuração que obtive até agora. Vou atualizar isso à medida que o tempo avança:
O
update()
método dentro do meu mecanismo leva, em média, apenas.018 ms
para ser executado. Geralmente, o atraso aumenta0.020 ms
quando toco na tela para liberar a conta.Depois de comparar os horários dos sorteios e as atualizações do jogo, parece que eu estava correto: eles estão ocorrendo simultaneamente . Assim, este não poderia ser o problema, certo?
O
FPS
jogo é mais ou menos87
, ele dispara aleatoriamente para (na extremidade inferior)60 FPS
, no entanto, esse aumento não está relacionado à liberação do cordão. Não háFPS
desvantagens em fazer isso. Isso faz sentido, uma vez que a única parte que aumenta sua complexidade após o lançamento do cordão é aupdate()
chamada, o desenho ainda acontece o mais rápido possível.Após mais testes, tornou-se evidente que esse não é o caso de a tela estar atrasada em relação à física. Testei isso com uma bandeira booleana simples, na qual o fundo da tela ficaria branco quando o tocasse, e isso acontece imediatamente . Portanto, deve haver outra causa para o cordão não esticar. Vou atualizar em breve.
Informação complementar
Aqui estão algumas informações adicionais que devem ajudá-lo a entender minhas circunstâncias:
Estou testando isso no Google Nexus 7.
Existem algumas contas no mapa que estão sendo atualizadas de uma só vez (cerca de 30), mas apenas uma delas está em movimento.
Geralmente, depois que o cordão começa a se mover (após o atraso inicial e se ele realmente puxa), ele continua a se mover de maneira muito suave.
É importante observar que tenho outros elementos da interface do usuário na tela que são atualizados em reação ao evento de toque. Por exemplo, o cordão carregado no canhão se torna um cordão novo quando a tela é tocada (significando que foi liberada), mas o cordão móvel simplesmente não é desenhado.
Respostas:
Sinceramente, tenho vergonha de anunciar a solução para o meu problema, pois passei muitas horas em busca dele, e era tão simples e poderia ter sido evitado tão facilmente com um pouco menos de negligência em meu nome. Pelo lado positivo, acabei encontrando alguns outros trechos de código que agora posso otimizar para obter um desempenho ainda melhor!
A solução
O canhão que estava lançando a conta estava abaixo do limite inferior da minha área jogável.
Isso foi enganoso, porque o limite inferior da minha área de jogo está um pouco acima da parte inferior da tela real do telefone. Então, basicamente, o mecanismo de física o estava devolvendo e o quarto levemente (invisível à inspeção humana) por cerca de 5 segundos antes de ser renderizado na tela.
Movi o canhão 50 pixels mais alto e ele funciona como pretendido agora.
Obrigado a todos pela ajuda! Eu não teria chegado aqui sem suas sugestões.
fonte