Comment faire bouger les choses toutes les N secondes dans le jeu?

8

Je veux que quelque chose se passe toutes les N secondes, comment dois-je faire? Peut-être utiliser une minuterie mais comment?

user2957632
la source
J'ai rendu votre question plus générique car je pense qu'elle est plus utile à plus de gens de cette façon.
MichaelHouse
Sur la base des commentaires sur l'une des réponses, je ne pense pas que l'affiche recherche le bit de minuterie, mais comment changer le cadre de l'image-objet. Cela dépend davantage de la plateforme dont nous parlons. Quoi qu'il en soit, maintenant que la question a été modifiée, elle ne représente plus ce qu'il demande vraiment. Java 2D était important pour la question qu'il essayait de poser.
prototype
Changer le sprite et le faire se produire toutes les 5 secondes ne sont pas liés et doivent être posées sous forme de questions différentes. Veuillez poser une nouvelle question sur le changement du sprite. Assurez-vous d'inclure ce que vous avez essayé et ce qui ne fonctionne pas.
MichaelHouse

Réponses:

14

Une approche courante consiste à utiliser la boucle de mise à jour et l'heure delta.

float timerCurrent = 0f;
float timerTotal = 5f;


Update() {
    timerCurrent += deltaTime;
    if(timerCurrent >= timerTotal) {
        //do timer action
        timerCurrent -= timerTotal;
    }
}

Cela suppose que vous ayez accès à une deltaTimevariable. Le temps delta est simplement le temps qui s'est écoulé depuis la dernière image. De nombreux moteurs auront cela à votre disposition, ou vous pouvez en savoir plus sur la configuration de votre propre ici .

MichaelHouse
la source
Est-ce dans un sens technique préférable au démarrage d'un minuteur explicite comme dans la réponse de @ Josh?
Jack M
@JackM Cela dépendra de l'implémentation de la minuterie. La raison pour laquelle j'ai répondu comme ceci est parce que c'est un langage indépendant et très simple à implémenter.
MichaelHouse
1
@JackM: C'est également préférable si vous utilisez un débogueur. Le temps de jeu accumulé peut s'arrêter lorsque vous atteignez un point d'arrêt plutôt que de voir chaque minuterie expirer et se déclencher instantanément.
Ben Jackson
Il faut être prudent, car le jeu pourrait par exemple geler et les ticks pourraient être perdus. Par conséquent, il faut invoquer l'action d'une minuterie pour chaque tick avec le delta spécifié qui est passé et pas seulement une fois, etc.
Christian Ivicevic
Cette méthode ne repose pas sur le comptage des ticks, elle repose sur le temps delta. S'il y a une trame extra longue, le temps delta est également très long. Cependant, dans de nombreux cas, il est préférable de limiter le temps de delta, des trames très longues peuvent causer des problèmes avec la physique et autres. Cette méthode est alors supérieure à l'utilisation de l'heure actuelle moins l'heure de début car elle se synchronisera mieux avec les autres calculs du jeu lors de la limitation de la durée du delta.
MichaelHouse
3

Dans la plupart des langues, vous devez démarrer l'horloge avec une sorte d'appel de fonction dans le sens de clock.startTimer()avant d'entrer dans la boucle principale. Ensuite, vous devez stocker la valeur de l'heure avant d'entrer dans la boucle principale dans une variable avec une fonction comme time = clock.getTime(). Stockez votre temps de pas dans une variable n.

Dans votre boucle principale, la vérification que vous voulez faire est quelque chose comme

if(time + n <= clock.getTime())
     //do stuff
     time = clock.getTime() //important to assign new time value here

Remarque: je ne suis pas sûr de la langue / bibliothèque que vous regardez, donc ce n'est qu'un algorithme générique auquel j'ai pensé du haut de ma tête. Il peut ne pas répondre exactement à vos besoins. Certaines langues / bibliothèques nécessitent que vous créiez un objet horloge tandis que d'autres vous permettent simplement de faire un appel de fonction directement.

Selon les commentaires ci-dessous, vous devez faire attention aux problèmes de threading en fonction de la langue que vous utilisez. Vous devez également utiliser un flotteur double pour stocker time.

