Qu'est-ce que le "code de logique de jeu"?

50

J'utilise C # / XNA et on m'a souvent dit de ne pas mélanger le code de mise à jour avec le code de tirage - et je suis certain que ce n'est pas le cas! Mais quelqu'un pourrait-il s'il vous plaît décrire ce qu'est exactement le «code logique»?

Comme on peut le voir ici: http://blogs.msdn.com/b/shawnhar/archive/2007/07/25/understanding-gametime.aspx

[...] assurez-vous de mettre toute votre logique de jeu dans la méthode Update (pas dans Draw!) et tout se déroulera à une vitesse constante.

Je pose cette question car la vitesse de mon jeu fluctue par rapport au FPS. Les FPS lents correspondent aux objets se déplaçant lentement et inversement. Et oui, j'inclus le position += speed * (float)gt.ElapsedGameTime.TotalSeconds;code attendu .

C'est probablement une grande question de recrue, mais je veux juste être absolument clair sur la définition de cela.

Gars timide
la source
Je pense que tu voulais dire position = speed * ...TotalSeconds. Remarquez que =non +=. Si c'était +=juste comme vous l'aviez tapé, votre position disparaîtrait presque instantanément de l'écran.
DrZ214
J'ai un code qui ressemble à 'position + = direction * vitesse * ... TotalSeconds' et qui fonctionne très bien. J'ai peut-être mal saisi quelque chose, mais position = speed lui attribuerait chaque mise à jour. Votre chemin peut fonctionner, mais mon code fonctionne comme ceci. (Notez que la direction est normalisée)
Shyy Guy
J'ai pensé gt.ElapsedGameTime.TotalSecondsest le nombre de secondes écoulées depuis le début du programme. Si vous multipliez votre vitesse par cela, alors après 5 secondes de jeu, votre vitesse sera 5 fois plus rapide (sauf dans le cas particulier où la vitesse est réglée sur 0). Vous ne savez pas quoi d'autre pourrait rendre cela faux, mais je suis intrigué.
DrZ214
1
Aha, c'est depuis la dernière mise à jour. gamedev.stackexchange.com/questions/67968/…
Shyy Guy
2
Fascinant, je ne l'aurais jamais deviné. Jamais eu besoin d'une telle chose en quelques secondes, parce que j'utilise personnellement ma propre variable appelée iiiincrémenter manuellement chaque mise à jour, parce que je ne la veux pas en quelques secondes, je veux des étapes ou des cadres. Je peux voir que votre façon de faire est un moyen valable de coder de manière souple.
DrZ214

Réponses:

102

Cela change-t-il l'état de votre monde de jeu? C'est un code logique.

Affiche-t-il l'état du monde du jeu? C'est du code de rendu.

Nils Ole Timm
la source
Je vais parcourir mon code pour être sûr à 100%. Bonne explication, merci.
Shyy Guy
38
Est-ce qu'il gère les entrées? Son code de contrôleur. Séparez le contrôle de la logique pour pouvoir utiliser la même logique avec différents types de contrôles. Par exemple, un FPSInputController + CharacterMotor contre AIInputController + CharacterMotor contre NetworkInputController (par exemple, d'autres joueurs dans une instance multijoueur) + CharacterMotor. Le moteur (code logique) ne tient pas compte de la façon dont il obtient les instructions, mais seulement de leur ordre (ce type de découplage permet une transition aisée du joueur vers le bot IA (pensez aux joueurs de Left 4 Dead et inactifs) et vice-versa, entre autres).
Draco18s
10
Draco soulève un bon point. Il y a beaucoup de divisions différentes que vous pouvez insérer dans le code. La division de Nils est ce que je considérerais comme la division archétypale entre la logique et le rendu, mais vous verrez de nombreuses autres couches. La vraie raison de les séparer en couches est que chaque couche consiste en des actions similaires qui nécessitent un style de code similaire avec des exigences similaires. Par exemple, dans de nombreux jeux, vous pouvez vous échapper avec une logique de jeu prenant 2 ou 3 images à compléter, mais si vous n'effectuez pas le rendu de chaque image, l'œil de l'utilisateur le remarquera rapidement.
Cort Ammon
En les différenciant, vous pourrez gérer vos besoins dès lors qu’ils commencent à devenir une source de tension.
Cort Ammon
6
Et rappelez-vous que si vous lancez trop de MVC, cela peut ralentir considérablement, essayez donc toujours de trouver un équilibre entre maintenabilité et optimisation. Mais n'optimisez pas trop tôt, à moins d'être absolument sûr de ce que vous faites. Et rappelez-vous que vous pouvez toujours refactoriser. Et ... Euh, fais beaucoup de jeux et apprends de tes erreurs.
Maurycy
24

