Maison > Article > interface Web > Partage de code de jeu Javascript haute imitation Legend of Blood
La première version du jeu a été développée en 2014. Le navigateur utilise html+css+js, le serveur utilise asp+php, la communication utilise ajax et le stockage de données utilise access+mySql. Cependant, en raison de certains problèmes (je ne savais pas comment utiliser node à l'époque, écrire une logique complexe en asp était vraiment difficile à écrire ; il y avait peu d'écriture sur le canevas à cette époque, et le rendu dom pouvait facilement atteindre des goulots d'étranglement en termes de performances) , il a été abandonné. Plus tard, une version a été refaite à l’aide de toile.
Cet article vous présente principalement le code d'implémentation du jeu JavaScript haute imitation Legend of Blood. Il est très bon et a une valeur de référence. Les amis qui en ont besoin peuvent s'y référer.
1. Préparation avant le développement
Pourquoi utiliser Javascript pour implémenter un PC plus complexe -side games
1.js est réalisable pour implémenter des jeux en ligne côté PC. Avec l’évolution des configurations matérielles des PC et téléphones mobiles, la mise à jour des navigateurs et le développement des diverses bibliothèques H5, il devient de plus en plus difficile d’implémenter un jeu en ligne en js. La difficulté ici réside principalement dans deux aspects : les performances du navigateur ; la question de savoir si le code js est suffisamment facile à étendre pour satisfaire l'itération d'un jeu à la logique extrêmement complexe.
2. Parmi les jeux js à ce stade, il y en a peu à grande échelle pour référence. La plupart (presque tous) les jeux impliquant des connexions multijoueurs, un stockage de données côté serveur et des interactions complexes sont développés à l'aide de Flash. Mais Flash est finalement en déclin, tandis que js se développe rapidement et peut fonctionner tant qu'il existe un navigateur.
Pourquoi avez-vous choisi un jeu légendaire de 2001 ?
La première raison est le ressenti de l'ancien jeu bien sûr, l'autre raison plus importante est que.. . Soit je ne peux pas jouer au jeu, soit je peux y jouer mais je n'ai pas le matériel (images, bruitages, etc.). Je pense que c'est une perte de temps de consacrer beaucoup d'efforts à collecter la carte d'un jeu, les modèles de personnages et de monstres, les diagrammes d'objets et d'équipement, puis de les traiter et de les analyser avant de les utiliser pour le développement js.
Comme j'ai déjà collecté du matériel pour les jeux Legend et que, heureusement, j'ai trouvé un moyen d'extraire les fichiers de ressources du client Legend of Blood (adresse github), je peux commencer à écrire du code directement, économisant ainsi du temps de préparation.
Difficultés possibles
1. Performances du navigateur : Cela devrait être le point le plus difficile. Si le jeu souhaite conserver 40 images, il ne reste alors à chaque image que 25 ms pour que js puisse le calculer. Et comme le rendu consomme généralement plus de performances que le calcul, le temps réel restant pour js n'est que d'environ 10 millisecondes.
2. Anti-triche : Comment empêcher les utilisateurs d'appeler directement les interfaces ou de falsifier les données des requêtes réseau ? Puisque l’objectif est d’utiliser js pour implémenter des jeux plus complexes et que tout jeu en ligne doit en tenir compte, il doit exister une solution relativement mature. Ce n’est pas l’objet de cet article.
2. Conception globale
Côté navigateur
Le rendu de l'écran utilise du canevas.
Par rapport à dom(p)+css, canvas peut gérer un rendu de scène et une gestion d'événements plus complexes. Par exemple, la scène suivante implique quatre images : des joueurs, des animaux, des objets au sol et l'image la plus basse de la carte. . (Il y a en fait des ombres au sol, les noms correspondants qui apparaissent lorsque la souris pointe sur des personnages, des animaux et des objets, ainsi que des ombres au sol. Pour faciliter la lecture, nous ne considérerons pas autant de contenu.)
À ce stade, si vous souhaitez obtenir l'effet "cliquez sur l'animal, attaquez l'animal ; cliquez sur l'objet, ramassez l'objet", alors vous devez pour surveiller les événements des animaux et des objets. Si vous utilisez la méthode dom, il y aura plusieurs problèmes difficiles à résoudre :
a. L'ordre de rendu et l'ordre de traitement des événements sont différents (parfois le z-index doit être traité en premier). si le z-index est petit), ce qui nécessite un traitement supplémentaire. Par exemple, dans l'exemple ci-dessus : lorsque vous cliquez sur des monstres ou des objets, il est facile de cliquer sur des personnages, vous devez donc effectuer un traitement de « pénétration d'événement de clic » pour les personnages. De plus, l'ordre de traitement des événements n'est pas fixe : si j'ai une compétence (comme un traitement dans le jeu) qui nécessite la libération d'un personnage, alors le personnage doit avoir une surveillance des événements à ce moment-là. Par conséquent, le fait qu'un élément doive gérer des événements et l'ordre dans lequel les événements sont gérés varient en fonction de l'état du jeu, et la liaison d'événements du DOM ne peut plus répondre aux besoins.
b. Les éléments associés sont difficiles à mettre dans le même nœud DOM : comme le modèle du joueur, le nom du joueur et les effets de compétence du joueur. Idéalement, ils devraient être placés dans un e388a4556c0f65e1904146cc1a846bee section> dans le conteneur pour une gestion facile (de cette façon, le positionnement de plusieurs éléments peut être hérité de l'élément parent, sans avoir à gérer la position séparément). Mais de cette façon, le z-index sera difficile à gérer. Par exemple, si le joueur A est au-dessus du joueur B, alors A sera masqué par B. Par conséquent, l'index z de A doit être plus petit, mais le nom du joueur A ne doit pas être masqué par le nom ou l'ombre de B, ce qui ne peut pas être obtenu. . Pour faire simple, la maintenabilité de la structure DOM sacrifiera l'effet d'affichage à l'écran, et vice versa.
c. Problèmes de performances. Même si l'effet est sacrifié, l'utilisation de DOM pour le rendu conduira inévitablement à de nombreuses relations imbriquées, et les styles de tous les éléments changeront fréquemment, déclenchant continuellement la repeinture du navigateur ou même la redistribution.
Séparation de la logique de rendu du canevas et de la logique du projet
Si les différentes opérations de rendu du canevas (telles que drawImage, fillText, etc.) sont assemblées avec le code du projet, cela conduira inévitablement à l'impossibilité de maintenir le projet plus tard. Après avoir parcouru plusieurs bibliothèques de canevas existantes et combiné les outils de liaison de données et de débogage de Vue, j'ai créé une nouvelle bibliothèque de canevas Easycanvas (adresse github) et, comme Vue, elle prend en charge les éléments de débogage dans le canevas via un plug-in.
De cette façon, la partie rendu de l'ensemble du jeu sera beaucoup plus facile. Il vous suffit de gérer l'état actuel du jeu et de mettre à jour les données en fonction des données renvoyées par le socket par le serveur. Easycanvas est responsable du lien « les modifications des données entraînent des modifications de la vue ». Par exemple, dans l'implémentation du joueur enveloppant les éléments dans l'image ci-dessous, il nous suffit de donner l'emplacement du conteneur d'emballage et les règles de disposition de chaque élément dans le sac à dos, puis de lier chaque élément emballé à un tableau, puis gérer ce tableau Oui (Easycanvas est responsable du processus de mappage des données à l'écran).
Par exemple, le style d'un total de 40 éléments sur 5 lignes et 8 colonnes peut être transmis à Easycanvas sous la forme suivante (l'index est l'index de l'élément , et l'espacement dans la direction x de l'élément est de 36, l'espacement dans la direction y est de 32). Et cette logique est immuable, quelle que soit la manière dont le tableau d’éléments change ou l’endroit où le package est déplacé, la position relative de chaque élément est fixe. Quant au rendu sur toile, il n'est pas nécessaire de considérer le projet lui-même, la maintenabilité est donc meilleure.
style: { tw: 30, th: 30, tx: function () { return 40 + index % 8 * 36; }, ty: function () { return 31 + Math.floor(index / 8) * 32; } }
rendu en couches de toile
Hypothèse : le jeu doit conserver 40 images, le navigateur fait 800 de large et 600 élevé, et la superficie est de 480 000 (ci-après dénommée 480 000 pour 1 zone d'écran).
Si le même canevas est utilisé pour le rendu, alors le numéro d'image de ce canevas est 40 et au moins 40 zones d'écran doivent être dessinées par seconde. Cependant, il est probable que plusieurs éléments se chevauchent au même point de coordonnées. Par exemple, l'interface utilisateur, la barre de santé et les boutons en bas se chevauchent et bloquent conjointement la carte de la scène. Ainsi, en les additionnant, la quantité d'affichage par seconde du navigateur peut facilement atteindre plus de 100 zones d'écran.
Ce dessin est difficile à optimiser, car la vue est mise à jour n'importe où sur toute la toile : cela peut être le mouvement des joueurs et des animaux, cela peut être les effets spéciaux des boutons, cela peut être l'effet de un certain changement de compétence. Dans ce cas, même si le joueur ne bouge pas, la toile entière sera redessinée en raison de l'effet des vêtements "flottant au vent" (en fait l'animation du sprite passe à l'image suivante), ou d'une bouteille de potion apparaissant sur le sol. Parce qu'il est presque impossible qu'une certaine image du jeu ne se distingue pas de l'image précédente. Même une partie de l'écran de jeu est difficile à rester inchangée. L'ensemble de l'écran de jeu est toujours mis à jour.
Parce qu'il est presque impossible qu'une certaine image du jeu ne se distingue pas de l'image précédente, et l'écran est toujours mis à jour.
J'ai donc cette fois adopté la disposition superposée de trois toiles. Étant donné que le traitement des événements d'Easycanvas prend en charge la diffusion, même si l'utilisateur clique sur le canevas supérieur, si aucun élément ne termine un clic, le canevas suivant peut également recevoir l'événement. Les trois toiles sont responsables de l'UI, du sol (carte) et des elfes (personnages, animaux, effets de compétences, etc.) :
L'avantage de cette superposition est que chaque couche Le nombre maximum d'images peut être ajusté selon les besoins :
Par exemple, la couche d'interface utilisateur, car de nombreuses interfaces utilisateur ne bougent généralement pas, et même si elles bougent, elles n'en ont pas besoin trop dessin précis, de sorte que le nombre d'images peut être réduit de manière appropriée, par exemple à 20 . De cette façon, si la force physique du joueur passe de 100 à 20, la vue peut être mise à jour dans les 50 ms et le changement de 50 ms ne peut pas être ressenti par le joueur. Étant donné que les changements dans les données de la couche d'interface utilisateur, telles que la force physique, sont difficiles à modifier plusieurs fois de manière continue sur une courte période de temps, et que le délai de 50 ms est difficile à percevoir pour les humains, un dessin fréquent n'est donc pas nécessaire. Si nous économisons 20 images par seconde, nous pouvons probablement enregistrer 10 zones de dessin à l’écran.
Comme le sol, la carte ne changera que lorsque le joueur se déplacera. De cette façon, si le joueur ne bouge pas, 1 zone d'écran peut être sauvegardée par image. En raison de la nécessité d'assurer la fluidité des mouvements des joueurs, la fréquence d'images maximale au sol ne doit pas être trop faible. Si le cadre au sol est de 30 images, alors lorsque le joueur est à l'arrêt, 30 zones d'écran peuvent être enregistrées par seconde (dans ce projet, la carte est presque dessinée pour remplir l'écran). De plus, les mouvements des autres joueurs et animaux ne modifieront pas le sol, et il n’est pas nécessaire de redessiner la couche de sol.
La fréquence d'images maximale de la couche de sprite ne peut pas être réduite. Cette couche affichera les parties essentielles du jeu telles que les mouvements des personnages, la fréquence d'images maximale est donc fixée à 40.
Dans de cette façon, la zone dessinée par seconde, mouvement du joueur. Elle peut être de 80 à 100 zones d'écran lorsque le joueur ne bouge pas, mais elle ne peut être que de 50 zones d'écran lorsque le joueur ne bouge pas. Dans le jeu, les joueurs s'arrêtent pour combattre des monstres, taper, organiser des objets et libérer des compétences tout en restant immobiles. Par conséquent, le dessin du sol ne sera pas déclenché pendant une longue période, ce qui permet d'économiser considérablement les performances.
Côté serveur
Le but étant d'implémenter un jeu multijoueur en ligne avec js, le serveur utilise Node et socket pour communiquer avec le navigateur. Un autre avantage est qu'une certaine logique commune peut être réutilisée aux deux extrémités, comme déterminer s'il y a un obstacle à un certain point de coordonnées sur la carte.
Les données liées au jeu telles que les joueurs et les scènes côté Node sont toutes stockées en mémoire et synchronisées régulièrement avec des fichiers. Chaque fois que le service Node démarre, les données sont lues du fichier vers la mémoire. De cette façon, lorsqu'il y a plus de lecteurs, la fréquence de lecture et d'écriture des fichiers augmente de façon exponentielle, provoquant des problèmes de performances. (Plus tard, afin d'améliorer la stabilité, un tampon a été ajouté pour la lecture et l'écriture des fichiers, en utilisant la méthode "memory-file-backup" pour éviter les dommages aux fichiers causés par le redémarrage du serveur pendant le processus de lecture et d'écriture).
Le côté Node est divisé en plusieurs couches telles que l'interface, les données et l'instance. L'"interface" est chargée d'interagir avec le navigateur. Les « données » sont des données statiques, telles que le nom et l'effet d'un certain médicament, la vitesse et la force physique d'un certain monstre, et font partie des règles du jeu. « Instance » est l'état actuel du jeu. Par exemple, un médicament sur un certain joueur est une instance de « données sur un médicament ». Pour un autre exemple, « l'instance de cerf » a l'attribut « volume sanguin actuel ». Le cerf A peut être de 10, le cerf B peut être de 14, et « le cerf » lui-même n'a qu'un « volume sanguin initial ».
3. Implémentation de la carte de scène
Scène de la carte
Commençons par la partie scène de la carte, qui s'appuie toujours sur Easycanvas pour le rendu.
Réflexion
Puisque le joueur est toujours fixé au centre de l'écran, le mouvement du joueur est en réalité le mouvement de la carte. Par exemple, si le joueur court vers la gauche, la carte se déplacera vers la droite. Comme mentionné tout à l'heure, le joueur se trouve dans la couche intermédiaire des trois toiles et la carte appartient à la couche inférieure, le joueur doit donc bloquer la carte.
Cela semble raisonnable, mais s'il y a un arbre sur la carte, alors "le niveau du joueur est toujours supérieur à celui de l'arbre" est faux. À l'heure actuelle, il existe deux grandes solutions :
La superposition de cartes, "au sol" et "au-dessus du sol" séparées. Placez le joueur entre deux calques, par exemple, dans l'image ci-dessous, le côté gauche est au sol et le côté droit est au sol, puis superposez et dessinez pour prendre en sandwich le personnage du milieu :
Cela semble résoudre le problème, mais cela introduit en fait deux nouveaux problèmes : Le premier est que les joueurs peuvent parfois être bloqués par des objets "au sol" (comme un arbre), et parfois ils doivent pouvoir bloquer les choses "au sol" (par exemple, si vous vous tenez sous cet arbre, votre tête bloquera l'arbre). Un autre problème est que le coût des performances du rendu va augmenter. Étant donné que les joueurs changent tout le temps, la couche « sol » doit être redessinée fréquemment. Cela rompt également la conception originale - pour enregistrer autant que possible le rendu de la grande carte au sol, ce qui rend la superposition de la toile plus compliquée.
La carte n'est pas superposée, "au sol" et "au-dessus du sol" sont dessinés ensemble. Lorsque le joueur est derrière un arbre, réglez la transparence du joueur à 0,5, comme l'image suivante :
Il n'y a qu'un seul inconvénient à cela : le corps du joueur soit opaque, soit ils sont tous translucides (les monstres marchant sur la carte auront également cet effet), ce qui ne sera pas complètement réaliste. Car l'effet idéal est d'avoir une scène où une partie du corps du joueur est obscurcie. Mais cela améliore les performances et le code est facile à maintenir. J'utilise actuellement cette solution.
Alors, comment déterminer quelles parties de l'image « carte » sont des arbres ? Les jeux ont généralement un gros fichier de description de carte (en fait un tableau), qui utilise des nombres tels que 0, 1 et 2 pour identifier quels endroits peuvent être traversés, où se trouvent des obstacles, quels endroits sont des points de transfert, etc. Le "fichier de description" dans Legend of Hot Blood est décrit en 48x32 comme la plus petite unité, donc les actions du joueur dans Legend auront une sensation "d'échiquier". Plus l'unité est petite, plus elle est fluide, mais plus le volume qu'elle occupe est important et plus le processus de génération de cette description prend du temps.
Passons aux choses sérieuses.
Mise en œuvre
J'ai demandé à un ami de m'aider à exporter la carte de "Beach Province" dans le client Legend of Legend, qui est 33600 large et 33600 haut 22400, des centaines de fois la taille de mon ordinateur. Pour éviter que l'ordinateur n'explose, il doit être divisé en plusieurs morceaux à charger. Puisque la plus petite unité d'une légende est 48x32, nous divisons la carte en 4900 (70x70) fichiers image à 480x320.
Nous avons fixé la taille de la toile à 800x600, de sorte que les joueurs n'aient qu'à charger 3x3 images au total, qui peuvent couvrir toute la toile. 800/480=1,67, alors pourquoi pas 2x2 ? Parce qu'il est possible que la position actuelle du joueur ne provoque l'affichage que d'une partie de certaines images. Comme indiqué ci-dessous :
Recommandations associées :
Exemple de code de jeu de saisie JavaScript
Introduction graphique complète du code du jeu de puzzle HTML5 en 2 heures
Description du code du jeu JavaScript whack-a-mole_Game Entertainment
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!