6
votes

Aide au développement du jeu. Render boucle?

Je travaille sur un jeu simple, c'est mon premier projet de jeu.

La plupart des échantillons que je trouve avoir une boucle de rendu où toute la logique du jeu est faite aussi et je n'aime tout simplement pas ça. Disons que j'ai une balle avec x = 0 et un mur en x = 10 et dans une machine lente, la première boucle place la balle en x = 7 et dans une seconde boucle, il place la balle en x = 14. Il serait juste de planter le jeu!

Est-ce que cette "boucle de rendu" est la bonne façon de faire des jeux? Devrais-je écrire du code pour vérifier les choses comme ceci dans chaque cadre? Exemple, nouveau cadre x = 14, la dernière image a x = 7, donc je devrais vérifier s'il y a quelque chose de x = 7 à x = 14 ??

Je pensais que je devrais avoir un fil séparé pour la logique de jeu et dans la boucle de rendu, je devrais simplement "prendre un instantané" de la logique de jeu actuelle et afficher cela, non?

Comment les gars, les développeurs de jeux expérimentés travaillent autour de cela?

Merci!


0 commentaires

7 Réponses :


0
votes

de mon expérience limitée dans la conception de gibier et de l'AI, je dirais d'avoir une boucle logique et une boucle d'affichage (beaucoup comme Xna installe). La boucle logique (méthode de mise à jour dans XNA) gérera fondamentalement la mise à jour des positions et ce qui n'est pas, tandis que la boucle d'affichage (la méthode de dessin dans XNA) attire tout à l'écran. En ce qui concerne la détection de collision, je vais personnellement localiser cela à votre balle. Quand il se déplace, il faut une collision et réagir de manière appropriée.

Le threading est un autre sujet, mais à mon avis, je dirais de ne pas séparer la mise à jour et de dessiner. Cela semble intrinsèquement méchant pour moi d'avoir potentiellement 2 tirages pour 1 mise à jour ou vice versa. Pourquoi dessiner si rien n'a mis à jour ... ou pourquoi mettre à jour plusieurs fois avant de montrer à l'utilisateur ce qui se passe.

Juste mes opinions, espérons que je ne suis pas un chemin hors base.


0 commentaires

3
votes

Si vous créez un fil séparé pour cela, vous créez également beaucoup de complexité que vous ne voudrez peut-être pas traiter. Il est facile à manipuler avec un fil et une boucle.

En gros, ce que vous voulez faire, c'est avoir une boucle à la fois logique et rendu, mais pas nécessairement dans chaque itération. Voir ce pseudo-code: P>

while(true) {
   oldTime = currentTime;
   currentTime = systemTime();
   timeStep = currentTime - oldTime;

   // Only do logic x times / second
   if( currentTime > lastLogicTime + logicRefreshTime ){
      doGameLogic( currentTime - lastLogicTime );
      lastLogicTime = currentTime;
   }

   // Extrapolate all movements using timeStep
   renderGraphics( timeStep );

   wait( screenRefreshTime );
}

void doGameLogic( timeStep ) {
   // Update all objects
   for each( gameObject obj )
     obj.move( timeStep );
}


4 commentaires

Hmmm ne devriez-vous pas vérifier la logique du jeu puis rendre? Je pense que le rendu est la dernière chose que vous devriez faire depuis que vous avez besoin que toutes vos données soient valides avant de l'afficher à l'écran.


@Cristina: Oui, tu devrais probablement faire ça. Vous pouvez également choisir d'interpoler au lieu d'extrapoler si l'exactitude est plus importante que la réactivité.


La raison pour laquelle beaucoup de jeux ne le font pas bien parce que "puis comparez les lignes à voir si deux lignes intersect" n'est pas triviale pour résoudre si la géométrie devient complexe. En comparant naïvement chaque paire de lignes va tuer votre temps de trame assez rapide. Plus, même si les lignes se croisent, vous avez toujours beaucoup de travail pour déterminer si les objets devraient en réalité entrer en collision; La collision ne devrait pas arriver si l'intersection est au «début» du mouvement d'un objet et à la «fin» de l'autre.