Votre séparation est correcte si:

  • L'appel de Draw () plusieurs fois de suite sans appel intercalé de Update () n'entraînerait jamais de modifications visibles entre les appels.
  • Appeler Update () plusieurs fois de suite sans un appel entremêlé de Draw () équivaudrait à jouer au jeu avec l'écran éteint: tout se déroule parfaitement et de manière cohérente, vous ne pouvez pas le voir.
Thomas
la source
5
Correctement écrit Draw()peut dessiner des images différentes au fil du temps. Par exemple, les images des images-objets animées peuvent continuer à changer. En outre, les objets peuvent continuer à avancer visuellement si le code de rendu utilise une astuce commune et ajoute velocity * time since last update / period of updateà la position visible des objets (alors que leur position réelle reste inchangée).
HolyBlackCat
2
iffsignifiant si-et-seulement-si?
BalinKingOfMoria
3
@HolyBlackCat: c'est discutable. Et si je veux suspendre les graphiques? Que se passe-t-il si les images d'animation affectent le jeu (animations d'attaque correspondant aux hitboxes, etc.)? L'interpolation visuelle implique toujours que le "temps" (comme dans le temps delta du jeu) est en train de passer, mais si le temps passe et que vous ne le faites pas, Updatequ'y a-t-il d'autre de désynchronisé? Les entrées du joueur sont manquées, les événements réseau ne sont pas traités, etc.? Le jeu doit être piloté par une seule horloge, avec des "ticks" fixes pour la logique de jeu ou la physique dérivés de cette horloge, et un état graphique dérivé également piloté par cette même horloge.
Sean Middleditch
@SeanMiddleditch Je suis d'accord, vous pouvez presque toujours écrire Draw()de manière à ce que l'image soit toujours la même lorsqu'elle est appelée plusieurs fois de suite. On devrait le faire si possible. Mais il y a des cas où vous ne savez pas à quelle fréquence Draw()sera appelée. Par exemple, si vous souhaitez une prise en charge complète (120 FPS réels) pour les nouveaux moniteurs 120hz et que vous activez vsync. What if I want to pause graphics?Ensuite, vous passez 0 à la place du temps delta réel Draw().
HolyBlackCat
2
@HolyBlackCat: Rien de ce que je voulais dire n'empêcherait l'utilisation du rendu 120hz. Je ne recommandais absolument pas un taux de tirage fixe; c'est juste amateur. Il devrait y avoir une seule horloge de jeu globale dont le delta est mesuré en termes d'images de rendu et qui alimente la valeur d'accumulation du tick de logique de jeu à taux fixe. Cette horloge globale pilote les graphiques, y compris l'interpolation. Vous pouvez mettre les graphiques en pause en réglant l'échelle de l'horloge sur 0. Vous pouvez avoir des horloges hiérarchiques pour que, par exemple, l'interface utilisateur continue de tourner et s'anime pendant que l'interpolation des caractères s'arrête aussi, très très facilement.
Sean Middleditch
7

Le point ici est la séparation des éléments du modèle qui ne sont pas le modèle.

La logique de jeu est le modèle mentionné dans

Ce sont tous différents, liés, modèles d'architecture logicielle. Mais dans tous les cas, le modèle est la même chose, c'est la logique réelle et l'état réel.

C'est lors de la création d'un logiciel de gestion que l'on parle parfois de logique métier et que certaines des stratégies d'entreprise sont codées. Par exemple, si vous codez quelque chose pour une banque, pour calculer des factures de carte de crédit, la fonctionnalité permettant à une personne de ne pas avoir à payer d’intérêts s’il efface sa dette en moins de 30 jours fait partie de la logique commerciale, elle réside dans la modèle. Il ne vit par exemple pas sur l’une des couches affichées. Le code pour imprimer une facture, par exemple, ne modifie pas le texte en fonction de ses actions. Cet exemple montre peut-être pourquoi vous souhaitez organiser votre code de cette façon.

Il en va de même pour la logique de jeu.

Imaginez qu’à un moment donné votre jeu ait été porté sur une autre console. Il peut être utile d’imaginer quelque chose de vraiment différent de votre cible actuelle. Par exemple, si vous ciblez quelque chose avec une manette de jeu / contrôleur, imaginez que votre jeu soit transféré sur une tablette à écran tactile. La logique de jeu est la partie du code qui ne change pas lorsque vous la portez.

Si votre jeu ressemblait à un jeu de stratégie militaire, imaginez-le converti au jeu de société le plus complexe au monde. La logique de jeu est constituée des sections de code, qui correspondent directement aux lignes du livre de règles. (Pas toutes les lignes du livre de règles, pas celles concernant les pièces en mouvement, mais certaines.).

La logique de jeu est la chose qui ne change jamais, peu importe la forme.

Lyndon White
la source