Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Discussions


Index du Forum » Discussions » Utilisation de timers et moteurs de jeux
Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Utilisation de timers et moteurs de jeux

Posté le 19/04/2018 21:14

Ce topic est la suite d'une discussion sur la shout. J'ai en gros deux questions, tout le monde étant invité à répondre :

- Louloux, tu utilises souvent des timers quand tu codes des jeux ? (toutes plateformes confondues)
- Peut-on se contenter de 2 timers pour écrire un moteur de jeu ?


Ninestars Hors ligne Membre Points: 2462 Défis: 24 Message

Citer : Posté le 20/04/2018 15:55 | #


Je réponds à tous ça ce soir
Louloux Hors ligne Ancien administrateur Points: 7035 Défis: 61 Message

Citer : Posté le 20/04/2018 17:37 | #


Lephenixnoir a écrit :
Maintenant les histoires de Δtime sont intéressantes parce qu'il n'y a pas de risque que le moteur graphique affiches des informations obsolètes (il tourne toujours juste après le moteur physique). Le problème si le moteur physique tourne à échéances fixes, c'est que si le moteur graphique met 1.1 fois la durée allouée il va accumuler du retard et afficher les infos de plus en plus tard. Je pense que le « saut » qui en résulte (au bout de 10 tours) est vraiment à éviter, et je vais sans doute revoir mon modèle.

Ce n'est pas l'objectif du delta-time. Il n'y a pas de question d'obsolescence, c'est juste qu'on base la physique sur le temps au lieu d'un système discret qui assume des intervalles réguliers.

Pour citer mon propre code :

this.yspeed = GameSettings.GRAVITY + (this.yspeed - GameSettings.GRAVITY) * (Math.exp(-delta/(1000*GameSettings.INERTIA)));
[...]
this.ypos += this.yspeed * delta/1000;



Lephenixnoir a écrit :
Si le rendu graphique lagge, actuellement on n'a pas de garanties sur la vitesse de la physique (voir au-dessus).

Si le rendu lag trop, l'utilité d'avoir une physique qui fonctionne à vitesse normale est discutable.
Mais évidemment il y a moyen de faire bien mieux, le mieux est de crash-test différentes méthodes en gérant manuellement la longueur des fonctions update et draw avec des sleep.


Lephenixnoir a écrit :
Surtout en cas de lag soudain et très passager (1-2s)

C'est le genre de trucs qu'on peut adapter avec un moving average, si on veut ne pas réagir à un lag passager.
Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 20/04/2018 17:50 | #


Ce n'est pas l'objectif du delta-time. Il n'y a pas de question d'obsolescence, c'est juste qu'on base la physique sur le temps au lieu d'un système discret qui assume des intervalles réguliers.

C'est exact, je mettais simplement en valeur les avantages que j'observais du Δtime sur mon système proposé. Ce n'étais, je l'admets, pas très clair...

Disons que si le graphique lagge, le joueur peut potentiellement tenir 1 ou 2 secondes en « imaginant ce qui est en train de se passer » le temps que le programme reprenne son souffle, parce que dans le feu de l'action, le cerveau continue de calculer. C'est pas idéal mais ça peut se faire.

Le problème d'autoriser la physique à ralentir c'est que le joueur n'a aucun moyen d'estimer de combien ça ralentit. Impossible de savoir si la touche sur laquelle j'ai appuyé a été prise en compte, etc. Il peut tout aussi bien lâcher les commandes qu'il ne sera pas plus avancé. C'est très différent de la situation précédente, où l'on constate que le graphisme lagge mais on sait (par expérience) que le jeu continue de tourner parce qu'il a été codé pour. On n'a pas tout perdu.

J'ai déjà raté des timings un peu délicats à cause de lags passagers, c'est rageant, surtout quand tu te dis que tu connais la combinaison par cœur et que si la physique avait avancé normalement, tu aurais réussi ta manip' - et qu'elle serait juste apparue à l'écran une demi-seconde plus tard.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Ninestars Hors ligne Membre Points: 2462 Défis: 24 Message

Citer : Posté le 20/04/2018 19:46 | #


Le reprend ce que disais Louloux, se le fait qu’il ne faut pas oublier qu’on est sur une calculatrice. C’est notre première hypothèse et sans la plus importante.