@ Dash-Tom-Bang: Vous avez tellement raison. Un moyen de simplifier le test de collision d'objet consiste à utiliser des formes de collision plus simples que les formes réelles des objets. Les vieux jeux 2D avaient généralement des boîtes de collision invisibles. Pour les jeux 3D, vous pouvez utiliser des cylindres ou même des sphères avec de bons résultats - ce n'est que la ligne + le rayon de la sphère. Je ne dis pas que c'est trivial, bien sûr.



5
votes

Comme une autre réponse indiquée, le problème que vous voyez est appelé "tunneling" C'est la "balle à travers le papier", la balle bouge vite, le papier est mince, comment savez-vous qu'une collision est arrivée?

C'est facile si vos frontières du monde sont simples. Par exemple. Dans Tetris, les blocs ne sont autorisés que de se déplacer à gauche et à droite jusqu'à ce qu'ils touchent les côtés et il est facile de tester si la coordonnée la plus bas frappe le "sol". Ces tests sont simples, car vous pouvez effectuer un axe à la fois et les collisions contre les côtés signifie quelque chose de différent des collisions contre le fond de la fosse. Si vous avez une pièce rectangulaire, il suffit de «arrêter» l'objet en mouvement si son mouvement l'a mis à l'extérieur de la pièce en serrant ses coordonnées. C'est à dire. Si la largeur de la pièce est de -3 à +3 et que votre objet a un x de 5, changez-le simplement à 3 et vous avez terminé.

Si vous voulez gérer des mondes plus compliqués, c'est un peu plus délicieux. Vous voudrez lire sur la collision de géométrie "balayée". Fondamentalement, si vous avez un cercle, vous devez effectuer des tests de collision avec une capsule à la place, la forme qui serait faite en "balayant" le cercle de son point de départ à son point de fin. Ce sera comme un rectangle avec des demi-cercles à l'une ou l'autre extrémité. Le calcul est étonnamment simple (IMHO), mais il peut être difficile de bien comprendre et de bien comprendre ce qui se passe. Ça vaut la peine!

edit: sur le problème du fil - pas besoin de compliquer les choses. Un fil est bien. Sauter Mettre à jour des cadres peut aussi être désordonné et est assez avancé puisque vous devez réellement comprendre "l'avenir", puis faire interpolation de toutes les valeurs intéressantes jusqu'à ce point. Je ne l'appelle pas la boucle "Render", moi-même, car la boucle de rendu n'est qu'une partie du processus. xxx

edit 2: Cela semble être une discussion intéressante: http: //www.gamev. net / communauté / forums / topic.asp? topic_id = 482397


0 commentaires

2
votes

Ne vous enfoncez pas - vous causerez plus de problèmes que vous ne résoudrez pas. Vous peut strong> threads et distincts des mises à jour logiques et de rendu, mais il est difficile de bien comprendre et de grandes portions de boucles de jeu sont intrinsèquement uniformes.

Au lieu de cela, examinez la boucle de votre jeu en utilisant un delta Il est temps de mettre à l'échelle des choses afin que la mise à jour logique soit largement indépendante de la capacité de la machine à chomber à travers les cadres. p>

en termes simplifiés, si vous utilisez un delta pour mettre à l'échelle des choses, quelle que soit la durée nécessaire pour traverser un cadre, une balle bougeant d'un côté d'une pièce à une autre prendra le même temps. Pour le faire sur un PC vraiment rapide et un lent lent. p>

par exemple Si une balle déplace 10 unités en une seconde et que vous pouvez déterminer que 0,1 seconde est passée depuis la dernière mise à jour (utilisez la minuterie haute performance ou tout ce qui vous est disponible), vous expliquez simplement le mouvement de 0,1 et la balle déplace 1 unité. p>

EG P>

private const float BallSpeedInMetresPerSecond = 10;

public void Update(float deltaTimeInSeconds)
{
    float adjustedSpeed = deltaTimeInSeconds * BallSpeedInMetresPerSecond;
    // set ball's speed / move it etc. using adjusted speed
}


0 commentaires

0
votes

Si les mises à jour logiques sont généralement bon marché et que le rendu est parfois coûteux, la chose la plus facile à faire est de disposer de n mises à jour logiques par seconde. N = 60 est courant - mais vous devriez simplement choisir la plus petite valeur qui permet au jeu de bien fonctionner, choisissez une valeur et modifier le jeu jusqu'à ce qu'il fonctionne à ce taux, ou (plus probable) une combinaison des deux.

