Une musique capable de changer de manière dynamique et transparente pour refléter ce qui se passe à l'écran peut ajouter un nouveau niveau d'immersion au jeu. Dans ce didacticiel, nous examinons l’un des moyens les plus simples d’ajouter de la musique réactive à un jeu..
Remarque: Bien que ce tutoriel soit écrit en utilisant JavaScript et l'API Web Audio, vous devriez pouvoir utiliser les mêmes techniques et concepts dans presque tous les environnements de développement de jeux..
Voici une démo JavaScript de musique réactive en direct pour vous permettre de jouer avec (avec le code source téléchargeable). Vous pouvez regarder une version enregistrée de la démo dans la vidéo suivante si votre navigateur Web ne peut pas exécuter la démo en direct:
Note importante: Au moment de la rédaction de ce didacticiel, l'API Web Audio du W3C (utilisée par la démo JS) est une technologie expérimentale disponible uniquement dans le navigateur Web de Google Chrome..
Journey, un jeu développé par thatgamecompany, est un bon point de départ pour ce tutoriel. Les graphismes et la musique du jeu fusionnent pour créer une expérience interactive saisissante et émouvante, mais la musique du jeu a quelque chose de spécial qui rend l'expérience aussi puissante qu'elle est: elle coule de manière transparente dans tout le jeu et évolue de le joueur progresse et déclenche certains événements du jeu. Journey utilise une musique «réactive» pour renforcer les émotions ressenties par le joueur tout en jouant au jeu..
Pour être juste, beaucoup de jeux modernes utilisent la musique réactive d'une manière ou d'une autre - Tomb Raider et Bioshock Infinite sont deux exemples qui me viennent à l'esprit - mais chaque jeu peut bénéficier d'une musique réactive..
Alors, comment pouvez-vous réellement ajouter de la musique réactive à vos jeux? Eh bien, il existe de nombreuses façons d’y parvenir. certaines manières sont beaucoup plus sophistiquées que d'autres et nécessitent le transfert de plusieurs canaux audio à partir d'un périphérique de stockage local, mais ajouter de la musique réactive de base à un jeu est en réalité assez simple si vous avez accès à une API audio de bas niveau..
Nous allons examiner une solution suffisamment simple et légère pour être utilisée aujourd'hui dans les jeux en ligne, y compris les jeux basés sur JavaScript..
Le moyen le plus simple d'obtenir de la musique réactive dans un jeu en ligne consiste à charger un seul fichier audio en mémoire au moment de l'exécution, puis à effectuer une boucle de programmation sur des sections spécifiques de ce fichier audio. Cela nécessite un effort coordonné des programmeurs de jeux, des ingénieurs du son et des concepteurs..
La première chose à considérer est la structure actuelle de la musique.
La solution de musique réactive que nous examinons ici a besoin la musique doit être structurée de manière à ce que des parties de l'arrangement musical puissent être bouclées de manière transparente - ces parties pouvant être mises en boucle seront appelées «zones» tout au long de ce tutoriel..
En plus d'avoir des zones, la musique pouvez se composent de parties non bouclables utilisées comme transitions entre différentes zones - elles seront appelées "remplissages" dans la suite de ce didacticiel.
L'image suivante illustre une structure musicale très simple composée de deux zones et de deux remplissages:
Si vous êtes un programmeur ayant déjà utilisé des API sonores de bas niveau, vous avez peut-être déjà compris où nous en sommes: si la musique est structurée de telle sorte qu'elle permette de boucler en boucle des parties de l'arrangement, La musique peut être séquencée par programme - tout ce que nous avons besoin de savoir, c'est l'emplacement des zones et des remplissages dans la musique. C'est là un descripteur le fichier est utile.
Remarque: Il ne doit y avoir aucun silence au début de la musique; cela doit commencer immédiatement. S'il y a un morceau de silence aléatoire au début de la musique, les zones et zones remplies ne seront pas alignées sur les mesures (l'importance de cela sera traitée plus loin dans ce didacticiel)..
Si nous voulons être en mesure de lire et de boucler par programmation des parties spécifiques d'un fichier musical, nous devons savoir où se trouvent les zones et les remplissages musicaux dans la musique. La solution la plus évidente est un fichier descripteur qui peut être chargé avec la musique. Pour simplifier les choses, nous allons utiliser un fichier JSON, car la plupart des langages de programmation sont capables de décoder et d'encoder des données JSON..
Ce qui suit est un fichier JSON qui décrit la structure de musique simple dans l'image précédente:
"bpm": 120, "bpb": 4, "structure": ["type": 0, "taille": 2, "nom": "Relaxé", "type": 0, "taille" : 2, "name": "Hunted", "type": 1, "taille": 1, "name": "A", "type": 1, "size": 1, "name" : "B"]
bpm
field est le tempo de la musique, en battements par minute.bpb
field est la signature de la musique, en battements par mesure.structure
champ est un tableau ordonné d'objets qui décrivent chaque zone et remplissent la musique.type
le champ nous indique si l'objet est une zone ou un remplissage (zéro et un respectivement).Taille
champ est la longueur ou la zone ou le remplissage, en barres.prénom
champ est un identifiant pour la zone ou le remplissage.Les informations contenues dans le descripteur de musique nous permettent de calculer diverses valeurs liées au temps nécessaires pour jouer la musique avec précision via une API de son de bas niveau..
L'information la plus importante dont nous avons besoin est la longueur d'une barre de musique, en échantillons. Les zones et les pistes musicales sont toutes alignées sur les mesures et lorsque nous devons passer d'une partie de la musique à une autre, la transition doit avoir lieu au début d'une mesure. Nous ne voulons pas que la musique saute d'une position aléatoire. dans un bar parce que ça sonnait vraiment déconcertant.
Le pseudocode suivant calcule la longueur d’échantillon d’une barre de musique:
bpm = 120 // battements par minute bpb = 4 // battements par bar srt = 44100 // fréquence d'échantillonnage bar_length = srt * (60 / (bpm / bpb))
Avec le bar_length
calculés, nous pouvons maintenant calculer la position et la longueur de l’échantillon et les longueurs dans la musique. Dans le pseudocode suivant, nous parcourons simplement le descripteur structure
tableau et ajoutez deux nouvelles valeurs à la zone et aux objets de remplissage:
i = 0 n = descriptor.structure.length // nombre de zones et remplit s = 0 while (i < n ) o = descriptor.structure[i++] o.start = s o.length = o.size * bar_length s += o.length
Pour ce didacticiel, toutes les informations dont nous avons besoin pour notre solution de musique réactive - nous connaissons maintenant la position et la longueur de l'échantillon de chaque zone et remplissons la musique. nous aimons. Pour l’essentiel, nous pouvons maintenant séquencer par programmation une piste musicale infiniment longue au moment de l’exécution avec très peu de temps système..
Maintenant que nous avons toutes les informations dont nous avons besoin pour jouer la musique, la lecture programmée des zones et des remplissages à partir de la musique est une tâche relativement simple, et nous pouvons le gérer avec deux fonctions..
La première fonction consiste à extraire des échantillons de notre fichier de musique et à les transmettre à l'API de son de bas niveau. Encore une fois, je vais démontrer ceci en utilisant un pseudo-code car différents langages de programmation ont différentes API pour faire ce genre de choses, mais la théorie est cohérente dans tous les langages de programmation..
entrée // tampon contenant les échantillons de notre sortie musicale // son de bas niveau tampon de sortie de l'API tête de lecture = 0 // position de la tête de lecture dans le fichier musical, dans les échantillons start = 0 // position de départ de la zone ou du remplissage actif, en échantillons length = 0 // longueur de la zone ou du remplissage actif, en échantillons next = null // la zone ou le remplissage suivant (objet) à lire // invoqué chaque fois que l'API de son de bas niveau requiert davantage de fonctions de données d'échantillonnage update () i = 0 n = output.length // longueur d'échantillon du tampon de sortie end = longueur - commence tout (i < n ) // is the playhead at the end of the active zone or fill if( playhead == end ) // is another zone or fill waiting to be played if( next != null ) start = next.start length = next.length next = null // reset the playhead playhead = start // pull samples from the input and push them to the output output[i++] = input[playhead++]
La deuxième fonction est utilisée pour mettre en file d'attente la zone ou le remplissage suivant qui doit être joué:
// param 'name' est le nom de la zone ou du remplissage (défini dans le descripteur) function setNext (name) i = 0 n = descriptor.structure.length // nombre de zones et de remplissages tandis que (i < n ) o = descriptor.structure[i++] if( o.name == name ) // set the 'next' value and return from the function next = o return // the requested zone or fill could not be found throw new Exception()
Pour jouer la zone de musique 'Relaxed', nous appellerions setNext ("Relaxed")
, et la zone serait mise en file d'attente, puis jouée à la prochaine occasion possible.
L'image suivante montre la lecture de la zone 'Relaxed':
Pour jouer la zone de musique "Hunted", nous appellerions setNext ("Hunted")
:
Croyez-le ou non, nous avons suffisamment de ressources pour ajouter de la musique réactive simple à tout jeu ayant accès à une API son de bas niveau, mais rien ne justifie que cette solution reste simple: nous pouvons jouer à différents niveaux de la musique dans n'importe quel ordre, ce qui ouvre la porte à des bandes sonores plus complexes.
Une des choses que nous pourrions faire est de regrouper différentes parties de la musique pour créer des séquences, qui pourraient être utilisées comme des transitions complexes entre les différentes zones de la musique..
Le regroupement de différentes parties de la musique pour créer des séquences sera traité dans un prochain tutoriel, mais en attendant, considérons ce qui se passe dans l'image suivante:
Au lieu de passer directement d'une section de musique très forte à une section de musique très silencieuse, nous pourrions calmer les choses progressivement en utilisant une séquence, c'est-à-dire une transition en douceur..
Nous avons examiné une solution possible pour la musique de jeu réactive dans ce didacticiel, utilisant une structure de musique et un descripteur de musique, ainsi que le code de base requis pour gérer la lecture de musique..
La musique réactive peut ajouter un nouveau niveau d'immersion à un jeu et les développeurs de jeux devraient en tirer parti au moment de démarrer le développement d'un nouveau jeu. Les développeurs de jeux ne doivent cependant pas commettre l'erreur de laisser ce genre de choses jusqu'aux dernières étapes du développement; cela nécessite un effort coordonné des programmeurs de jeux, des ingénieurs du son et des concepteurs.