Josh
la source
1
Bonne réponse. Cela pourrait avoir des problèmes de thread dans certaines langues (par exemple. .NET) où une minuterie est implémentée dans un thread distinct de votre boucle de jeu.
ashes999
1
Il est également important de noter ici que si timeva stocker le temps de jeu écoulé, il doit utiliser un format à virgule flottante double précision.
kevintodisco
Ce sont de bons points, je les ajouterai à la réponse.
Josh
2

Comme d'autres réponses l'ont déjà souligné, la mise en œuvre d'un temporisateur peut être effectuée en incrémentant une valeur stockée par chaque trame deltaTimeet en la comparant à la durée attendue. Pour être complet, je vais inclure du code qui est très similaire aux autres réponses:

float elapsed = 0.0f;
float duration = 4.0f;

void update(float deltaTime) {
    elapsed += deltaTime;
    if (elapsed <= duration) {
        // Run code.
        elapsed = 0.0f;
        // Maybe remove from update loop?
    }
}

La façon dont vous voulez gérer la // Run code.portion dépend de vous. Peut-être que vous avez une Timerclasse, dont une instance prend un delegate(C #) ou un callback(C ++) et l'appelle lorsque le temporisateur expire. En outre, la pause du minuteur consiste à le supprimer de la boucle de mise à jour.

Une autre approche consiste à marquer l'heure de début de la minuterie et à la place faire un calcul à la demande du temps écoulé:

double startTime = 0.0; // This is a double for a reason, I'll explain below.
bool running = false;

void start() {
    startTime = getTime(); // This is whatever system time call you want to use.
    running = true;
}

double getElapsed() {
    double elapsed = getTime() - startTime;
    return elapsed;
}

Ce style donne un peu plus de contrôle à l'utilisateur de la minuterie. La structure elle-même n'est pas concernée par ce qu'il faut faire lorsque le temps écoulé atteint un certain point; ce n'est même pas une mise à jour. L'utilisateur peut simplement interroger le temps écoulé lorsque cela est nécessaire. Ce modèle a pour effet secondaire malheureux de ne pas être compatible avec le débogueur. L'heure du système continue pendant que votre programme est arrêté sur un débogueur, donc les temporisateurs comme celui-ci se comporteront différemment lors de la navigation dans les programmes. Une solution potentielle à cela est de maintenir une valeur de temps écoulé spécifique au programme qui est mise à jour à chaque trame à l'aide de deltas de temps système.

Je pense que le plus important est cependant deux bizarreries de synchronisation sur un ordinateur, surtout en ce qui concerne le développement de jeux. La première est la précision en virgule flottante et la seconde est la résolution de la minuterie native.

Vous remarquerez que dans le deuxième exemple, j'ai utilisé un doubletype au lieu d'un float, comme dans le premier exemple (le nom du type dépend bien sûr de la langue que vous utilisez). La raison en est que le deuxième exemple est le stockage du temps de jeu total écoulé . Si le jeu est exécuté pendant très longtemps, les valeurs de format à virgule flottante simple précision auront une précision insuffisante pour mesurer avec précision le temps écoulé , ce qui entraînera des problèmes de stabilité. Le premier exemple est très bien en utilisant le floattype tant que des durées énormes ne sont pas attendues.

À l'autre extrémité du spectre, si le temps de mise à jour que vous attendez est suffisamment petit, vous ne pourrez peut-être pas le réaliser initialement, selon la façon dont vous obtenez l'heure du système. Les minuteries dépendent souvent de la résolution de la minuterie du système d'exploitation sur lequel vous exécutez. Par exemple, la résolution du minuteur par défaut de Windows 7 et inférieur est de 15,6 ms . Cela signifie que la précision de temporisation la plus faible que vous pourriez obtenir en utilisant des fonctions telles que timeGetTimeou GetTickCount, est de 15,6 ms, sauf si vous modifiez la résolution de la temporisation (cela comporte également des dangers ).

Eh bien, cela s'est avéré un peu long, mais ce sont des choses importantes à prendre en compte lors de l'implémentation des temporisateurs.

kevintodisco
la source
vous merci mais je maintenant comment faire ce bit, mais comment pourrais-je changer le sprite en arrière et froward
user2957632
@ user2957632 Ce n'est pas ce que votre question demande en ce moment. Veuillez être plus clair.
kevintodisco