7
votes

Création d'un métronome avancé dans WPF (problèmes avec l'animation créée par code et l'événement terminé)

Bon après-midi,

Au cours des dernières semaines, je travaille sur un projet pour créer un métronome avancé. Le métronome est composé des choses suivantes

  1. un bras oscillant
  2. Un éclair de lumière
  3. une collection de contrôles utilisateur créés de manière dynamique qui représente des battements (4 d'entre eux qui sont sur, accentués ou éteints).
  4. Un usercontrol qui affiche un écran numérique LCD et calcule le nombre de millisecondes entre les battements pour le BPM sélectionné (60000 / BPM = millisecondes)

    L'utilisateur sélectionne un BPM et appuie sur Démarrer et les suivants se produisent

    1. Le bras balance deux angles à un taux de n millisecondes par balayage
    2. La lumière clignote à la fin de chaque balayage de bras
    3. Les indicateurs sont créés et ils clignotent en séquence (une à la fin de chaque balayage).

      maintenant le problème L'animation de bras et de lumière de lumière est créée dans le code et ajouté à une carte de l'histoire avec une répétition de répétition pour toujours et automatique.

      Les indicateurs sont créés dans le code et doivent déclencher un événement à la fin de chaque animation de balayage de bras. .

      Donc, ce que j'ai fait après que beaucoup de messages autour était de créer une minuterie qui fonctionne au même rythme que le scénario.

      Le problème, plus de 30 secondes, la minuterie et le storyboard vont hors de synchronisation et donc les indicateurs et le balayage du bras ne sont pas à temps (pas bon pour un métronome !!).

      J'essayais d'attraper l'événement terminé des animations et d'utiliser cela comme une gâchette à Arrêtez et redémarrez la minuterie, c'était tout ce que je pouvais trouver pour garder les deux en parfaite synchronisation.

      Le déménagement de synchronisation est causé par le glissement de la scénario et le fait que le scénario soit invoqué Sur la ligne avant que la minuterie ne soit invoquée avec .start, cela bien que les microsecondes, je pense que elles commencent incroyablement fermées mais pas exactement au même moment.

      Ma question, Lorsque j'essaie de lier à l'événement terminé de l'animation, il ne tire jamais. J'étais sous l'impression que complétiez même les incendies quelles que soient les autorités autonomes (c'est-à-dire entre chaque itération). n'est-ce pas le cas?

      Quelqu'un peut-il penser à un autre moyen (plus de rusé) de garder les deux choses en synchronisation.

      Enfin, j'ai cherché à voir si je pouvais voir un La méthode d'un storyboard (qui voudrait-elle avoir fabriqué ma vie vraiment facile, mais il semblerait que cela ne puisse pas être fait).

      S'il y a des suggestions, je ne suis pas précieux, je veux juste que ce soit fini! !

      point d'intérêt final, Le BPM peut être ajusté tandis que le métronome est en cours d'exécution, il est réalisé en calculant la durée de milliseconde à la volée (souris vers le bas d'un bouton) et en évoluant le storyboard par la différence entre la vitesse actuelle et la nouvelle vitesse. Évidemment, la minuterie qui exécute les indicateurs doit être modifiée en même temps (à l'aide d'un intervalle).

      Code ci-dessous est de mon projet jusqu'à présent (pas le xaml juste le c #) xxx


2 commentaires

Votre application peut être candidate pour Animation par cadre . Voir ce doc sur Rendu sur cadre .


J'écris une animation similaire avec DoubleanimationDowingkeyFames pour le moment. Quand je l'ai fini moi-même, je vais jeter un oeil si cela pouvait se situer pour vous.


4 Réponses :


0
votes

Vous pouvez essayer 2 animations, une pour la bonne balance et une pour la gauche. Dans l'animation complète sur chacun, démarrez l'autre animation (vérification des indicateurs d'annulation) et mettez à jour vos indicateurs (éventuellement via Begininvoke sur le répartiteur afin de ne pas interférer avec le prochain départ d'animation.)


0 commentaires

0
votes

Je pense que la minuterie se synchronise avec une animation est difficile - il s'agit d'une minuterie à base de répartiteur basée sur des messages - parfois, cela peut sauver un peu de temps, c'est-à-dire si vous cliquez sur vite avec la souris beaucoup, je pense que le La minuterie d'animation est également répartiteur basée sur une répartition, elle sera donc facilement synchronisée.

Je suggérerais d'abandonner la synchronisation et de laisser la minuterie le gérer. Vous ne pouvez pas la laisser mettre à jour une propriété avec notification et laisser votre position de bras métronome se lier à cela? Pour obtenir l'accélération / décélération, il vous suffit d'utiliser une fonction sinusoïdale ou cosinus.


1 commentaires

Vous pouvez laisser vos positions réelles être basées sur le temps système, vous pouvez obtenir des sauts en animation, mais ce sera le bon endroit et ne sortez jamais de synchronisation.



1
votes

La synchronisation du temps est un champ de poussée que vous ne le pensez.

Je vous suggère de regarder Quartz.net de renom pour les problèmes de planification / minuterie.

La synchronisation d'une animation WPF est délicate car les storyboards ne font pas partie de l'arbre logique. Par conséquent, vous ne pouvez rien lier de rien.
C'est pourquoi vous ne pouvez pas définir des storyboards dynamiques / variables dans XAML, vous devez le faire en C # comme vous l'avez fait.

Je vous suggère de faire 2 scénario: un pour la coche à gauche, l'autre à droite.
Entre chaque animation, tirez une méthode pour effectuer vos calculs / mettre à jour une autre partie de l'interface utilisateur, mais faites-la dans une tâche distincte de sorte que les horaires ne soient pas gâchés (quelques μs pour les calculs Composer un peu de temps après 30 ans déjà!)
N'oubliez pas que vous devrez utiliser application.Current.dispatcher à partir de votre tâche pour mettre à jour l'interface utilisateur.

et enfin, au moins définissez le Task drapeau TaskCreationOptionS.preferfairness de sorte que les tâches fonctionnent dans l'ordre de démarrage.
Depuis que cela donne simplement un indice sur le TaskScheduler et ne les garantit pas à exécuter dans l'ordre, vous pouvez utiliser un système de mise en file d'attente pour une garantie complète.

hth,

BAB.


0 commentaires

2
votes

Cela pourrait ne pas être facilement implémenté avec des animations WPF. Au lieu de cela, une bonne méthode serait un boucle de jeu . Une petite recherche devrait augmenter beaucoup de ressources à ce sujet. Le premier qui m'a sauté à moi était http: //www.nuclex.org/articles/3-basics/5-how-a-game-loop-works .

Dans votre boucle de jeu, vous suivriez l'une ou l'autre de ces procédures de base:

  • Calculez combien de temps s'est écoulé depuis la dernière image.
  • déplacez vos affichages de manière appropriée.

    ou

    • Calculez l'heure actuelle.
    • positionnez vos affichages de manière appropriée.

      L'avantage d'une boucle de jeu est que, bien que le chronométrage puisse dériver légèrement (en fonction du type de chronométrage que vous utilisez), tous les écrans dériveront de la même quantité.

      Vous pouvez empêcher la dérive de l'horloge en calculant le temps par l'horloge système, qui à des fins pratiques ne dérive pas. Les minuteries font la dérive, car elles ne fonctionnent pas par l'horloge système.


0 commentaires