Au moment de l'exécution, gardez la trace du temps écoulé, gardez une trace de combien de temps s'est écoulé logiquement (en termes de mises à jour effectuées), et lorsqu'il y a plus de 1,0 / n secondes de discordance (parce que le rendu prend trop de temps) effectuer des mises à jour supplémentaires pour rattraper. C'est mieux que d'essayer d'effectuer une période arbitraire de la durée de mises à jour en une fois, car il est plus prévisible. (Si le lecteur n'est pas d'accord, ils sont les bienvenus pour la découvrir de la manière difficile.)

L'inconvénient de ce système est que si le rendu devient particulièrement chronométrant, et la logique doit effectuer trop de mises à jour en raison de cela, les deux peuvent obtenir un peu de synchronisation et la logique ne se rattrapera jamais. Si vous ciblez un système fixe, cela indique simplement que vous essayez de faire beaucoup, et vous devrez faire moins faire moins, ou (si cette situation est susceptible d'être rare) vider toute l'idée et faire A 1: 1 Render: Mise à jour. Si vous ciblez quelque chose de variable comme un PC Windows, vous devrez simplement clamponner le nombre de mises à jour logiques de rattrapage et espérons que cela laissera les choses se remettre en ligne.

(Si la logique est plus chère, cette approche n'est pas appropriée; Je n'ai jamais travaillé sur un jeu où c'était un problème, cependant.)


0 commentaires

1
votes

Je pensais que je devrais avoir un Fil séparé pour la logique du jeu et dans la boucle de rendu, je devrais juste "Prenez un instantané" du jeu actuel logique et afficher cela, non?

Il n'y a aucun moyen qui est simple, sûr et rapide à prendre un instantané d'un gros morceau d'état de jeu. Vous pouvez double tamponner, ce qui est probablement la meilleure meilleure chose. Mais cela ne résout pas le problème de toute façon, donc non, vous ne le feriez pas, du moins pas à cette fin.

disons que j'ai une balle avec x = 0, et un mur en x = 10 et dans une machine lente, La première boucle place la balle en x = 7 et dans une seconde boucle, il place la balle en x = 14. Ça tomberait juste le Jeu!

Le filetage des deux ne résoudrait pas cela, sauf si vous ne pouvez garantir que chaque ordinateur que vous avez utilisé serait toujours assez rapide pour vérifier x = 1, x = 2, x = 3 ... x = 10. Vous ne pouvez pas faire cette garantie. Et même si vous le pouviez, il est rare d'utiliser des nombres entiers pour des postes. Pouvez-vous vérifier itérativement x = 0.0000001, x = 0,0000002, x = 0.0000003 ... x = 0.9999999, x = 10,00000? Nope.

Comment les gars, les développeurs de jeux expérimentés travaillent autour de cela?

Nous avons toujours encore une boucle. Entrée, mise à jour, rendu, répétition. Les problèmes de collision Comme vous le mentionnez sont résolus en utilisant une méthode de détection de collision qui calcule la zone que l'objet passerait, par exemple. Résoudre pour x = [0 à 17]. Sur une machine vraiment lente, il pourrait être x = [0-50] et sur une machine rapide, il pourrait être x = [0-5] suivi de x = [5-10], mais chacun fonctionnera comme prévu.


0 commentaires

3
votes

Il est possible d'avoir un thread de mise à jour distinct et un thread de dessin , mais ce n'est pas facile! Habituellement, vous devrez utiliser beaucoup de mutex vérifier pour empêcher l'accès multithreadé aux mêmes variables, ce qui n'est pas vraiment viable (plus vous ne voulez pas gérer avec des états à moitié mis à jour). Pour une mise en œuvre correcte, vous devez en effet avoir une forme d'instantané du dernier état de rendu. Si cela ne vous dérange pas de la difficulté impliquée, il y a une bonne implémentation que Van soit trouvée ici:

http://blog.slapware.eu/game-Engine / Programmation / Multhreaded-Renderloop-Part1 /

http://blog.slapware.eu/game-Engine / Programmation / Multhreaded-Renderloop-Part2 /

Ne laissez pas les Naysayers vous décourager. C'est possible, c'est viable et efficace. Le seul inconvénient est qu'il est très difficile à mettre en œuvre et donc probablement pas de votre temps (sauf si vous avez un jeu très lourd de la CPU).


0 commentaires