Je me demandais s'il y avait un danger possible lorsque ma boucle de jeu tourne aussi vite que le système le permet?
J'ai actuellement une boucle qui, en mesurant le temps passé en nanosecondes, exécute la logique du jeu et rend la logique à des vitesses prédéfinies sans problème. En fait, toute logique que je fais dans la boucle est cadencée à un certain nombre d'appels chaque seconde.
La boucle elle-même fonctionne à peu près aussi vite qu'elle le souhaite, ce qui représente environ 11,7 millions de boucles par seconde sur ma machine.
Boucle (pseudocode simple):
while(!isGameOver){
if(canPollInputs){
pollInputs()
}
while(canStepLogic){
stepLogic()
}
if(canRender){
render()
}
}
Ma question est essentiellement si cette simple boucle, si elle ne fonctionne pas à une vitesse contrôlée, peut nuire à un système?
Edit: cela signifie que ma logique fonctionne 30 fois par seconde (30 tps), mon moteur de rendu fonctionne à 60 ips, j'interroge les entrées 100 fois par seconde et il y a aussi une certaine logique pour faire face à la logique ou le rendu prend plus de temps que prévu . Mais la boucle elle-même n'est pas étranglée.
Edit: Utiliser Thread.sleep()
par exemple pour réduire la boucle principale à 250 boucles par seconde entraîne une réduction mais les boucles fonctionnent à environ 570 boucles par seconde au lieu des 250 souhaitées (ajoutera du code lorsque je serai sur ma machine de bureau ..)
Edit: C'est parti, une gameloop java fonctionnelle pour clarifier les choses. N'hésitez pas non plus à l'utiliser mais ne le revendiquez pas à vous;)
private void gameLoop() {
// Time that must elapse before a new run
double timePerPoll = 1000000000l / targetPPS;
double timePerTick = 1000000000l / targetTPS;
double timePerFrame = 1000000000l / targetFPS;
int maxFrameSkip = (int) ( (1000000000l / MINIMUM_FPS) / timePerTick);
int achievedPPS = 0;
int achievedFPS = 0;
int achievedTPS = 0;
long timer = TimeUtils.getMillis();
int loops = 0;
int achievedLoops = 0;
long currTime = 0l;
long loopTime = 0l;
long accumulatorPPS = 0l;
long accumulatorTPS = 0l;
long accumulatorFPS = 0l;
long lastTime = TimeUtils.getNano();
while(!isRequestedToStop) {
currTime = TimeUtils.getNano();
loopTime = currTime - lastTime;
lastTime = currTime;
loops = 0;
accumulatorPPS += loopTime;
accumulatorTPS += loopTime;
accumulatorFPS += loopTime;
if(accumulatorPPS >= timePerPoll) {
pollInputs();
playerLogic();
achievedPPS++;
accumulatorPPS -= timePerPoll;
}
while(accumulatorTPS >= timePerTick && loops < maxFrameSkip) {
tick();
achievedTPS++;
accumulatorTPS -= timePerTick;
loops++;
}
// Max 1 render per loop so player movement stays fluent
if(accumulatorFPS >= timePerFrame) {
render();
achievedFPS++;
accumulatorFPS -= timePerFrame;
}
if(TimeUtils.getDeltaMillis(timer) > 1000) {
timer += 1000;
logger.debug(achievedTPS + " TPS, " + achievedFPS + " FPS, "
+ achievedPPS + " Polls, " + achievedLoops + " Loops");
achievedTPS = 0;
achievedFPS = 0;
achievedLoops = 0;
}
achievedLoops++;
}
}
Comme vous pouvez le voir, il n'y a presque pas de code exécuté sur chaque boucle mais toujours une certaine sélection en fonction du temps réel écoulé. La question se réfère à cette «boucle des travailleurs» et comment elle influence le système.
la source
Réponses:
Cela entraînera un cœur de processeur à toujours fonctionner à 100%. Cela ne cause généralement aucun dommage au système. Les processeurs sont conçus pour fonctionner à 100% pendant des heures. Mais sur un appareil mobile, cela déchargera rapidement la batterie et chauffera l'appareil, ce qui vous coûtera probablement environ une étoile dans les notes de votre magasin. Sur un ordinateur de bureau, cela pose moins de problème, mais il consommera davantage d'électricité des utilisateurs, provoquera une rotation plus rapide du ventilateur du processeur, ce qui pourrait provoquer du bruit et gaspiller des cycles de processeur qui pourraient autrement être utilisés par d'autres processus. Bien que ce ne soient pas des défauts critiques, ils sont toujours de mauvais style, vous devez donc les éviter lorsque cela est possible.
Vous n'avez rien dit sur le fonctionnement interne de votre boucle de jeu, mais lorsque vous utilisez l'approche delta-time (chaque calcul que vous faites prend le temps depuis le dernier appel), vous avez affaire à un très petit delta- valeurs de temps. Cela signifie que vous pouvez rencontrer des problèmes d'imprécision en virgule flottante qui peuvent provoquer toutes sortes de comportements étranges. De plus, la résolution de la minuterie système est souvent limitée, donc lorsque votre boucle logique est trop rapide, vous pouvez obtenir une valeur delta-t de zéro, ce qui pourrait alors provoquer une division par zéro entraînant un crash.
Pour atténuer ce problème, vous devez limiter votre fréquence d'images (graphique et logique) au maximum de ce que l'œil humain peut percevoir. La quantité contestée dépend du type d'animation et du type d'affichage affiché, mais les estimations varient de 40 FPS à 120 FPS. Cela signifie que vous devez définir un temps minimum d'exécution de chaque boucle entre 20 ms et 8 ms. Si une itération de boucle se termine plus rapidement, laissez le thread cpu
sleep
pour la durée restante.la source
Vous perdez des cycles CPU. Cela signifie moins de temps de batterie sur les ordinateurs portables, tablettes et téléphones, des factures d'électricité plus élevées, plus de chaleur générée par la machine, des ventilateurs plus bruyants. De plus, vous pouvez manger des cycles provenant d'autres processus système importants (par exemple, le serveur de fenêtres peut devenir saccadé), ce qui pourrait alors affecter le gameplay. Certains programmateurs système sur les systèmes multitâches préventifs d'aujourd'hui pénalisent également les applications qui utilisent trop de cycles, vous pouvez donc être rapide en premier, puis voir soudainement d'étranges secousses lorsque vous êtes étranglé par le système.
De nombreux joueurs inconditionnels construisent également à partir de zéro des PC personnalisés qui sont à la limite des spécifications de leurs fans, auquel cas une journée chaude et la chaleur générée par votre jeu peuvent déclencher les sécurités dans la machine (au mieux) ou même faire surchauffer les pièces et mourir (au pire). Donc, si c'est votre public cible, vous voudrez peut-être vous assurer de toujours laisser un peu d'espace "en haut".
Enfin, il y a des problèmes de gameplay où vous pourriez être en train d'avantager les joueurs avec des machines plus rapides que ceux avec des machines plus lentes. La limitation de la boucle de jeu à une certaine fréquence et l'utilisation de cycles supplémentaires uniquement pour les aspects non liés au gameplay (comme le rendu de graphismes plus fidèles, les effets sonores surround ou autre) rendront votre jeu plus équitable.
la source
Vous ne devriez pas avoir de mouvement / gameplay nerveux
Il existe deux façons d'implémenter la logique du jeu - liée à un temps réel, ou liée au nombre de "tours" / étapes de traitement. Si quelque chose dans votre jeu se déplace vers la gauche, est-ce que le mouvement sera différent si votre stepLogic () a été appelé 100 au lieu de 50 fois?
Si votre code traite explicitement le temps écoulé partout et le fait correctement, alors cela pourrait être correct; mais s'il y a quelque chose dans votre code qui dépend du nombre de «pas», vous obtiendrez des effets secondaires indésirables.
Tout d'abord, la vitesse des choses qui devraient bouger constamment variera de manière imprévisible (selon l'utilisation du processeur), ce qui rend les contrôles très ennuyeux - vous ne pouvez pas effectuer un coup de poing précis ou un saut si soudainement le jeu accélère ou ralentit. Même pour les jeux sans «secousses», cela semble ennuyeux et nerveux si les choses ne se déroulent pas correctement.
Deuxièmement, vous pourriez avoir des problèmes avec les capacités des personnages en fonction de la vitesse de l'ordinateur - un exemple classique est l'ancien problème Quake où la plage de saut maximale dépendait involontairement de vos fps.
Ces problèmes peuvent apparaître même si vous essayez d'avoir un code indépendant des fps, l'accumulation d'erreurs d'arrondi peut souvent provoquer de tels bogues.
la source
Le seul danger potentiel est votre consommation d'énergie, alors ne le faites pas sur les appareils mobiles. À l'inverse, bon nombre de systèmes intégrés passent leur vie entière dans une boucle en attendant que les choses se produisent.
Auparavant, il était tout à fait normal de simplement rendre les images de jeu aussi rapidement que possible, parfois même sans minuterie pour compenser le gameplay pour différentes vitesses de processeur. Le jeu de course de Bullfrog, Hi-Octane, a été particulièrement victime de cela, et je soupçonne que c'est à cela que fait référence l'affiche mentionnant Civ2.
Je vous conseille au moins d'interroger les entrées à chaque passage si vous êtes sur un système Windows ou similaire, pour assurer une réponse d'entrée rapide.
la source
swap
/present
/flip
pour attendre le signal vsync, pour réguler la boucle de jeu.