On a 3 choix :
vitesse rendu < vitesse physique
Vitesse rendu > vitesse physique
Vitesse rendu = vitesse physique
(Je devrais dire fréquence d’ailleurs )
Procédons par élimination

La vitesse du rendu < vitesse physique signifie qu’on "sous-affiche", ou plutôt qu’on sur-calcul. Ça peut être légitime pour des simulations qui cherchent la précision avec des objets rapides. Par contre exemple Forza 2, un jeux de voiture sur Xbox360 tourne à 360fps avec un rendu à 30. C’est justifiable pour la gestion des collisions et la simulation de conduite. Sur calculette ? Est-ce qu’on a fait ou fera des jeux purement de simulation avec des équations nécessitant un pas temporel fin ?

Deuxième cas, vitesse rendu > vitesse physique. Dans ce cas on "sur-affiche", on affiche plusieurs fois la même frame puisque la physique n’a pas changé. A moins, que le programmeur ait paramétré ces animations pour qu’elles puissent être affichées (et cohérentes) entre deux drames physiques. Mais qui ferait ça ? C’est beaucoup de travail pour des gens qui font déjà tout le reste du programme seul. Est-ce pertinent en plus avec un écran avec rémanence ?

La troisième solution est l’égalité.

Ça ne veut pas dire qu’il faille abandonner les autres possibilités, mais évitons l’usine à gaz se personne n’utIlisera
Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 20/04/2018 20:45 | #


Dans l'absolu je suis d'accord avec ton analyse, dans la pratique il y a deux hypothèse en moins : d'une part la vitesse de rendu n'est pas unique, d'autre part tu n'obtiendras jamais un réglage exact de ton égalité.

