web-dev-qa-db-fra.com

Java boucle de jeu principale

J'écris une boucle de jeu, j'ai trouvé le code dans l'exemple ci-dessous ici . J'ai également examiné d'autres façons de faire une boucle de jeu, comme à partir de cet article . Je n'ai pas réussi à faire fonctionner ceux-là. J'ai donc gardé celui du premier lien.

Ce que j'aimerais savoir:

  • La façon dont j'ai écrit ma boucle de jeu est-elle un bon moyen de le faire?
    • Aucune suggestion?
  • Dois-je utiliser Thread.sleep(); dans ma boucle de jeu?

Voici mon code actuel:

public void run(){
    long lastLoopTime = System.nanoTime();
    final int TARGET_FPS = 60;
    final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
    long lastFpsTime = 0;
    while(true){
        long now = System.nanoTime();
        long updateLength = now - lastLoopTime;
        lastLoopTime = now;
        double delta = updateLength / ((double)OPTIMAL_TIME);

        lastFpsTime += updateLength;
        if(lastFpsTime >= 1000000000){
            lastFpsTime = 0;
        }

        this.updateGame(delta);

        this.repaint();

        try{
            Room.gameTime = (lastLoopTime - System.nanoTime() + OPTIMAL_TIME) / 1000000;
            System.out.println(Room.gameTime);
            Thread.sleep(Room.gameTime);
        }catch(Exception e){
        }
    }
15
Get Off My Lawn

Finalement, vous voudrez passer à quelque chose comme LWJGL , mais permettez-moi de souligner, continuez à faire ce que vous faites ici pour l'instant. Il vous apprendra les bases.

Bon travail sur votre boucle. Looks Nice, permettez-moi de vous offrir quelques conseils:

  • Repeindre ne rendra pas l'écran immédiatement. Il indique au RepaintManager de s'afficher lorsqu'il est prêt. Utilisation invaliderpaintImmediately à la place. paintImmediately bloquera l'exécution jusqu'à ce que le composant soit redessiné afin que vous puissiez mesurer le temps de rendu.

  • Thread.sleep a généralement une dérive de quelques millisecondes. Vous devriez l'utiliser pour éviter que votre boucle n'utilise trop de CPU, mais assurez-vous de comprendre que si vous dormez 10 millisecondes, vous pouvez dormir 5 millisecondes ou vous pouvez dormir 20.

  • Enfin:

    double delta = updateLength / ((double)OPTIMAL_TIME);
    

    Si updateLength est inférieur à OPTIMAL_TIME, n'appelez pas update. En d'autres termes, si delta est inférieur à un, ne mettez pas à jour. Ce tutoriel explique pourquoi mieux que jamais.

14
William Morrison

Dans l'ensemble, c'est une bonne boucle, mais il y a quelques aspects manquants à ce que j'ai trouvé par expérience comme la meilleure boucle.

Vous voudrez éventuellement passer à LWJGL ou à un autre Java API de jeu, mais pour l'instant, apprenez les bases de la façon dont les boucles de jeu fonctionnent et ce qui convient le mieux à vos besoins.

  • Tout d'abord, en réponse à l'un de vos points, non. Vous ferez mieux de rester loin de

    Thread.sleep ()

    cela peut s'écarter de la durée réelle de mise en veille.
    par exemple. si vous le mettez en veille pendant 10 millisecondes, il peut mettre le programme en veille pendant 5 à 20 millisecondes.

  • Le deuxième problème que je vois immédiatement est que vous n'avez aucun moyen d'arrêter la boucle de jeu pour une méthode stop () personnalisée. Essayer

    boolean running = true;
    en courant) {
    // Votre code ici //
    }

  • Troisièmement, vous voudrez peut-être envisager de modifier la façon dont vous utilisez votre variable delta. Le chemin dans le code ci-dessous peut être une meilleure utilisation et construction pour vous.

    Voici un exemple de ma boucle de jeu que j'utilise dans mes programmes:

    @Override
    public void run() {
    
    long initialTime = System.nanoTime();
    final double timeU = 1000000000 / UPS;
    final double timeF = 1000000000 / FPS;
    double deltaU = 0, deltaF = 0;
    int frames = 0, ticks = 0;
    long timer = System.currentTimeMillis();
    
        while (running) {
    
            long currentTime = System.nanoTime();
            deltaU += (currentTime - initialTime) / timeU;
            deltaF += (currentTime - initialTime) / timeF;
            initialTime = currentTime;
    
            if (deltaU >= 1) {
                getInput();
                update();
                ticks++;
                deltaU--;
            }
    
            if (deltaF >= 1) {
                render();
                frames++;
                deltaF--;
            }
    
            if (System.currentTimeMillis() - timer > 1000) {
                if (RENDER_TIME) {
                    System.out.println(String.format("UPS: %s, FPS: %s", ticks, frames));
                }
                frames = 0;
                ticks = 0;
                timer += 1000;
            }
        }
    }
    
4
Robert E Fry