Mise à jour de la console sans scintillement - c++
Je suis d'essayer de faire une console de jeu de tir défilement côté, je sais que ce n'est pas le moyen idéal pour elle, mais je me suis un peu un défi.
Le problème est que chaque fois qu'il met à jour le cadre, l'intégralité de la console clignote. Est-il un moyen de contourner ce problème?
J'ai utilisé un tableau pour contenir tous les caractères nécessaires à la sortie, voici mon updateFrame
fonction. Oui, je sais system("cls")
est paresseux, mais à moins que ce soit la cause du problème, je ne suis pas embêté à cette fin.
void updateFrame()
{
system("cls");
updateBattleField();
std::this_thread::sleep_for(std::chrono::milliseconds(33));
for (int y = 0; y < MAX_Y; y++)
{
for (int x = 0; x < MAX_X; x++)
{
std::cout << battleField[x][y];
}
std::cout << std::endl;
}
}
Il y a des doublons pour cela. Si rien n', vous devriez être en interrompant le fil après vous imprimer quelque chose, et non pas lorsque l'écran est vide, mais je suppose que le scintillement sera toujours visible sur Windows.
vous devriez essayer d'utiliser ncurses, il permet de faire ce que vous voulez dans la coquille.
Les doublons ou pas, c'est une question que j'ai envie de répondre pour un temps très long, car j'ai passé beaucoup de temps à jongler avec les mêmes choses que moi-même. Il y a des moyens d'éviter le scintillement.
vous devriez essayer d'utiliser ncurses, il permet de faire ce que vous voulez dans la coquille.
Les doublons ou pas, c'est une question que j'ai envie de répondre pour un temps très long, car j'ai passé beaucoup de temps à jongler avec les mêmes choses que moi-même. Il y a des moyens d'éviter le scintillement.
OriginalL'auteur Persistence | 2016-01-17
Vous devez vous connecter pour publier un commentaire.
Ah, cela ramène au bon vieux temps. J'ai fait des choses similaires dans le lycée 🙂
Vous allez rencontrer des problèmes de performances. Console d'e/S, en particulier sur Windows, est lente. Très, très lent (parfois plus lent que l'écriture sur le disque, même). En fait, vous allez vite devenir étonné de voir comment beaucoup plus de travail que vous pouvez le faire sans que cela n'affecte la latence de votre boucle de jeu, depuis le I/O aura tendance à dominer tout le reste. Donc, la règle d'or est tout simplement de réduire le montant de l'I/O que vous faites, au-dessus de tout le reste.
Tout d'abord, je suggère de se débarrasser de la
system("cls")
et de le remplacer avec les appels à la réelle console Win32 sous-système de fonctions quicls
d'enveloppe (docs):En effet, au lieu de redessiner l'ensemble de la "trame" à chaque fois, vous êtes beaucoup mieux de dessin (ou de les effacer, en les écrasant avec un espace) les caractères à la fois:
Noter que ceci élimine le scintillement, aussi, puisqu'il n'est plus besoin de vider complètement l'écran avant de redessiner -- vous pouvez simplement changer ce qui doit changer sans intermédiaire, de clair, de sorte que l'image précédente est mis à jour incrémentielle, persistant jusqu'à ce qu'il est complètement à jour.
Je vous suggérons d'utiliser un double-buffering technique: Avoir un tampon en mémoire que représente le "courant" de l'état de l'écran de la console, initialement peuplée par des espaces. Alors un autre tampon, qui représente la "prochaine" de l'état de l'écran. Votre jeu de logique de mise à jour va modifier "à côté" de l'état (exactement comme il le fait avec votre
battleField
tableau pour le moment). Quand vient le temps de dessiner le cadre, ne pas effacer tout d'abord. Au lieu de cela, passer par les deux tampons en parallèle, et d'écrire seulement les changements partir de l'état précédent (le "courant" de la mémoire tampon au niveau de ce point contient de l'état précédent). Ensuite, copiez les "à côté" de la mémoire tampon dans le "courant" de la mémoire tampon pour la configuration de votre image suivante.Vous pouvez même aller plus loin et lot pistes de changements en un seul appel d'e/S (ce qui est nettement moins cher que de nombreux appels à caractère individuel écrit, mais toujours proportionnellement plus cher, le plus de caractères sont écrites).
En théorie, ce qui sera beaucoup plus rapide que la première boucle; toutefois, dans la pratique, il ne sera probablement pas faire une différence depuis
std::cout
est déjà mise en mémoire tampon écrit de toute façon. Mais c'est un bon exemple (et un modèle commun qui se montre beaucoup quand il n'y a pas de tampon dans le système sous-jacent), je l'ai donc inclus de toute façon.Enfin, notez que vous pouvez réduire votre sommeil à 1 milliseconde. Windows ne peut pas vraiment dormir pour moins de 10-15ms de toute façon, mais il empêchera votre cœur de PROCESSEUR d'atteindre 100% d'utilisation avec un minimum de latence additionnelle.
Remarque que ce n'est pas du tout le mode de "vrais" jeux de faire des choses; ils sont presque toujours effacer la mémoire tampon et de redessiner tout à chaque image. Ils n'obtenez pas de scintillement, car ils utilisent l'équivalent d'un double-tampon sur la carte graphique, dans le cas où l'image reste visible jusqu'à ce que le nouveau cadre est complètement terminé.
Bonus: Vous pouvez changer la couleur d'un de 8 différentes couleurs du système, et l'arrière-plan, trop:
std::memcpy((char*)prevBattleField, (char const*)battleField, MAX_X * MAX_Y);
section ne, ou ce que vous voulez dire par être contiguës en mémoire, de sorte que davantage de clarification pourrait aider. Merci pour tout!Ne pas ajouter des filets au mélange si vous pouvez l'aider -- il ne sera probablement pas améliorer les performances, mais il va considérablement compliquer votre code et peut introduire d'subtile non-déterministe de bugs (race conditions). Le
memcpy
juste des copies de tous les octets debattleField
àprevBattleField
de sorte que les deux contiennent les mêmes valeurs après (mise en place deprevBattleField
pour l'image suivante). Un "contigus" région signifie simplement que les octets sont tous les uns à côté des autres dans la mémoire. Aveca[x][y]
, tous les octets pour une colonne donnée sont contigus, mais vous voulez que tous les octets pour une ligne donnée à contiguë (a[y][x]
).C'est... étonnant. Je suis en train d'apprendre beaucoup de cette réponse
Excellent 😀 C'est une réponse que j'ai eu envie d'écrire depuis des années, alors quand l'occasion s'est présentée je l'ai pris.
OriginalL'auteur Cameron
system("cls")
est la cause de votre problème. Pour mettre à jour le cadre de votre programme doit générer un autre processus, puis de charger et d'exécuter un autre programme. C'est assez cher.cls
efface votre écran, ce qui signifie que pour une petite quantité de temps (jusqu'à ce que le contrôle retourne à votre processus principal), il affiche complètement rien. C'est là que le scintillement.Vous devez utiliser une bibliothèque comme
ncurses
qui vous permet d'afficher la "scène", puis déplacez votre curseur de position <0,0> sans modifier quoi que ce soit sur l'écran et réafficher votre scène "de plus" la vieille. De cette façon, vous éviterez de scintillement, parce que votre scène sera toujours afficher quelque chose, sans complètement vide à l'écran de l'étape.OriginalL'auteur nsilent22
Une méthode consiste à écrire les données mises en forme d'une chaîne de caractères (ou tampon), puis bloquer l'écriture de la mémoire tampon de la console.
De chaque appel d'une fonction a une surcharge. Essayez d'aller en faire plus d'une fonction. À votre Sortie, cela pourrait signifier beaucoup de texte par sortie demande.
Par exemple:
Opérations d'e/S sont chers (exécution-sage), de sorte que la meilleure utilisation est de maximiser la quantité de données par demande de produits.
OriginalL'auteur Thomas Matthews