Prenons un exemple pour le premier point : TLT n'aura pas du tout la même quantité de rendu à faire en ville où il y a trois PNJs qui se battent en duel et pendant un combat contre 30 ennemis quand 12 effets graphiques et 150 particules sont en vol à l'écran (j'exagère volontairement le trait).

Je pense que le Δtime a les propriétés intéressantes suivantes :
- Il s'adapte aux variations liées au fait que le jeu ne demande pas les mêmes ressources à tout instant ;
- Il n'y a pas besoin de faire des mesures et des ajustements pour obtenir le fameux vitesse_rendu = vitesse_physique.

Soit dit en passant, et pour complétude car l'argument n'est pas entièrement pertinent en pratique, le réglage qui ajuste les deux durées peut ne pas convenir :
- Si la machine est overclockée et que le jeu ne fixe pas son niveau d'overclock
- Si le "dual-threading" de la Prizm est utilisé (peu probable parce que ça plombe trop les perfs, même CubeField explose)

Finalement, pour revenir sur mon deuxième point, à défaut d'avoir l'égalité tu risques d'avoir temps_rendu = 1.01 * temps_physique et dès la deuxième période tu affiches tout avec un frame de retard ; au bout de 100 périodes tu sautes un frame. Comme quoi pas si facile.

Je suis d'accord toutefois que la simplicité est à privilégier, en toutes circonstances. Tout à l'heure j'ai lu le document linké par Louloux en page précédente et le Δtime n'est pas très compliqué à utiliser donc pour l'instant je dois m'avouer assez intéressé par cette méthode.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Ninestars Hors ligne Membre Points: 2462 Défis: 24 Message

Citer : Posté le 20/04/2018 23:39 | #


C’est pour cela que je disais qu’il faut mettre le moteur graphique et physique sur le même timer, c’est le seul moyen de garantir le rapport de 1
Après "il faut", c’est plutôt moi qui procéderais comme ça pour un jeu sur calculatrice.
Rien n’empeche de laisser les deux. Je défends juste mon point de vue pour le débat, et surtout pour répondre à ta question d’origine

Enfin pour reprendre ton exemple de TLT (qu’est ce que c’est ?) je trouve qu’il ne justifie rien.
En ville, tu affiches tes 3 png et le prog attend. En combat il mettra plus de temps à afficher et moins à attendre.
Dans tout les cas il ne faut pas que le temps de travail pour l’affichage d’une scène n’excède le temps qui lui ait alloué (1/framerate). Sinon c’est que le prog est mal fait ou le jeu trop gourmand. Point. Le Delta T n’y changera rien
Le Delta T sert pour ce qui est numérique, qu’est ce que tu en fait du Dt si à la frame n tu as une image et à la frame n+1 une autre image ? Il ne va pas te servir le Dt.
Pour une équation comme celle de cinematique c’est parfait, seulement tout n’est pas interpolable. Louloux le dit bien, le Dt sert pour un calcul de physique (au sens physique cinématique)
Louloux Hors ligne Ancien administrateur Points: 7035 Défis: 61 Message

Citer : Posté le 21/04/2018 01:36 | #


Ninestars a écrit :
Le Delta T n’y changera rien
Le Delta T sert pour ce qui est numérique, qu’est ce que tu en fait du Dt si à la frame n tu as une image et à la frame n+1 une autre image ? Il ne va pas te servir le Dt.
Pour une équation comme celle de cinematique c’est parfait, seulement tout n’est pas interpolable. Louloux le dit bien, le Dt sert pour un calcul de physique (au sens physique cinématique)

Effectivement le delta-time est un paramètre physique.
Après des utilisations, notamment en animation, tiennent de l'interpolation, mais il n'est pas judicieux d'interpoler dans draw des paramètres qui sont gérés par la logique (parce que déjà ça veut dire qu'on fait trop de draw par rapport aux updates, ce qui n'est pas très judicieux).

Lephenixnoir a écrit :
Finalement, pour revenir sur mon deuxième point, à défaut d'avoir l'égalité tu risques d'avoir temps_rendu = 1.01 * temps_physique et dès la deuxième période tu affiches tout avec un frame de retard ; au bout de 100 périodes tu sautes un frame. Comme quoi pas si facile.

Je ne vois pas en quoi c'est un problème, j'ai dû manquer un truc.
La méthode draw affiche l'état du jeu au moment où elle est appelée, donc à moins de faire plusieurs appels à update pendant un appel à draw, elle a toujours moins d'une frame de retard. Et si les perfs pêchent pas trop, c'est rien.
Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 21/04/2018 08:17 | #


Enfin pour reprendre ton exemple de TLT (qu’est ce que c’est ?) je trouve qu’il ne justifie rien.
En ville, tu affiches tes 3 png et le prog attend. En combat il mettra plus de temps à afficher et moins à attendre.

Désolé de l'imprécision ; TLT c'est un long projet de RPG que je partage avec Darks. Et tu contournes encore le cas où la calculatrice n'est pas assez puissante, regarde.

Supposons que le combat que j'ai décrit est hyper épique et la calto arrive pas à tenir plus de 4 FPS (horreur !). Si mon moteur est réglé sur la fréquence fixe de 4 FPS alors je n'aurai pas plus que ça en ville... j'en ai pourtant les moyens ! Et puis si le moteur est réglé sur plus (eg. 15 FPS), alors tout ira bien en ville, mais en combat je n'arriverai jamais à dessiner le moindre frame dans les temps. Plusieurs modes de travail sont envisageables :

1. 15 fois par seconde, on arrête tout et on commence le frame suivant. Idée horrible car en combat on n'aura plus rien.
2. On « enfile des signaux » 15 fois par seconde et le moteur graphique défile un nouveau frame quand il est libre ; dans ce cas le graphique va prendre un retard non borné (!) sur la physique.
3. On fait tourner le moteur graphique à fond et il affiche à chaque nouveau frame les données les plus récentes.

La seule situation acceptable à mon avis est la 3, mais...
- Si ça lagge vraiment (eg. 2 FPS contre 15 normalement), ça donne les mêmes résultats que le Δtime.
- Si ça lagge juste un chouille (eg. 15 / 1.01 FPS au lieu de 15 FPS), tous les 100 frames t'as des sauts, j'en ai déjà parlé.

Dans tout les cas il ne faut pas que le temps de travail pour l’affichage d’une scène n’excède le temps qui lui ait alloué (1/framerate). Sinon c’est que le prog est mal fait ou le jeu trop gourmand.

Bien sûr, le jeu doit être pensé pour. Mais j'ai pas quoté le « Point. » parce que je suis certain que je finira pas avoir un lag par-ci par-là par erreur et je ne veux pas que ça explose à ce moment-là.

Pour une équation comme celle de cinematique c’est parfait, seulement tout n’est pas interpolable. Louloux le dit bien, le Dt sert pour un calcul de physique (au sens physique cinématique)

Le Δtime me servirait à faire les calculs de physique à intervalles non fixes. Un chemin d'exécution typique ce serait update(), draw(), update(), draw(), etc en séquentiel. Le Δtime que j'enverrais à mon moteur physique serait grosso modo le temps utilisé par le moteur graphique pour rendre le dernier frame.

Je ne peux pas accepter le fonctionnement « framerate fixe, period » parce que justement je souhaite faire un jeu où on peut pousser les perfs de la machine de façon acceptable. Et je n'ai pas encore mentionné que je compte overclocker (dans une certaine marge) dynamiquement si les perfs baissent trop.

Je ne vois pas en quoi c'est un problème, j'ai dû manquer un truc.

Faudrait que je fasse un diagramme, mais en gros tu vas voir apparaître à intervalles parfaitement réguliers sur l'écran les frames 0, 1, ... 98, 99, 101 et paf, t'as un saut. Je suis pas sûr que ce soit agréable à voir.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Ninestars Hors ligne Membre Points: 2462 Défis: 24 Message

Citer : Posté le 21/04/2018 11:07 | #


OK, je vois très bien ce que tu veux dire. Tu veux une fréquence du physique constante, mais le graphique qui s'adapte, et si les perf de la calculatrice ne permettent pas d'avoir Tphysique + Trendu ≤ 1/framerate tu retires des rendu pour avoir du calcul physique assuré.

Je vois 2 problèmes :
- C'est lié au programmeur qui fait mal son job, il a eu les yeux plus gros que le ventre sur les animations et le Trendu >Tphys - 1/framerate. Dans ce cas faut revoir ses exigences à la baisse.
Après toi tu parles des cas où tu n'a pas voulu que ça soit gourmand (bug, accès mémoire, ... je sais pas).

- Le problème vient du fait que tu puisses pas parallèliser le rendu et la physique. Et bien justement fait un graphique et tu verras le problème. Tiens je vais le faire comme ça on sera bien d'accord

Légende :
première ligne, c'est ce que tu veux, une fréquence de physique constante
la deuxième et troisième c'est un ordi
le quatrième et cinquième c'est une calculette.
En vert c'est un rendu léger, en rouge chargé.
Tu vois le problème apparaitre ?
Sur du monocoeur tu dois forcement respecter l'équation Tphysique + Trendu ≤ 1/framerate, si Trendu augmente, tu vas manger sur la physique.
Sur ordi peut importe parce que c'est le CPU et le GPU qui gèrent ça de façon quasi indépendante.


Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 21/04/2018 19:10 | # | Fichier joint


Ninestars a écrit :
Tu veux une fréquence du physique constante, mais le graphique qui s'adapte, et si les perf de la calculatrice ne permettent pas d'avoir Tphysique + Trendu ≤ 1/framerate tu retires des rendu pour avoir du calcul physique assuré.

Alors, ça m'attriste un peu de devoir te dire ça après que tu aies pris le temps de faire des diagrammes, mais c'est pas (du tout) ce que je veux faire. En fait, ça fait assez longtemps que je suis en train de critiquer ce modèle. Dès que je parle de 1.01 et de saut, c'est pour dire que le modèle dont tu viens de démontrer la faiblesse ne marche pas.

En fait, le problème que tu soulèves avec les deux dernières lignes de ton dessin est un système que j'ai rejeté juste dans mon message au-dessus :

[Solution 1]. 15 fois par seconde, on arrête tout et on commence le frame suivant. Idée horrible car en combat on n'aura plus rien.

Non, ma suggestion consiste à dire qu'on ne peut pas espérer contrôler les délais :
- On ne peut pas dire qu'on a temps_rendu = temps_graphique.
- On ne peut pas dire que temps_graphique < une_borne pour configurer la durée du timer.

De plus, on est bien d'accord que sur une calculatrice il est inutile de faire plusieurs rendus entre deux updates, donc chaque rendu est suivi d'une update. Je me place dans le cas simple où on ne cherche pas, comme l'a suggéré Louloux, à faire plusieurs updates entre deux frames.

Je te laisse voir que dans ce contexte on a une alternance parfaite rendu - update - rendu - update. Ce que je propose depuis que je parle de Δtime c'est la méthode suivante :


Le Δtime est utilisé car la durée qui s'écoule entre deux updates peut varier - puisque c'est la durée d'un rendu. Ainsi, en ville j'ai un framerate super élevé et je peux me payer le luxe de dormir un peu si j'ai assez de puissance ; en combat, mon framerate diminue mais le jeu tourne toujours à la même vitesse.

Cette méthode ne nécessite pas non plus de timer à proprement parler, juste une horloge pour mesurer le Δtime.

Il me semble bien que ton message précédent parle du point [1] de mon précédente message, et qui n'était donc probablement pas clair. Les histoires de sauts et de 1.01 c'est le point [3]. Je t'invite à le relire et à m'engueuler si c'est incompréhensible parce que j'ai la forte impression qu'on tourne en rond et que les idées ne passent pas.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Dark storm Hors ligne Labélisateur Points: 11641 Défis: 176 Message

Citer : Posté le 22/04/2018 00:44 | #


J'ai pas de solution à proposer, mais déjà je propose qu'on trie ce qui est le plus important pour ensuite trouver une solutiok technique. Donc en bref :
– Réactivité du jeu (ie, j'appuie sur une touche, quand le moteur va la prendre en compte ?)
– Nombre de FPS graphiques
– Nombre de FPS physiques
– Résilience de la physique (ie sa capacité à garder ses FPS même si les graphiques sont à la ramasse)
– Résilience des graphiques (l'inverse)
– Sûrement d'autres trucs à définir

Le problème du Delta-Time, c'est que la réactivité prend un sacré coup dans la tronche. Si on fout l'affichage dans la boucle principale, c'est la résilience de ce dernier qui en prend un coup. Si on fait l'inverse, c'est la résilience de la physique qui est sur la sellette.

Je doute qu'il y ai une solution toute faite pour tous les jeux, mais déjà définir des priorités en phase avec le support de développement peur aider à trouver un modèle qui conviendra. Je reste persuadé que l'on n'aura dans tous les cas que des compromis.
Finir est souvent bien plus difficile que commencer. — Jack Beauregard
Louloux Hors ligne Ancien administrateur Points: 7035 Défis: 61 Message

Citer : Posté le 22/04/2018 01:14 | #


Lephenixnoir a écrit :

Je te laisse voir que dans ce contexte on a une alternance parfaite rendu - update - rendu - update. Ce que je propose depuis que je parle de Δtime c'est la méthode suivante :


Le Δtime est utilisé car la durée qui s'écoule entre deux updates peut varier - puisque c'est la durée d'un rendu. Ainsi, en ville j'ai un framerate super élevé et je peux me payer le luxe de dormir un peu si j'ai assez de puissance ; en combat, mon framerate diminue mais le jeu tourne toujours à la même vitesse.

Ça me paraît pertinent au regard de ce qu'on a dit et des limitations de la calculatrice.

Du coup il faut partir sur la solution qu'on a tous les deux évoquées : un timer à plus haute fréquence pour déclencher soit un update soit un draw en alternance, et si une fonction est en exécution, bah idle.
Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 22/04/2018 07:52 | #


Le problème du Delta-Time, c'est que la réactivité prend un sacré coup dans la tronche. Si on fout l'affichage dans la boucle principale, c'est la résilience de ce dernier qui en prend un coup. Si on fait l'inverse, c'est la résilience de la physique qui est sur la sellette.

Tel que je l'ai proposé, les deux sont dans la boucle principale. Après on peut gérer l'input de façon asynchrone pour tenter de gagner en « fidélité » entre ce que le joueur demande et ce que le moteur entend. Par contre les updates n'iront pas plus vite, donc il faut faire attention.

Je dis ça parce que j'aimerais essayer des patterns un peu compliqués au clavier avant d'implémenter TLT et je pense qu'il faudra que ce soit un peu asynchrone sur les bords.

Du coup il faut partir sur la solution qu'on a tous les deux évoquées : un timer à plus haute fréquence pour déclencher soit un update soit un draw en alternance, et si une fonction est en exécution, bah idle.

Pourquoi un timer pour implémenter l'alternance parfaite ?

while(1)
{
  int delta = get_time_since_last_frame();
  update(delta);
  draw();
}

Évidemment ça ne fait pas l'input, mais sur le principe ça devrait fonctionner non ?
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Ninestars Hors ligne Membre Points: 2462 Défis: 24 Message

Citer : Posté le 22/04/2018 14:07 | #


Ok !!! C’est bien plus clair avec des schémas pour nous expliquer
Ok je vois ce que tu veux, en effet c’est pas idiot ce que tu veux faire. En résumé tu indiques à la fonction update si elle est en avance ou en retard.
Ok, en soit c’est une très bonne idée. Après je ressors le pont noir que j’en vois à ça. Ça fait beaucoup de travail supplémentaire pour le programmeur. Que fais-tu si tu envoies update(0.99) et qu’a la frame théorique, c’est a dire à update(1), tu dois afficher une nouvelle image ?
Tu es plus proche de 1 que 0 donc tu affiches l’image ? Oui mais t’es pas arrivé à 1 donc l’image ne devrait pas être encore affichée... ça pose des questions.
Pareil pour déplacer to personnage sur quadrillage, c’est à dire avec des coordonnées entières. Tu places le joueur sur la case suivante ? Ou bien il reste sur sa case (parce qu’on est à 0.99 et pas 1) ?
Mêmes question avec une valeur supérieure à 1

Tu vois les problèmes que je soulève ?

Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 22/04/2018 14:32 | #


Je pense que je vois le problème, mais je ne cerne pas bien tous les enjeux. J'ai l'impression que le souci ne se pose que si le système de temps/espace/etc du jeu est intrinsèquement discret, et que si la physique est « continue » le souci ne se présente pas.

Ça fait beaucoup de travail supplémentaire pour le programmeur. Que fais-tu si tu envoies update(0.99) et qu’a la frame théorique, c’est a dire à update(1), tu dois afficher une nouvelle image ?

Peux-tu préciser « frame théorique » ? Dans mon esprit il n'y a pas d'instants prédéfinis où la calculatrice devrait afficher une image ; elle le fait quand elle est prête. La différence de comportement si j'envoie update(0.99) et pas update(1), c'est que la physique avancera d'un chouille moins (mon perso parcourra 1.98m et non 2m). Ensuite draw() sera appelée et le résultat obtenu sera à quelques pixels près identique dans les deux cas.

Tu es plus proche de 1 que 0 donc tu affiches l’image ? Oui mais t’es pas arrivé à 1 donc l’image ne devrait pas être encore affichée... ça pose des questions.

Le principe de la combinaison « Δtime + physique continue » c'est qu'on peut calculer la position à tout instant en tenant compte du temps écoulé. Mais je vois le problème que tu poses grâce à ta remarque :

Pareil pour déplacer to personnage sur quadrillage, c’est à dire avec des coordonnées entières. Tu places le joueur sur la case suivante ? Ou bien il reste sur sa case (parce qu’on est à 0.99 et pas 1) ?

Effectivement quand l'espace n'est pas continu c'est plus subtil. Pour moi le symptôme du problème va se voir quand tu vas essayer d'implémenter update() pour finalement réaliser que tu ne peux pas paramétrer ton mouvement (qui est instantané, à intervalles fixes) par le temps écoulé (il te faudrait le temps absolu).

À bien y réfléchir, le problème se pose dans une plus large mesure. Supposons que le canon envoie un boulet toutes les secondes, et update() a été exécutée à t = 0.96s puis t = 1.13s. Comment connaître la position du boulet qui vient d'être envoyé ?

Pour ce cas précis, j'ai une solution. Un timer peut interrompre le programme à t = 1s et créer un boulet avec une vitesse initiale appropriée. update() pourra alors voir que, bien que le rendu ait nécessité 0.17s de calcul, le boulet n'est apparu que depuis 0.13s, et calculer la trajectoire et la position.

Une autre idée, mais plus coûteuse en temps, c'est qu'update() simule l'avancée du temps par intervalles de, disons, 0.01s. Cela signifie qu'il va passer à t = 1.00s à un moment et créer le boulet. Cette solution peut paraître peu élégante, mais je la suggère parce qu'elle résout un autre problème : supposons que deux (grosses) balles de pistolet se rentrent dedans. Comment détecter la collision alors qu'au frame n elles ne se sont pas encore croisées et qu'un calcul naïf au frame n + 1 renvoie des positions après le point de croisement (ie. la collision est très rapide donc a une grande probabilité de se produire entre deux frames) ?

Si j'applique la solution du timer à ton exemple de mouvement sur une grille carrée, le personnage va avancer 1 fois par seconde, comme voulu. Mais, si les frames sont rendus de façon très irrégulière (et en supposant que le personnage va vite), certaines positions seront affichées plusieurs fois et certaines seront sautées.

Cependant l'affichage sera toujours fidèle au modèle idéal. Car, mon critère pour décider si le personnage a avancé c'est le temps absolu, et non pas le Δtime. Sinon, avec un Δtime constant de 0.49 le personnage ne bougerait jamais car à aucune update() le moteur penserait que suffisamment de temps s'est écoulé pour déplacer le personnage.

Pour résumer un peu tout ça, si j'applique mon modèle (plus le timer) à ton système discret : les frames pourront être irréguliers mais ils afficheront toujours l'état idéal du jeu ; la physique tournerait toujours à la bonne vitesse.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)
Louloux Hors ligne Ancien administrateur Points: 7035 Défis: 61 Message

Citer : Posté le 23/04/2018 13:39 | #


Ninestars a écrit :

Pareil pour déplacer to personnage sur quadrillage, c’est à dire avec des coordonnées entières. Tu places le joueur sur la case suivante ? Ou bien il reste sur sa case (parce qu’on est à 0.99 et pas 1) ?
Mêmes question avec une valeur supérieure à 1

Le déplacement discret c'est caca. Si tu fonctionnes avec une grille, tu peux avoir un coefficient d'avancement pour les phases de transition, ça fait un affichage plus joli et des collisions plus intelligentes avec les objets en mouvement.

Lephenixnoir a écrit :
Pourquoi un timer pour implémenter l'alternance parfaite ?

Si tu veux supprimer complètement l'utilisation de timers de la game loop ok, mais trouve une solution propre pour fixer le framerate en cas de bonnes performances (on se concentre trop sur les cas où les perfs ne suivent pas).

Lephenixnoir a écrit :
À bien y réfléchir, le problème se pose dans une plus large mesure. Supposons que le canon envoie un boulet toutes les secondes, et update() a été exécutée à t = 0.96s puis t = 1.13s. Comment connaître la position du boulet qui vient d'être envoyé ?

Mon implémentation pour ce genre de cas, c'est :
à chaque exécution de update, ajouter le delta-time à un compteur.
si le compteur dépasse 1s, créer un boulet et le déplacer selon la différence entre le compteur et 1s.
retrancher 1s au compteur.
Évidemment il y a la possibilité que le boulet spawn en retard, mais il aura parcouru une distance équivalente à ce qu'il parcourra à chaque frame, donc ce retard ne sera pas gênant du tout.

Ajouté le 23/04/2018 à 13:44 :
Lephenixnoir a écrit :
Cette solution peut paraître peu élégante, mais je la suggère parce qu'elle résout un autre problème : supposons que deux (grosses) balles de pistolet se rentrent dedans. Comment détecter la collision alors qu'au frame n elles ne se sont pas encore croisées et qu'un calcul naïf au frame n + 1 renvoie des positions après le point de croisement (ie. la collision est très rapide donc a une grande probabilité de se produire entre deux frames) ?

C'est un problème bien connu.
Je ne vois pas trop en quoi cette solution le résout. Parce qu'elle exécute plus souvent la physique ?
Lephenixnoir En ligne Administrateur Points: 24673 Défis: 170 Message

Citer : Posté le 23/04/2018 17:36 | #


Si tu veux supprimer complètement l'utilisation de timers de la game loop ok, mais trouve une solution propre pour fixer le framerate en cas de bonnes performances (on se concentre trop sur les cas où les perfs ne suivent pas).

Bien entendu. J'étais vraiment sur le bare minimum quand je disais qu'un timer n'était pas requis. Pour que tout se passe bien, il faut ajouter de la décoration.

à chaque exécution de update, ajouter le delta-time à un compteur.
si le compteur dépasse 1s, créer un boulet et le déplacer selon la différence entre le compteur et 1s.
retrancher 1s au compteur.

Ça paraît honnête. Tu fais a posteriori ce que je faisais en temps réel avec un timer, et je pense que tu as raison.

C'est un problème bien connu.
Je ne vois pas trop en quoi cette solution le résout. Parce qu'elle exécute plus souvent la physique ?

On en apprend bien tous les jours. Ce que je décris est précisément la méthode a posteriori évoqué dans l'article. Seulement, je serais tenté de ne pas faire tourner tout le moteur physique à chaque pas de temps mais seulement un subset pour détecter les collisions parce qu'on n'a pas assez de puissance sinon. Je ne sais pas si c'est possible.
Mon graphe (11 Avril): ((Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; passe gint 3 ; ...) || (shoutbox v5 ; v5)

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 177 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd