Créer un jeu de physique animé avec JavaScript | Frank Dvorak | Skillshare
Recherche

Velocidad de reproducción


1.0x


  • 0.5x
  • 0.75x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 1.75x
  • 2x

Crea un juego de física animado con JavaScript

teacher avatar Frank Dvorak, Creative Coding

Regardez ce cours et des milliers d'autres

Bénéficiez d'un accès illimité à tous les cours
Suivez des cours enseignés par des leaders de l'industrie et des professionnels
Explorez divers sujets comme l'illustration, le graphisme, la photographie et bien d'autres

Regardez ce cours et des milliers d'autres

Bénéficiez d'un accès illimité à tous les cours
Suivez des cours enseignés par des leaders de l'industrie et des professionnels
Explorez divers sujets comme l'illustration, le graphisme, la photographie et bien d'autres

Leçons de ce cours

    • 1.

      Introducción

      0:46

    • 2.

      Configuración básica

      3:51

    • 3.

      Programación orientada a objetos en JavaScript

      4:21

    • 4.

      Dibuja al jugador

      7:10

    • 5.

      Controles del ratón

      5:59

    • 6.

      Hacer que el jugador se mueva

      7:39

    • 7.

      Crea obstáculos

      6:33

    • 8.

      Obstáculos que no se superponen

      6:35

    • 9.

      Imágenes aleatorias de una hoja de sprite

      5:14

    • 10.

      Reglas de posicionamiento

      5:59

    • 11.

      Método de detección de colisiones reutilizable

      4:04

    • 12.

      Física

      8:07

    • 13.

      8 animación de sprites direccionales

      4:13

    • 14.

      Ángulos de animación

      7:05

    • 15.

      Modo de depuración

      3:33

    • 16.

      Límites de movimiento de los jugadores

      2:56

    • 17.

      FPS

      9:39

    • 18.

      Clase de huevos

      4:53

    • 19.

      Añade nuevos huevos periódicamente

      6:59

    • 20.

      Física de huevos

      5:34

    • 21.

      Orden de sorteo

      8:17

    • 22.

      Clase de enemigos

      11:19

    • 23.

      Clase de larva

      3:26

    • 24.

      Sombrear con líneas

      9:58

    • 25.

      Sprites de larva y colisiones

      4:37

    • 26.

      Conseguir puntos de partitura

      2:40

    • 27.

      Efectos de partículas

      8:55

    • 28.

      Movimiento de partículas

      7:04

    • 29.

      Diseños de enemigos aleatorios

      4:24

    • 30.

      Condición de ganar y perder

      10:31

    • 31.

      Reinicia el juego

      6:32

    • 32.

      Extensión de la clase de enemigos

      5:55

    • 33.

      Modo de pantalla completa simple

      3:07

    • 34.

      Animación completa de la hoja de sprite del jugador

      2:36

    • 35.

      Animación completa de la hoja de sprite de larva

      1:43

    • 36.

      Animación completa de la hoja de sprites de los enemigos

      6:38

    • 37.

      Proyecto adicional (opcional)

      0:46

    • 38.

      Configuración de proyectos adicionales

      1:36

    • 39.

      Mejora de mundos de juego

      6:56

    • 40.

      Configuración de JavaScript

      5:52

    • 41.

      Controles de teclado

      7:27

    • 42.

      Personaje jugador

      11:21

    • 43.

      4 hojas de sprites direccionales

      12:00

    • 44.

      Cómo controlar FPS

      9:02

    • 45.

      Objetos de juego colocados al azar

      8:19

    • 46.

      Layering y orden de sorteo en juegos 2D

      5:33

  • --
  • Nivel principiante
  • Nivel intermedio
  • Nivel avanzado
  • Todos los niveles

Generado por la comunidad

El nivel se determina según la opinión de la mayoría de los estudiantes que han dejado reseñas en esta clase. La recomendación del profesor o de la profesora se muestra hasta que se recopilen al menos 5 reseñas de estudiantes.

164

Estudiantes

1

Proyectos

À propos de ce cours

¿Qué hace que un juego sea genial? ¿Se trata de imágenes hermosas y refinadas o de un juego que se siente bien y responde? ¿Se trata de ideas únicas o tal vez de pequeños detalles, secretos especiales y huevos de Pascua? ¿Cuáles son los ingredientes de una receta perfecta para desarrollar un juego?

 

En esta clase, nos sumergiremos en la animación de sprites, la interactividad y la física 2D. Aprenderemos 10 técnicas importantes que todo desarrollador de juegos necesita conocer y las aplicaremos en un proyecto real. 

 

Los estudiantes de esta clase recibirán una gran cantidad de arte profesional de juegos en 2D en alta resolución de forma gratuita. Ofrezco elementos de arte ambiental y de personajes en forma de hojas de sprites listas para usar, así como archivos fuente con piezas separadas para aquellos de ustedes que quieran editar los colores, armar sus propias setas y criaturas o manipular sus propias animaciones. 

 

Hoy aprenderemos:

- Cómo usar el método drawImage incorporado para dibujar entornos de juego aleatorios y personajes animados de una hoja de sprite

- Cómo controlar el FPS de nuestro juego y cómo medir el tiempo para activar eventos periódicos

- Cómo reiniciar el juego presionando un button

- Cómo aplicar la detección de colisiones, resolver colisiones y usarlo para simular física

- Cómo implementar una IA muy simple para que las criaturas se sientan vivas

- Cómo capturar la posición del ratón y animar una hoja de 8 sprites direccionales en función de la posición relativa entre el ratón y el personaje jugador

- Cómo usar HTML5, CSS3 y JavaScript simple para crear un juego desde cero. Escribiremos y entenderemos cada línea de código, no dependeremos de ningún framework o librería externa

... y mucho más

 

El ritmo y las técnicas de este curso son ideales para principiantes. Se necesita un conocimiento existente de HTML, CSS y JavaScript para seguir el curso. Si entiendes los conceptos básicos de JavaScript y sabes qué funciones son los bucles y las matrices, podrás sacar el máximo provecho de esta clase.

 

¡Diviértete! :)

Conoce a tu profesor(a)

Teacher Profile Image

Frank Dvorak

Creative Coding

Profesor(a)

Hello, I'm Frank. I'm a front-end web developer, owner of Frank's Laboratory YouTube channel. Come explore creative coding, game development and generative art with me.

Ver perfil completo

Level: Beginner

Notes attribuées au cours

Les attentes sont-elles satisfaites ?
    Dépassées !
  • 0%
  • Oui
  • 0%
  • En partie
  • 0%
  • Pas vraiment
  • 0%

Pourquoi s'inscrire à Skillshare ?

Suivez des cours Skillshare Original primés

Chaque cours comprend de courtes leçons et des travaux pratiques

Votre abonnement soutient les enseignants Skillshare

Apprenez, où que vous soyez

Suivez des cours où que vous soyez avec l'application Skillshare. Suivez-les en streaming ou téléchargez-les pour les regarder dans l'avion, dans le métro ou tout autre endroit où vous aimez apprendre.

Transcription

1. Introduction: Qu'est-ce qui fait un jeu parfait ? graphismes détaillés et fabriqués à la main, des environnements fantastiques et une grande variété de personnages animés ? Ou s'agit-il plutôt de la mécanique du jeu, la physique des interactions et IA pour que les créatures se sentent vivantes ? Quel est l'ingrédient spécial la recette de développement de jeux ? Dans ce cours, nous allons approfondir les secrets du JavaScript, de l' animation Web et du développement Web frontal. Essayons de découvrir ce qui fait un bon jeu et comment nous pouvons le créer du début à la fin en utilisant uniquement notre propre code JavaScript, sans frameworks ni bibliothèques. Ce cours est destiné aux débutants, mais certaines connaissances de base développement Web frontal sont nécessaires pour en tirer le meilleur parti. Allons-y. 2. Configuration de base: Je vais offrir une tonne d'illustrations de jeu gratuites pendant ce cours, je vais être comme ça. Nous contrôlerons la boule bleue. Son travail consiste à protéger les œufs à éclore des vagues d'ennemis affamés. Le joueur peut positionner tous les objets du jeu en les poussant. Nous pouvons mettre le X et les nouveau-nés en sécurité, ou nous pouvons repousser les ennemis pendant la construction de ce projet. Je vais vous montrer comment utiliser le HTML, le CSS et du JavaScript standard pour implémenter nombreuses techniques importantes d'animation Web et de développement de jeux Nous appliquerons la physique pour faire interagir les objets d'un jeu les uns avec les autres. Nous allons apprendre comment redémarrer notre jeu en appuyant sur un bouton, comment contrôler le FBS de l'ensemble du jeu, comment déclencher des événements périodiques. Nous appliquerons la plupart des contrôles. Apprenez à gérer et animer des feuilles de calcul directionnelles. Nous déclencherons et animerons des particules lorsqu'un certain événement se produit, et bien plus encore. Prolons-y étape par étape pour nous assurer de bien comprendre le code. À la fin de ce cours, vous aurez toutes les compétences nécessaires pour créer vos propres jeux et projets d'animation. Je crée un élément IMG avec un identifiant de superposition. La source sera un point PNG superposé. Vous pouvez télécharger tous les éléments du projet dans la section des ressources ci-dessous Il y a des images et des sprites individuels tels que je les utilise dans ce cours, ainsi qu'un dossier bonus contenant fichiers sources où chaque objet du jeu Gmb divisé en pièces haute résolution. Vous pouvez les modifier et les animer. Donc, si vous le souhaitez, vous pouvez les mélanger, les combiner avec des œuvres d'art que je vous ai données pour d'autres cours où nous utilisons ce thème de la forêt de champignons. Et vous pouvez créer vos propres environnements de jeu uniques. Toutes les œuvres de ce cours sont libres de droits d'auteur. N'hésitez pas à les télécharger, à les modifier et à les réutiliser dans vos propres projets comme vous le souhaitez. Je vous donne déjà toutes les œuvres dont vous aurez besoin pour suivre ce cours. Mais pour ceux d'entre vous, je veux aller plus loin. Si vous utilisez un éditeur graphique tel que Photoshop, vous pouvez par exemple modifier les couleurs des images pour créer encore plus de variété visuelle. Les fichiers sources des personnages peuvent également être violés et animés dans des outils de sprite 2D tels que des os de dragon ou une colonne vertébrale Consultez les fichiers sources et utilisez-les comme bon vous semble. C'est un cadeau que je te fais en guise remerciement pour le temps que tu as passé avec moi. Nous avons donc une configuration de base dans index.HTML et un style CSS. Gammas utilise par défaut cette petite taille de 300, 150 pixels. Si je définissais sa taille avec du CSS, je ne définirais que la taille de son élément. Et cela élargirait mes dessins. Le canevas HTML a en fait deux tailles. Taille de l'élément, taille de la surface de dessin qui peut être définie indépendamment. Je veux que les deux tailles soient identiques pour éviter toute distorsion. Je vais donc dimensionner mon canevas avec le JavaScript ici. J'intègre tout dans Load Event Listener, car nous utiliserons de nombreuses ressources artistiques. Et je voulais m'assurer que toutes mes images étaient complètement chargées et disponibles avant l'exécution de tout code JavaScript. abord, nous devons pointer JavaScript vers notre élément de canevas en utilisant get element by ID. Nous enregistrons cette référence dans cette variable personnalisée que j'appelle par exemple canvas. Ensuite, je prends cette variable et j' appelle la méthode intégrée GetContext, passant à D en tant qu'argument de type de contexte. Cela initialisera un objet intégré qui contient toutes les propriétés et méthodes de dessin du Canvas. Nous pouvons maintenant les appeler à partir de cette variable CD x. Comme je l'ai déjà dit, je souhaite définir la taille du canevas, la taille des éléments et la taille la surface de dessin sur la même valeur. On peut le faire comme ça. La largeur des points du canevas est de 1 280 pixels et la hauteur du canevas est de 720 pixels. Maintenant, l'illustration d' arrière-plan complète que j'ai préparée pour vous se révèle parfaite. 3. Programmation orientée objet en JavaScript: Je voulais écrire ce jeu sous forme base de code orientée objet pour le rendre plus modulaire Nous aurons une classe pour le joueur et autre classe pour le jeu pour gérer toute la logique du jeu. Le cerveau principal de cette base de code. Nous aurons également besoin d' une boucle d'animation pour dessiner et mettre à jour notre jeu encore et encore afin de créer une illusion de mouvement. constructeur de classe de jeu s' attendra à une référence à un élément du canevas comme argument comme celui-ci. À l'intérieur, nous la convertissons en propriété de classe et nous aurons besoin de la propriété de largeur. Et la valeur sera ce point Canvas à partir de la ligne 15, largeur du point. Comme ça. Cela nous donnera 1 280 pixels lorsque nous l'avons configuré en ligne, nous faisons la même chose pour cette hauteur de point. Nous prenons une référence à élément Canvas et nous définissons la largeur et la hauteur de notre jeu de manière à ce qu'elles soient identiques à la largeur et à la hauteur de Canvas. Nous terminerons cette configuration en connectant cet argument de canevas à cette variable de canevas un peu plus tard. Lorsque nous créerons une instance de notre classe de jeu en utilisant le nouveau mot clé, nous y arriverons plus tôt. Je vais te montrer. Avant cela, j'ai également besoin que le joueur ait accès aux propriétés de largeur et de hauteur de notre jeu, car il doit savoir, par exemple quand il se déplace hors de la zone de jeu, etc. Je vais lui donner accès à l'ensemble de la classe de jeu toutes ses propriétés et méthodes en lui transmettant une référence à cette classe de jeu sous forme d'argument, nous la convertissons en propriété de classe. Gardez à l'esprit que je ne crée pas de copie de Game Object lorsque je crée des objets de joueur en JavaScript qui sont des types de données de référence. Donc, ce jeu de points sur la neuvième ligne ne crée pas de copie. Cela indique simplement un espace dans la mémoire où notre objet de jeu principal est stocké. Le code à l'intérieur d'un constructeur de classe. Il se déclenche lorsque nous créons une instance d'une classe en utilisant le nouveau mot clé, nous le ferons dans une minute. Je veux que notre base de code crée automatiquement un joueur lorsque nous créons une instance de notre objet de jeu principal. Je peux donc le faire dans le constructeur de classe. Je crée une propriété appelée ce point Player et je la définis sur New Player comme ceci. Je peux voir que le constructeur de classe de joueurs, l'aide en ligne, attend le jeu comme argument. Je lui passe donc ce mot clé, puisque nous sommes ici dans cette classe de jeu. Ce mot clé fait ici référence à l'ensemble de l'objet du jeu. Ici, à la ligne 18, nous créons une instance de classe de joueur et nous l'enregistrons sous ce point. La propriété Player de la structure des classes du jeu dans forme de ce point. La propriété Player de la structure des classes du jeu dans notre code créera automatiquement un joueur. Lorsque nous créons un jeu, nous créons une instance d'objet de jeu comme cette variable personnalisée que j'appelle par exemple game, et je la définis comme étant égale à new game. À la ligne 14, je peux voir que le constructeur de la classe de jeu attend Canvas comme argument. Je passe donc la variable canvas de la ligne à cette variable qui sera convertie en propriété de classe et la largeur et la hauteur de la zone de jeu en seront extraites comme prévu. Vérifions si tout a fonctionné en consolidant cette variable de jeu. Super, je peux voir les propriétés de largeur et de hauteur correctes et nous avons également une instance de classe de joueur dedans. C'est l'une des manières d' organiser et de connecter vos objets dans une base de code JavaScript orientée objet. Gardez à l'esprit que l'ordre dans lequel nous définissons les classes est important. Le fichier Javascript est lu ligne par ligne de haut en bas. Les classes Javascript sont hissées, mais elles ne sont initialisées que lorsque cette ligne particulière est correcte. classe du joueur doit donc être définie avant d'être utilisée. Une très bonne idée serait de diviser notre code JavaScript en modules individuels et d'importer et d'exporter nos classes entre fichiers selon les besoins. Pour ce projet, j' écrirai tout le code dans un seul fichier JavaScript afin de le rendre aussi convivial que possible pour les débutants L'utilisation de modules JavaScript nous obligerait à exécuter ce code via un serveur local. Il n'exécuterait plus le code en ouvrant simplement un fichier HTML d'index dans un navigateur Web Si vous êtes plus expérimenté, il vous sera très facile de terminer le projet avec moi. Ensuite, si vous le souhaitez, vous pouvez vous-même diviser les cours individuels en modules distincts. Ce cours est destiné aux débutants Concentrons-nous donc sur les principes orientés objet et les techniques d'animation. 4. Dessiner le joueur: La fonction qui se trouve sur un objet s'appelle une méthode. Le joueur devra utiliser la méthode de dessin pour dessiner et animer. Il s'attendra à ce que le contexte soit un argument pour spécifier sur quel type d' entre nous nous appuyons. Nous allons connecter cet argument de contexte à notre variable CTX à partir de la troisième ligne Lorsque nous appellerons cette méthode de dessin un peu plus tard, je vous le montrerai. Au début, je voulais dessiner un cercle simple , représentant notre joueur. Pour dessiner un cercle sur Canvas, nous utilisons des contextes et nous appelons begin path pour indiquer à JavaScript que nous voulons commencer à dessiner une nouvelle forme. Nous voulons fermer la forme précédente. S'il y en a, nous appelons la méthode arc intégrée, qui attend au moins cinq arguments. Il attend les coordonnées x et y du point central du cercle. Son rayon, son angle de départ en radians, est mesuré à partir de l'axe X positif et un angle où l'arc se termine, toujours en radians, mesuré à partir de l'axe X positif. Il existe un sixième argument facultatif pour le sens antihoraire. Si nous ne le définissons pas, il sera défini par défaut sur false, ce qui signifie que l'arc sera dessiné dans le sens des aiguilles d'une montre. Donc, l'angle de départ est de 0 rad et l'angle final est de math.pi fois deux, c'est un cercle complet. Nous pouvons maintenant choisir d'appeler remplissage, remplir la forme avec de la couleur, de tracer juste pour définir la forme. Ou on pourrait utiliser les deux. Nous le ferons bientôt. Comment dessiner réellement le joueur sur Canvas ? Maintenant, dans la classe de jeu, je crée une méthode que j'appelle, par exemple, un rendu. Cette méthode permettra de dessiner et de mettre à jour tous les objets de notre jeu. Il attend des contextes comme argument. À l'intérieur, je prends ce point Player de la ligne 23 et, grâce à cette référence, nous accédons à la méthode de tirage sur la classe de joueur que nous venons de définir à partir de la ligne 11. Cette méthode contient le code pour dessiner un cercle représentant le joueur. Je peux voir qu'il attend des contextes comme argument, donc je le transmets à ce contexte, nous l'avons passé à la méthode de rendu. Je peux maintenant prendre cette variable de jeu qui contient une instance de la classe de jeu complète. Et à partir de là, j'appelle render, et je le passe à CTX. À partir de la troisième ligne, ce CTX se verra attribuer un contexte de nom variable ici, et il sera transmis à méthode de dessin en fonction de la classe du joueur. Super, nous dessinons un cercle noir représentant la présence du joueur. Peut-être que tu ne peux pas le voir. Donnons-lui donc des coordonnées x et y différentes pour le déplacer. Au lieu de coder en dur toutes ces valeurs, je souhaite que vous créiez des propriétés dans la classe Player. Alors utilisez-les ici. Nous aurons besoin des coordonnées x et y pour la position du joueur. Mais parce que dans ce cours, nous découvrons les cases de position et de frappe et les images de personnages qui peuvent avoir des formes et des tailles très différentes. Je devrai créer une propriété pour les positions X et Y de la boîte d'identification du joueur. Et j'aurai besoin d' une propriété x et y différente pour l'image de la feuille de sprite du joueur. Cela aura plus de sens au fur et à mesure que nous le construirons. Je veux être très explicite avec noms de mes variables afin de préciser clairement quelle valeur est la position de la zone de collision et quelle valeur est la position d'une feuille de calcul. Donc, au lieu de nommer ces propriétés uniquement x et y, je les nommerai collision x et collège et position Y, X et Y de la zone de collision située au centre du cercle de collision. Tous les objets de notre jeu d'aujourd'hui seront dotés de zones de frappe circulaires, car je voulais vous montrer comment les faire pousser et glisser les uns sur les autres sur la position de départ du joueur exactement au milieu de la zone de jeu. Collision X sera donc ce jeu de points à partir des lignes 9. Et à partir de cette propriété, je vais extraire la largeur de la ligne 23. Et au milieu, donc multiplié par 0,5, la collision y sera la même. Ce point joue avec la hauteur multipliée par 0,5. Maintenant, je peux utiliser ces valeurs comme arguments x et y pour la méthode Canvas arc comme celle-ci. Nous pouvons maintenant déplacer le joueur en modifiant les valeurs de collision et de collision. Pourquoi des propriétés ? Nous aurons également besoin d'une propriété appelée rayon de collision, qui définira la taille de cette couche circulaire. Il avait des livres. Je l'utilise également ici dans la méthode arc. couleur de remplissage par défaut est toujours le noir. Je peux remplacer, adhérer par certains types de propriétés FillStyle au blanc comme ceci. Au lieu de remplir la forme de couleur, nous pourrions aussi simplement la caresser. Encore une fois. Par défaut, la largeur de ligne du trait est d'un pixel et la couleur est noire. J'ai réglé la largeur de ligne à trois pixels et j'ai défini le style de trait sur blanc. Notez que je définis ces propriétés Canvas en dehors de toute classe ou méthode. Je le fais exprès car ce code ne s'exécutera qu'une seule fois lors du chargement initial de la page. Cela n'est pas toujours possible si vous avez plusieurs objets avec des champs, des styles et des couleurs de trait différents . Dans ce cas, vous devrez définir ces propriétés dans la méthode de dessin et passer de l'une à l'autre encore et encore. Le problème, c'est que la méthode de dessin sera appelée 60 fois par seconde. Et un changement dans un tel état peut coûter cher en termes de performances. C'est une bonne idée de structurer le code de manière modifier le moins possible un état. Et quand je parle d'état du canevas, je veux dire tout, des transformations aux modifications des couleurs du FillStyle et du style des traits. C'est pourquoi j'ai mis ce code ici au lieu de le placer directement dans la méthode de dessin pour qu'elle s'exécute le moins possible tout en appliquant les couleurs et les paramètres dont j'ai besoin. Je peux aussi appeler Fill ici. Nous remplissons et traçons maintenant le même chemin défini par la méthode de l'arc. Je veux que le remplissage soit blanc, mais je voulais qu'il soit légèrement transparent. Kind of us possède une propriété alpha globale qui définit opacité des formes que nous dessinons. Le problème, c'est que lorsque j'ai donné alpha globale à une valeur différente, tout ce qui sera dessiné par la suite sera semi-transparent. Je souhaite que la transparence ne s'applique qu'à la couleur de fond du cercle de collision des joueurs afin de limiter certains types de paramètres à des appels de tirage spécifiques. Nous pouvons intégrer ce code de dessin entre méthodes Canvas sécurisées et restaurées. Et si je disais que l'alpha global est égal à 0,5, cela n'affectera que cette action de dessin spécifique. Dans notre cas, cela n' affectera que le remplissage de ce cercle. La méthode save crée donc un instantané de l'état actuel, y compris son FillStyle, son opacité en largeur de ligne, ainsi que les transformations et la mise à l'échelle. Si c'est ce que nous faisons, je peux apporter toutes les modifications nécessaires à l'état que je souhaite. Dans ce cas, je viens de régler l'opacité à 0,5. Cette couleur de remplissage sera affectée par cette modification de l'opacité. Ensuite, nous appelons restauration, c'est-à-dire la restauration de toutes sortes de paramètres tels qu'ils étaient lorsque nous avons appelé pour la première fois la méthode de sauvegarde associée. Pour cette raison, l'accident vasculaire cérébral ne sera pas affecté par une opacité réduite. Les méthodes de sauvegarde et de restauration nous permettent d'appliquer des paramètres de dessin spécifiques uniquement pour sélectionner les formes sans affecter le reste de nos dessins Canvas. 5. Contrôles de la souris: Je veux déplacer le joueur à l'aide de la souris. Nous savons déjà que le code contenu dans le constructeur de classe de jeu sera exécuté au moment où nous créerons une instance de cette classe à l'aide du nouveau mot clé. Nous tirons parti des données en créant automatiquement une instance de classe de joueur ici Nous pouvons en fait exécuter n'importe quel code JavaScript ici. Je peux même placer des auditeurs d'événements ici pour m'assurer qu'ils sont automatiquement appliqués. Lorsque je crée une instance de classe de jeu, je crée un écouteur d'événements pour les événements liés à la souris enfoncée. Lorsque vous cliquez sur le bouton de la souris, le code contenu dans cette fonction de rappel s'exécute. J'ai testé en enfonçant simplement le mot souris sur la console. Si j'enregistre les modifications parce que je suis déjà train d'instancier cette classe en ligne pour D6. écouteur D7 est automatiquement appliqué. Maintenant, lorsque je clique sur Canvas, journal de la console déclenche belle fonction de rappel sur EventListener qui génère automatiquement un objet d'événement contenant toutes sortes d'informations sur l'événement qui vient de se produire. Pour accéder à cet objet, il suffit de lui donner un nom de variable. Tu peux le nommer comme tu veux. Mais la convention est généralement un événement ou E. Consignez cet événement sur la console. Je clique sur Canvas et je le vois ici. J'ai inspecté. Vous pouvez voir qu'il contient de nombreuses informations sur ce clic de souris, par exemple, nous voyons les coordonnées x et y de ce clic ici. Il existe de nombreuses autres propriétés qui nous indiquent quel bouton de la souris a été pressé et bien d'autres choses encore. Je veux que vous preniez les coordonnées du clic et les enregistrez en tant que propriétés sur l'objet principal du jeu. Et à partir de là, nous pourrons également y accéder depuis notre objet joueur. Je crée une nouvelle propriété sur la classe de jeu appelée cette souris à points. Ce sera un objet avec la propriété x avec valeur par défaut de cette largeur de point multipliée par 0,5. Et y sera cette hauteur de point multipliée par 0,5. Donc, le milieu de la toile, horizontalement et verticalement. Nous voudrons également surveiller le moment où le bouton de la souris est enfoncé. Dans un premier temps, il sera défini sur false. Si je console log e point x et y, vous pouvez voir que nous obtenons les coordonnées x et y lorsque nous cliquons autour de nous. Le problème est que les coordonnées proviennent du bord supérieur gauche de la fenêtre du navigateur. Je voudrais plutôt mesurer les coordonnées du clip à partir du coin supérieur gauche de Canvas. Ainsi, lorsque nous cliquons ici dans le coin supérieur gauche du canevas, nous obtenons x et y zéro. Pour cela, nous pouvons utiliser une propriété différente sur cet objet d'événement généré automatiquement appelée offset x, qui nous donnera la coordonnée horizontale du clic sur le nœud cible. Dans notre cas, le nœud cible, la cible du clic, est en quelque sorte un élément. Vous pouvez maintenant voir les valeurs se rapprocher de zéro lorsque je clique près du bord de Canvas. Je pourrais également ajouter l'écouteur d' événements à l'élément de toile lui-même plutôt qu'à l'ensemble de l'objet de la fenêtre du navigateur. Si je clique plus près du coin supérieur gauche, nous obtenons des valeurs proches de 00. Parfait. Il serait probablement logique que j' utilise plutôt cette propriété point Canvas ici à partir de la ligne 31, puisque nous sommes à l'intérieur d'une classe et que la référence à Canvas est disponible ici. Nous obtenons maintenant la coordonnée du clic mesurée en pixels à partir du coin supérieur gauche de Canvas. Même lorsque nous redimensionnons la fenêtre du navigateur, cela fonctionne bien. Je souhaite que vous enregistriez les coordonnées cycliques dans propriété de la souris de notre client afin qu'elles soient accessibles à d'autres objets de notre base de code, tels que le lecteur intégré à l'écouteur d'événements avec la souris enfoncée. Je prends cette propriété point x de la souris à partir de la ligne 36, et je la définis comme étant égale à E point offset x. Ce point y de souris sera décalé par e point. Pourquoi ? Je crée un autre journal de console et j'examinerai ces propriétés de souris récemment mises à jour. Lorsque je clique sur Canvas, une erreur indique qu'il est impossible de définir des propriétés sur certains x non définis en ligne pour D3 Cela me dit que je ne peux pas définir propriété x sur quelque chose qui n'est pas défini. Pour une raison quelconque, cette souris à points n'est pas définie lorsqu'on y accède depuis Event Listener. C'est parce que lorsque cette fonction de rappel sur l'écouteur d'événements s'exécute, elle a oublié qu'elle avait été initialement définie dans ce constructeur de classe de jeu. Il oublie ce que signifie ce mot clé. Cela devrait permettre à l'écouteur d'événements de se souvenir de l' endroit où il a été défini pour la première fois, de sa position dans le champ lexical de notre base de code. Nous pouvons simplement utiliser la fonction de flèche ES6 ici à la place. L'une des particularités des fonctions de flèche d' ES6 est qu'elles ont automatiquement hérité de la référence à ce mot clé du scope parent. Toutes des fonctions. Rappelez-vous où, dans la base de code ils ont été initialement déclarés lexicalement. Et ils ajustent leur mot clé de bureau pour pointer vers le bon objet, vers l'objet parent. Désormais, ce point x de souris et ce point de souris visuel y sont correctement mis à jour avec les nouvelles valeurs, ce qui rend les coordonnées actuelles de la souris disponibles dans toute notre base de code chaque fois qu'elles sont nécessaires. Plus tard, je supprime les journaux de la console. Lorsque l'événement « souris enfoncée » se produit. J'ai dit que le prix allait de la ligne 38 à vrai. J'ai copié cet écouteur d'événements. Celui-ci sera réservé à l'événement Mouse Up. Lorsque le bouton de la souris est relâché, tout reste le même ici et la poitrine redevient fausse. Je crée également un écouteur d'événements pour les événements de déplacement de la souris. Laissons-nous consulter pour vérifier. Oui, ça marche. Faisons bouger le joueur. 6. Faire déplacer le joueur: Créez une méthode personnalisée que j'appelle mise à jour. À l'intérieur, j'ai dit collision x de la ligne 14 à la position X actuelle de la souris. Et la collision y sera la position Y actuelle de la souris, comme ceci. Pour exécuter ce code, nous devons en fait appeler la méthode de mise à jour. Je vais l'appeler depuis le rendu interne ici. Je supprime ce journal de console. Si nous voulions voir un mouvement, nous devons appeler Render encore et encore. Mettons-le donc dans la boucle d'animation ici. J'appelle Request Animation Frame intégré une méthode qui se trouve sur l'objet de la fenêtre du navigateur, mais nous pouvons également l'appeler directement comme ceci. Si nous le voulons. Je le passe, j'anime le nom de sa fonction mère pour créer une boucle d'animation infinie. Maintenant, je dois appeler animate pour démarrer l'animation. Quand je passe la souris au-dessus de nous, nous voyons des traces. Je voulais juste voir les images d'animation actuelles. Donc, entre chaque boucle, j'utilise la méthode rectangulaire transparente intégrée pour effacer l'ancienne peinture. Je voulais effacer toute la zone de la toile, de coordonnée zéro à la largeur et à la hauteur de la toile. Maintenant, le joueur tape la souris pendant que nous la déplaçons autour du cannabis, parfait. Je voulais créer une ligne entre la souris et le joueur pour indiquer clairement la direction dans laquelle le joueur va se déplacer. Dans la méthode de tirage au sort sur la classe du joueur, nous commençons une nouvelle forme par Colin Begin Bath. La méthode Move to définira les coordonnées x et y de départ de la ligne. Dans ce cas, je voulais que la ligne commence à partir des coordonnées de l'objet du joueur. Méthode de la deuxième ligne, nous allons définir la fin en coordonnées x et y de la ligne. Dans ce cas, il s'agira des coordonnées x et y de la souris. Ensuite, nous appelons trait pour réellement tracer la ligne. Cela fonctionne, mais comme le joueur est toujours capable de rattraper le curseur de la souris si rapidement, nous pouvons à peine voir la ligne. Donnons au joueur vitesse, vitesse X vitesse horizontale. Au départ, je l'ai réglé à zéro. Pourquoi la vitesse verticale l' a également initialement mise à zéro. Dans la méthode de mise à jour, nous allons calculer la vitesse x. Tout d'abord, je l'ai réglée sur un pixel codé en dur par image d'animation. Et j'augmente l' exposition des joueurs en fonction de la vitesse horizontale. Cela a fonctionné. Je le fais aussi pour la position verticale. Il existe deux manières d'obliger le joueur à suivre la souris. Une solution serait simplement de prendre la différence entre la position actuelle de la souris et la position du joueur sur l'axe X horizontal. Et définissez cette différence comme vitesse horizontale. Et nous le faisons également pour les mouvements verticaux. Maintenant, la position du joueur corrige la différence en fonction de la distance totale. Cela rend le mouvement instantané. Et si je le faisais bouger d'un vingt-cinquième de la différence entre la position du joueur et celle de la souris horizontalement d'un vingt-cinquième de la différence entre la position du joueur et celle de la souris pour l'image d'animation. Et aussi verticalement. Je crée une classe de propriétés pour dx, distance entre la souris et le joueur horizontalement et la distance verticale. Je remplace ces valeurs ici. C'est plus facile de le lire de cette façon. Je ne veux pas que le joueur suive tout le temps lorsque nous déplaçons la souris sur Canvas. Je ne le veux que lorsque nous cliquons quelque part ou lorsque nous maintenons le bouton de la souris enfoncé et que nous nous déplaçons. Dans l'écouteur d' événements de déplacement de la souris, je dis de ne mettre à jour que la position x et y de la souris. Si la souris est pressée. Maintenant, je peux cliquer pour déplacer le joueur vers cet endroit, ou je peux faire glisser ce point tout en maintenant la souris enfoncée. Parfait. Le problème de cette technique est que la vitesse n'est pas constante. se déplacent très vite au début, car un 20e de la distance est d' abord un gros morceau lorsqu'ils sont éloignés l'un de l'autre. Mais à mesure qu'ils se rapprochent, un 20e de cette distance diminue et le nombre de pixels à parcourir par image d'animation diminue. Vous souhaiterez peut-être intégrer cette émotion particulière à votre projet, mais pour le jeu que nous sommes en train de créer aujourd'hui, je voulais que le joueur se déplace à une vitesse constante. Nous devrons utiliser la deuxième technique pour cette méthode de mise à jour des informations. J'ai calculé la distance. Nous avons déjà dx, la distance entre la souris et le joueur horizontalement. Nous avons également d, la distance verticale entre la souris et le joueur. Nous voulons calculer la distance entre ces deux points. Nous pouvons le faire en calculant l'hypoténuse, le côté le plus long de ce triangle droit imaginaire. Nous pouvons utiliser la formule du théorème de Pythagore ou, en JavaScript, nous avons cette méthode d' hypoténuse par points mathématiques intégrée. Cette méthode calculera la longueur du côté le plus long pour nous si nous la transmettons aux autres côtés du triangle comme arguments Gardez à l'esprit qu'elle attend d, dy et dx secondes, ce qui peut être un peu inattendu si vous ne l'avez jamais vu auparavant. vitesse horizontale est le rapport entre dx, distance horizontale entre la souris et le joueur et la distance réelle. Vitesse du sandwich. Pourquoi ? Il s'agira du rapport entre la distance sur axe vertical y et la distance réelle entre les deux points. titre de sauvegarde, lorsque certaines de ces valeurs ne sont pas définies au début, nous disons ou zéro. Ainsi, nous sommes divisés en distance horizontale et verticale, ces côtés par la distance réelle représentée par le côté le plus long d'un triangle droit. Dx et DY sont toujours un nombre inférieur la distance car la distance correspond à l' hypoténuse, le côté le plus long. Pour cette raison, les valeurs que nous obtenons pour vitesse x et la vitesse y seront comprises entre 0 et 1. Cela nous donnera la bonne direction de mouvement à une vitesse constante. Il y a encore beaucoup à dire sur cette technique. Mais pour l'instant, c'est tout ce que nous avons besoin de savoir. Je vais y revenir. Maintenant. Le joueur se déplace à vitesse constante vers la souris. Je peux avoir un modificateur de vitesse. Je l'ai réglé sur cinq, par exemple je l'utilise ici et je multiplie la vitesse x et la vitesse. Pourquoi, avec ce modificateur, après avoir ajouté le modificateur de vitesse, le cercle des joueurs ne restera plus immobile. Il oscillera d'avant en arrière, dans ce cas de 50 pixels, car le modificateur de vitesse le pousse trop loin dans les deux sens. Je peux y remédier en disant ne déplacer le joueur que lorsque la distance entre souris et le joueur est supérieure au modificateur de vitesse. Sinon, la vitesse x était à zéro et la vitesse y à zéro également. Cela fonctionne parfaitement. Nous avons donc abordé une technique simple et une technique plus avancée pour amener le joueur à se déplacer vers la souris. Il est maintenant temps d'ajouter des obstacles solides, aléatoires et qui ne se chevauchent pas. 7. Créer des obstacles: Je crée une classe que j'appelle obstacle. constructeur s'attend à ce que le jeu soit un argument. Et à l'intérieur, j'ai converti cette référence propriété de classe, comme avant. Il pointera vers l'objet principal du jeu. Et nous en avions besoin, car grâce à cette référence, nous avons accès à la largeur et à la hauteur du jeu, la position de la souris et à d' autres propriétés. Nous serons ajoutés ultérieurement. Nous aurons accès à toutes ces valeurs depuis classe d'obstacles via cette référence .name à partir de la ligne 54. Comme je l'ai déjà expliqué, les objets de notre jeu se composeront d'une boîte circulaire chauffée en cas de collision et d'une feuille de calcul rectangulaire séparée. C'est pourquoi j'appellerai ces propriétés avec des noms très descriptifs afin de m' assurer que ce qui se passe lorsque nous déplacerons et animerons tout sera très clair ultérieurement. Collision x, le point central du cercle de collision de chaque obstacle, sera une valeur aléatoire comprise entre zéro et la largeur du jeu. Cette largeur provient de la ligne 62 ici. Et nous y accédons via cette référence de jeu de points que nous avons créée à la ligne 54. Nous aurons également besoin d'une collision. Pourquoi le point central vertical de la collision est un cercle. Ce sera une valeur aléatoire comprise entre zéro et la hauteur du jeu. Cette valeur de rayon de collision sera de 60. Nous devrons également dessiner une méthode qui attend les contextes comme argument. Je veux que le cercle qui représente la zone de frappe de chaque obstacle ressemble au cercle représentant le joueur. Je prends donc le code de dessin d'ici, juste pour le cercle. Donc ce bloc de code, je le copie et je le colle ici. Ce code fonctionnera ici car, comme pour le joueur à qui nous avons attribué la propriété d'obstacles, s' appelle collision x, collision et rayon de collision. Nous aurons également besoin du même nom toutes ces propriétés entre les différents types d'objets. Au cas où nous souhaiterions disposer d'une fonction de détection de collision réutilisable. Je vous montrerai comment l'utiliser plus tard. C'est simple. Quoi qu'il en soit, nous avons ici un code pour dessiner un cercle d'un rayon de 60 pixels avec une opacité de 50 %, un fond blanc et un trait blanc, entièrement visible et opacité totale. Cette classe d' obstacles est un plan. Nous l'utiliserons pour créer des objets d'obstacles individuels. La véritable logique pour créer et gérer ces objets se trouvera ici dans la classe de jeu principale, qui est le cerveau principal de notre base de code. Je crée une propriété appelée ce point obstacles. Ce sera un tableau contenant tous les objets d' obstacles actuellement actifs. Au début, il s'agira d'un tableau vide, le nombre d'obstacles sera par exemple de cinq. Je crée une méthode personnalisée pour notre classe de jeu, que j'appelle par exemple dans IT. Pour l'instant, son travail consistera à créer cinq objets d'obstacles aléatoires et à les placer dans le tableau d'obstacles que nous venons de définir. À l'intérieur, je crée une boucle en forme de « for ». Elle sera exécutée cinq fois parce que nous avons indiqué le nombre d'obstacles à cinq sur la ligne 76. Chaque fois qu'il s'exécute, il prend ce tableau d'obstacles à points de la ligne 77 et, sur celui-ci, il appelle la méthode push intégrée du tableau à méthode push sous la forme d'un ou de plusieurs éléments jusqu' à la fin d'un tableau, et il renvoie la nouvelle longueur du tableau. Je vais lui passer un nouvel obstacle comme celui-ci. Le nouveau mot clé recherchera une classe portant le nom obstacle, et il déclenchera son constructeur de classe en ligne 53 Je peux voir que le constructeur de classe d'obstacles attend le jeu comme argument. Ici, la méthode init se trouve dans cette classe de jeu, donc je lui transmets le mot clé, ce qui représente ici l'ensemble de l'objet du jeu avec toutes ses propriétés et les méthodes associées, les rendant toutes disponibles depuis la classe d'obstacles. Maintenant, je joue sur console et je peux voir que le tableau d'obstacles est complètement vide. Pour le remplir, tout ce que j'ai à faire est d'appeler la méthode init. Nous venons d'écrire comme ça. Maintenant, je peux voir que le tableau contient cinq objets obstacles. Je vérifie que toutes les propriétés ont des valeurs. Si vous voyez undefined dans l'un d'entre eux, cela signifie qu'il y a un problème dans votre base de code. Tout va bien ici. Tout comme je suis en train de dessiner une mise à jour et que le joueur utilise la méthode de rendu du jeu, j'aimerais dessiner les cinq obstacles sur Canvas. Je prends un éventail d'obstacles de -77. Nous savons déjà qu'il contient cinq objets et que chacun de ces objets a été créé à l'aide notre classe d'obstacles personnalisée de I'm 52. Ils ont tous accès à cette méthode de dessin que nous avons définie à la ligne 59. Donc, ici, dans le rendu, je prends ce tableau d'obstacles, j'appelle un tableau intégré pour chaque méthode, la méthode forEach exécute une fonction fournie une fois pour chaque élément du tableau. abord, nous devons définir un nom de variable qui sera utilisé dans cette méthode forEach pour faire référence à des objets individuels dans ce tableau. Je vais appeler chaque objet obstacle. Donc, pour chaque objet d'obstacle d'un tableau d'obstacles, j'appelle leur méthode de dessin associée à partir de 1959 en ligne 59, je peux voir qu'elle attend une référence au contexte comme argument pour spécifier type d'élément Us sur lequel nous voulons dessiner. Je transmets simplement ce contexte qui a été transmis à la méthode de rendu parent. Agréable. Nous dessinons un joueur et 12345 obstacles positionnés aléatoirement. Je monte ici et j'agrandis un peu les obstacles. Chaque fois que j'actualise la fenêtre du navigateur, ils sont positionnés de manière aléatoire quelque part dans la zone du canevas car c'est ainsi que nous définissons leur position sur les lignes 55.56. Et si je voulais m'assurer que les obstacles ne se chevauchent jamais comme ça et peut-être aller encore plus loin, car ce seront des obstacles solides que le joueur ne pourra pas franchir et devra les contourner. J'aimerais également qu'il y ait un espacement minimum entre eux et également entre les bords de la zone de jeu. Juste pour s'assurer que toutes les créatures qui vont bientôt ramper ici ne restent pas coincées et puissent éventuellement contourner automatiquement chaque obstacle. Il est en fait plus facile de mettre en œuvre tout cela, que vous ne le pensez peut-être, mais nous devons y aller étape par étape et expliquer quelques astuces que nous pouvons utiliser ici pour y parvenir. 8. obstacles non chevauchants: Dans la méthode init, nous ajoutons simplement cinq obstacles positionnés au hasard. Hein ? Maintenant. Je dois le supprimer. Nous aurons besoin que cette structure soit appelée un peu différemment ici. Je voulais donc d'abord m'assurer que les obstacles ne se touchent pas, qu'ils ne se chevauchent pas comme ça. Nous pouvons également ajuster le nombre d' obstacles pour qu'il soit possible de placer le nombre maximum de cercles dans une zone donnée sans que deux d'entre eux ne se chevauchent. ce que nous appelons parfois l'emballage circulaire. Réécrivons donc un cercle très simple dans l'algorithme ici. Je vais utiliser la technique de base qui consiste à essayer plusieurs fois de jouer des cercles à des positions aléatoires. Et seuls ceux qui n'entrent pas en collision avec des cercles déjà existants seront réellement transformés en objets d'obstacles et dessinés. C'est ce qu'on appelle également un algorithme de force brute. Ce n'est pas très intelligent, il essaie encore et encore de nombreuses fois. Je vais créer une variable principale appelée tentatives. Ce sera ma mesure de sécurité. Nous compterons le nombre de fois où nous avons essayé de tracer un cercle et nous abandonnerons après un certain nombre de tentatives. L'hypothèse étant qu' il devait déjà y avoir suffisamment d'opportunités pour placer les obstacles. Je vais utiliser une boucle pendant un certain temps. Tu dois être prudent avec celui-ci. Si vous créez une boucle de temps infinie, vous ralentirez votre navigateur et vous devrez le redémarrer. très vieux ordinateurs peuvent même se bloquer si vous utilisez While Loop Rome, les nouveaux navigateurs peuvent généralement y faire face. Mon objectif ici est de placer des cercles au hasard encore et encore. Et avant de transformer ce cercle en objet obstacle, nous vérifions s'il chevauche des cercles d'existence. Si cela ne se chevauche pas, nous l'avons ajouté au tableau des obstacles. Je veux que cette boucle continue de fonctionner tant que la longueur du réseau d'obstacles est inférieure à, nombre d'obstacles, inférieure à cinq. Nous avons défini ce tableau ici, et le nombre d'obstacles a été défini ici. En guise de sauvegarde, j'ai également défini une condition secondaire ne continuer à l'exécuter que pendant la boucle tant que le nombre de tentatives est inférieur à 500. C'est important car si je disais rayon d'un obstacle est très grand, ou si je fixe un nombre d'obstacles si grand qu' ils ne peuvent pas rentrer physiquement dans la zone disponible, nous obtiendrions une boucle infinie. Mais lorsque la condition secondaire est JavaScript, nous allons juste essayer 500 fois. Et si, à ce moment-là, ils n'arrivaient pas à trouver un emplacement pour surmonter tous les obstacles, il abandonnerait. Je pense que 500 tentatives sont plus que suffisantes. Chaque fois que la boucle fonctionne, nous devons augmenter le nombre de tentatives d'une unité pour que notre plan de sécurité fonctionne. Chaque fois que cette boucle s'exécute, nous créons un objet temporaire que j'appelle, par exemple obstacle de test. Il sera à la hauteur du nouvel obstacle et je lui passe un jeu, ce mot clé comme argument, comme nous le faisions auparavant. Configurons cet obstacle de test dans la console. Agréable. Nous avons 500 obstacles de test sur console. Vous pouvez maintenant voir qu'ils ont les propriétés de collision, collision y et de rayon de collision de collision y et de rayon de collision comme il se doit. Mon objectif est maintenant de prendre cet objet d'essai temporaire et le comparer tous les autres obstacles du tableau d'obstacles. Bien sûr, au début, ce tableau est vide, donc le premier obstacle doit toujours être placé sans problème. Le deuxième obstacle de test se comparera au premier déjà présent dans la matrice, et ainsi de suite. Donc, pour chaque obstacle, réseau d' obstacles, je vais utiliser une formule de détection des collisions circulaires. La détection des collisions circulaires en JavaScript est assez simple. Nous devons essentiellement calculer la distance entre les deux points centraux de ces deux cercles. Ensuite, nous comparons la distance entre deux points centraux à la somme des rayons. Si la distance est inférieure au rayon 1 plus le rayon du cercle, ils se chevauchent. Si c'est exactement pareil, les cercles se touchent. La distance est supérieure à la somme des rayons. n'y a pas de collision. Nous l'avons déjà fait en mesurant la distance entre le joueur et la souris. Cette fois, les deux points que nous voulons mesurer la distance entre eux sont le point central du premier cercle d'obstacles. Et le point central des obstacles est également circulaire. Encore une fois, nous créons ce triangle droit imaginaire où dx est la différence entre deux points horizontalement. D est la différence entre les deux points verticalement. Et la distance réelle est l'hypoténuse de ce triangle. Nous utilisons donc ici la formule du théorème de Pythagore ou une méthode mathématique intégrée d' hypoténuse par points, en lui passant un DY d'abord et un second. Nous savons maintenant quelle est la distance entre les deux points centraux. somme au-dessus de l'ADI est le rayon du cercle 1, dans ce cas, le rayon de l'obstacle d'essai. Et le second est le rayon de n' importe quel objet obstacle à l'intérieur d' un réseau d'obstacles, sur lequel nous sommes actuellement en train de parcourir un cycle. Comme nous l'avons dit, si la distance est inférieure à la somme des rayons, comment dois-je procéder ? En dehors de la méthode pour chaque méthode, je crée une variable de longueur d'indicateur que j'appelle chevauchement, et je la définis initialement sur false. La distance est inférieure à la somme des rayons. Nous avons défini le chevauchement comme vrai car une collision a été détectée en dehors de la pour chaque méthode. Si le chevauchement est toujours faux après avoir créé un obstacle de bureau et après l'avoir comparé à l'aide de la formule de détection des collisions avec tous les autres obstacles existants de la matrice. S'il n'entre en collision avec aucun d'entre eux. Et la variable de chevauchement est toujours fausse. Après toutes ces vérifications, nous prenons un réseau d'obstacles et nous insérerons cet obstacle de test qui a réussi nos contrôles dans le tableau. Maintenant, lorsque je rafraîchis le jeu, cinq obstacles seront positionnés au hasard et ils ne se chevaucheront pas, car ceux qui se chevauchent sont supprimés. Et seuls les cercles qui ne se chevauchent pas sont utilisés. Comme j'ai ma mesure de sécurité sur la ligne 10008, et que nous arrêtons toujours cela en boucle lorsque nous atteignons 500 tentatives, je peux monter ici et régler le nombre d' obstacles à un nombre élevé qui je le sais, ne correspondra jamais à notre code. Nous allons simplement placer autant d'obstacles que possible, puis il cessera d'essayer. Nous savons que cela fonctionne, car si je continue à actualiser mon projet encore et encore, nous ne verrons jamais de cercles qui se chevauchent. Je veux dire, aucun obstacle ne se chevauche. À ce stade, le joueur peut se chevaucher avec des obstacles. Ça ne nous intéresse pas pour le moment. J'ai parlé d'un certain nombre d' obstacles à dix. 9. Images randomisées à partir d'une feuille de sprite: Permettez-moi maintenant de vous montrer comment nous allons attacher des images aux cases de collision circulaire et comment positionner l'image par rapport à la boîte principale de manière à ce qu'elle ait sens visuel et crée illusion qu'il ne s' agit pas d' une toile plate, mais d'un environnement tridimensionnel dans lequel le joueur peut réellement contourner ces obstacles. Vous pouvez télécharger tous les projets forme d'actifs dans la section des ressources ci-dessous. Dans index.HTML, je crée un autre élément d' image avec un identifiant d'obstacles et la source sera obstacles point PNG. Cette image est une feuille de sprites. Nous allons sortir aléatoirement l'un de ces cadres pour chaque objet d' obstacle. Je ne veux pas vraiment dessiner l'élément d'image réel, donc je le cache avec du CSS dans le constructeur de classe d' obstacles, je crée une nouvelle propriété, j'appelle cette image à points. J'ai pointé du doigt cette feuille de calcul d' obstacles utilisant get element by ID comme celle-ci. Fixons le nombre d' obstacles à un pour le moment. Dans la méthode de dessin sur la classe d'obstacles, j'appelle la méthode intégrée de dessin d'image sur toile. Cette méthode nécessite au moins trois arguments, l'image que nous voulons dessiner. Alors, cette image ponctuelle de la ligne 58 et des coordonnées x et y, où la dessiner ? Je vais le dessiner lors cette collision de points x et de cette collision de points. Pourquoi ? commencer, nous allons simplement dessiner la feuille de sprite complète de l'image. Et le coin supérieur gauche de cette feuille de calcul partira point central du cercle d'obstacles, car c'est ainsi que, par défaut, images et les cercles sont dessinés sur le canevas HTML. Si j'actualise le projet ou un nouvel obstacle est positionné de manière aléatoire quelque part sur Canvas, j'ai créé cette feuille de calcul pour vous. Je sais donc que les cadres individuels ont une largeur de 250 pixels. J'enregistre cette valeur en tant que sprite avec une hauteur de sprite variable qui sera également de 250 pixels. Si vous utilisez une autre feuille de calcul, vous pouvez obtenir la largeur en divisant la largeur de la feuille de calcul entière par le nombre de colonnes. Et la hauteur est la hauteur de la feuille de sprite divisée par le nombre de lignes au cas où nous voudrions ajouter une échelle. Et plus tard, je créerai également des propriétés indépendantes de largeur et de hauteur. Pour l'instant, la largeur et la hauteur du sprite seront égales, car j'ai dimensionné les cadres de sprite exactement à la même taille que celle que je souhaite qu' largeur et la hauteur du sprite seront égales, car j'ai dimensionné les cadres de sprite exactement à la même taille que celle que je ils soient dessinés dans le jeu. Draw image peut également accepter les quatrième et cinquième arguments facultatifs définis dans la largeur et la hauteur. L'image entière sera compressée ou étirée jusqu'à la zone que nous avons définie par ces valeurs. Cela ressemblera à ceci. Ce que je veux vraiment faire, c'est recadrer l'un de ces 12 obstacles et ne dessiner que celui-ci à la taille de 250 fois 250 pixels. Pour cela, je dois utiliser la version la plus longue de la méthode draw image qui attend neuf arguments. Ces neuf arguments sont l'image que nous voulions dessiner, la source x, y, source avec la hauteur de la zone que nous voulons recadrer à partir de l'image source. Et destination x, destination. Pourquoi la destination avec et hauteur de la destination pour définir où se trouve la destination sur laquelle je veux placer cette image recadrée. Donc, si je lui passe un zéro comme source x et zéro comme hauteur de la source. Sprite avec une hauteur de sprite comme celle-ci comme largeur et hauteur de la source, je dois l'épeler correctement. Nous dessinons maintenant le cadre supérieur gauche de notre feuille de calcul. Comme je l'ai déjà dit, je vais définir des positions x et y distinctes pour la feuille de calcul. Il existe différentes manières de procéder. Je peux simplement positionner l'image directement au-dessus de la collision x, qui est le point central du cercle de collision, moins la largeur de l'image multipliée par 0,5. Cela centrera l'image horizontalement exactement au-dessus du cercle de collision. Pour réellement appliquer cela, je dois utiliser le sprite X comme propriété x de destination transmise à la méthode draw image ici, soyez prudent lorsque vous passez des arguments à la méthode draw image. L'ordre dans lequel vous transmettez ces arguments est très important. D'accord, si je rafraîchis la page, je peux voir qu'elle est correctement centrée horizontalement. Je fais la même chose pour Sprite y, et je l'utilise comme destination. Pourquoi la propriété a été transmise à la méthode Draw Image. La feuille de calcul se trouve maintenant directement au-dessus du cercle de collision. J'ai dit rayon de collision à une valeur plus petite. Je veux que cette petite zone de collision soit positionnée à la base de la plante où se trouve la pierre. Parce que ce sera la zone solide qui touchera le sol dans laquelle les personnages du jeu devront se déplacer. Comme nos sprites ont défini une taille de 250 fois 250 pixels, je peux en fait utiliser une valeur codée en dur ici. Plus 40 le déplaceront vers le haut. -40, -50, -60, -70. Oui, cela semble correct. J'ai dit que le nombre d'obstacles était de dix. 10. Règles de positionnement: Et si je voulais m'assurer que non seulement les obstacles ne se chevauchent pas, mais aussi qu'il y ait un espace supplémentaire d'au moins 100 pixels entre les deux. Ils sont donc répartis de manière plus uniforme autour de la zone de jeu disponible, tout en laissant suffisamment d'espace entre les obstacles. Les personnages du jeu peuvent facilement les contourner. Je crée une variable d'assistance que j'appelle, par exemple , distance buffer, et je la règle à 100 pixels comme ceci. Ensuite, j'ai inclus un tampon de distance ici dans certains rayons pour appliquer ce tampon entre les obstacles lorsque nous les plaçons. Agréable. Pour m'assurer que cela fonctionne, j'augmente la distance tampon de 250 pixels. Cela devrait le rendre encore plus évident. Oui, c'est ainsi que nous pouvons facilement contrôler l'espacement des obstacles. Je tiens également à m' assurer que les images de sprites d'obstacles sont entièrement dessinées dans la zone de jeu et qu'elles ne sont pas partiellement cachées derrière les bords. J'aurais pu utiliser ce constructeur de classe d' obstacles Insight lors de la définition initiale de ces valeurs. Ou je peux aussi le faire ici, étant donné que nous ne dessinons pas autant d'obstacles et que leurs positions ne sont calculées qu' une seule fois lors du chargement de la première page. De toute façon, je m'assure que le bord gauche de la feuille de calcul des obstacles est supérieur à zéro, afin qu'elle ne soit pas cachée derrière le bord gauche de Canvas. En même temps, je m' assure que le bord droit n'est pas masqué. sprite X doit donc être inférieur à la largeur de la zone de jeu moins la largeur de l'obstacle. Agréable. Lorsque je rafraîchis la page, je peux voir horizontalement, les obstacles sont toujours parfaitement visibles. Pour la position verticale, je veux vérifier si l'image, le point central du cercle de collision situé à plus zéro à la verticale, ne suffira pas. Je souhaite définir une zone réservée à cette illustration d' arrière-plan. Je ne veux pas que des obstacles apparaissent au-dessus de cette zone. Je crée une propriété appelée marge supérieure. Je suppose que cette zone supérieure mesure environ 260 pixels de hauteur. Vérifions-le ici. Oui, la version 2.6D semble correcte, parce que je voulais m' assurer que la base des obstacles ne chevauche pas cette zone supérieure, mais cela ne me dérange pas que le haut des feuilles de calcul des obstacles se chevauche de cette manière, car cela donne l'impression que la plante d'obstacles se trouve devant l' arrière-plan pour que nous puissions la voir. Donc c'est très bien. Je vais également vérifier si le point central du cercle de la zone de collusion d' obstacles est inférieur à la hauteur de la zone de jeu. Je veux des marges. Je peux par exemple créer une variable d'assistance égale au rayon de collision de l'obstacle d' essai multiplié par deux. Je remplace cette valeur codée en dur par cette propriété de marge supérieure en pointillés que nous avons définie. De plus, je veux lui donner une marge supérieure supplémentaire afin que les personnages, et en particulier les ennemis, puissent se faufiler entre les obstacles et franchir des limites. Traverser le terrain de jeu horizontalement de droite à gauche. Je vais également tenir compte de la marge depuis le bas de la zone de jeu pour y créer de l'espace. Nous avons écrit un code qui place automatiquement des obstacles dans notre monde de jeu. Ces obstacles ne se chevauchent jamais et leurs zones de corrélation sont placées de manière à laisser suffisamment d'espace entre eux. Cela facilitera grandement la prochaine étape car nous avons besoin d'ennemis et de PNJ amis pour pouvoir les contourner automatiquement à l'aide d'une intelligence artificielle très simple. Nous avons différentes images pour les obstacles, mais pour le moment, nous ne dessinons que le premier cadre en haut à gauche à la coordonnée zéro-zéro. Nous pouvons recadrer différentes zones à partir de la feuille de calcul des obstacles, de la zone de recadrage horizontale. Nous allons partir de la position que nous transmettons comme argument source x pour dessiner une image ici, zéro fois le sprite avec ce cadre. Un. La largeur du sprite sera celle de ce cadre. Deux, c'est 13, c'est celui-ci. Retour à zéro. Pour sélectionner la ligne à partir de laquelle nous allons recadrer, nous utilisons la source Why argument here ? Encore une fois, nous multiplions le nombre de règles par la hauteur réelle des cadres lumineux des individus, zéro fois la hauteur du sprite est ce terme hauteur du sprite est celui-ci. Maintenant, nous en déroulons deux et il n'y a pas de ligne trois car nous partons de la ligne zéro. Les images sont dessinées et recadrées par le haut. Donc, au lieu de coder en dur ces valeurs qui sont actuellement définies sur 00, transformons-les en propriétés de classe pour plus de clarté. Et c'est un contrôle. Ce cadre d'affichage x déterminera quelle colonne nous nous trouvons dans notre feuille de calcul des obstacles. Si je fais un nombre aléatoire de 0 à 4, cela ne fonctionnera pas. n'y a pas de colonne 1.74, par exemple nous avons besoin d'entiers, de nombres sans décimales. Je l'enveloppe donc dans Math.floor pour arrondir la valeur aléatoire générée par Math.random à l'entier inférieur le plus proche. Ce code me donnera zéro ou un, ou deux ou trois. Ainsi, l'une de nos colonnes de sprites, lorsque nous multiplions ces entiers par la largeur d'un seul cadre de sprite et que nous transmettons cette valeur comme argument source à la méthode de dessin de l'image, nous définissons une coordonnée de recadrage horizontale. Cela a parfaitement fonctionné. Je ferai de même pour le cadre y, qui déterminera la ligne des sprites. Nous n'avons que trois rôles. Cette ligne de code me donnera des entiers, soit zéro, soit un ou deux correspondant au nombre de lignes disponibles dans notre feuille de calcul des obstacles. Nous pouvons maintenant remplacer ce zéro codé en dur par ce cadre de points y. Donc, l'argument source Pourquoi mais invité à dessiner une image sera ce cadre de points y fois cette hauteur de sprite. Je vais le faire dans une seconde. Les valeurs aléatoires dans l'image x et l'image pourquoi combinées nous donneront une image aléatoire parmi ces 12 obstacles disponibles sera attribuée à chaque objet d'obstacle image aléatoire de cette feuille de calcul lui sera attribuée à chaque objet d'obstacle. J'en finirai un peu plus tard. 11. Physique: Sur l'objet du faisceau principal, je crée une méthode que j' appelle vérifier la collision. Je veux que ce soit une méthode utilitaire réutilisable qui prend l'objet a et l'objet B et qui les comparera et vérifiera s'ils entrent en collision ou non. Nous pourrons l'utiliser dans toute la base de code chaque fois que la détection de collision entre deux cercles est nécessaire. Dans la façon dont je construis mon jeu, tous les personnages et objets auront une zone de collision circulaire, qui constituera une base solide que rien ne pourra traverser et où tout réagira et contournera tout. Grâce à cela, nous pouvons également faire bouger les choses. Je vais vous montrer comment vérifier la collision entre deux cercles. Nous avons le cercle a et le cercle B. Ici. Nous devons d'abord vérifier dx, la distance entre le point central du cercle a et le point central du cercle B sur l'axe horizontal des abscisses. Ces méthodes réutilisables ne fonctionneront que si tous les objets concernés possèdent des propriétés ayant la même convention de dénomination. Nous allons donc nous assurer d'avoir nommé les positions x et y chaque objet comme collision x et pourquoi ? J'utilise ces noms de propriétés trop descriptifs pour qu'il soit très clair quand les coordonnées x et y sont liées au cercle de la zone de collision et quand elles se rapportent à la position de la feuille de sprite de l'image. Il s'agit d'un tutoriel, donc je veux que les choses soient très claires et faciles à comprendre. Nous aurons également besoin d'un D, pourquoi la différence entre le point central du cercle a et le centre du cercle B sur l'axe vertical y. Ensuite, nous voulons connaître la distance entre ces deux points centraux. Donc, l'hypoténuse, le côté le plus long de ce triangle droit imaginaire, à angle droit de 90 degrés, est là. Et c'est la distance b Dagger a une formule théorique ou bien des mathématiques intégrées seraient une méthode d'hypoténuse. Et nous lui transmettons le Dui d'abord et le x comme deuxième argument. Pour déterminer s'il y a eu collision ou non, nous comparons la distance entre ces deux points centraux avec le rayon du cercle a plus le rayon du cercle B Je vais enregistrer cette valeur en tant que variable personnalisée, j'appelle par exemple certains rayons. Donc, si la distance est inférieure à la somme des rayons, nous savons que le cirque entre en collision. Si la distance est égale à la somme sur l'ADI, les cercles se touchent. Si la distance est supérieure à la somme des rayons, nous savons qu'il n'y a pas de collision. Cette fonction renvoie simplement la valeur true en cas collision et la valeur false s' il n'y a pas de collision. Utilisons notre fonction de vérification personnalisée des collisions. Ici, dans la méthode de mise à jour de la classe du joueur, nous vérifions s'il y a une collision entre le joueur et les obstacles. Nous avons un objet pour un joueur et plusieurs objets obstacles. Donc, pour tout comparer, nous allons faire appel à un réseau d'obstacles, qui contient tous les objets d'obstacles actuellement actifs. J'appellerai chaque objet du tableau avec un nom de variable auxiliaire, un obstacle et la méthode de collision par obstacle et vérification du journal de la console que nous venons de définir. Nous savons qu'il s'attend à ce que l' objet circulaire a et l'objet B soient des arguments pour comparer la distance leurs points centraux à la somme des rayons. Je passe donc ceci, ce qui signifie que cet objet joueur, cercle et l'obstacle que nous sommes en train parcourir à vélo avec cette méthode ForEach sous forme de cercle B. Gardez à l'esprit que cette méthode réutilisable de vérification et de collision ne peut comparer que des objets dont la propriété de collision x, de collision et de rayon est définie dans leur constructeur de classe. Je vais donc m'assurer de conserver les mêmes conventions de dénomination pour tous les objets du jeu que nous construisons aujourd'hui. Au fur et à mesure que le joueur se déplace, nous devenons faux et vrais sur la console. On dirait que cela fonctionne. En fait, n' enregistrons le mot collision sur console que lorsqu'une collision entre un joueur et un obstacle se produit. Maintenant, il est encore plus facile de voir que notre code fonctionne. Parfait. 12. Méthode de détection de collision: Dans la méthode de rendu, je vais d'abord dessiner les obstacles, donc derrière et le joueur après, pour qu'ils soient dessinés au-dessus. Et si je voulais également résoudre nos collisions ? Ce que je veux dire, c'est que s'ils entrent en collision avec un obstacle, je ne veux pas qu'il puisse le franchir comme ça. Je veux que le cercle du joueur soit repoussé un pixel par au cercle d'obstacles dans la direction qui pointe directement vers le centre de l'obstacle. C'est simple, nous allons rendre les obstacles solides. Le joueur va réellement contourner les obstacles et cela créera une belle physique. Laisse-moi te montrer. J'ai déjà calculé tout ce dont j'ai besoin pour obtenir ces informations, notre méthode de vérification par collision personnalisée, mais cette fonction ne renvoie actuellement que vrai ou faux. J'ai besoin de cette méthode réutilisable pour renvoyer plus de valeurs afin que nous puissions les utiliser dans la classe du joueur pour calculer la résolution de collision des fonctions vectorielles . Les méthodes en JavaScript peuvent renvoyer une valeur comme celle-ci, mais elles peuvent également renvoyer un tableau contenant plusieurs valeurs. Je souhaite renvoyer l'état de collision vrai ou faux en tant que premier élément du tableau avec un indice de zéro. Nous voulons également renvoyer la distance nous calculons à la ligne 127. Nous aurons également besoin de certains rayons de la ligne 128. Et nous aurons besoin de DX et DY à partir des lignes 100.2526. présent, notre méthode de vérification personnalisée des collisions permet non seulement de vérifier si une collision se produit ou non, mais elle nous donne également d'autres valeurs à partir de calculs effectués en cours de route. Il est important de mémoriser l'ordre dans lequel ces valeurs nous sont renvoyées. L'élément dont l'indice est zéro est-il vrai ou faux ? L'élément dont l'indice est égal à un est la distance. Certains rayons sont indexés sur. Dx est l'indice trois et d y est indexé pour. Je vais simplement copier ce tableau qui est renvoyé ici. Et j'ai commenté juste pour que je puisse le voir comme une référence utile. Maintenant, je veux prendre chacune de ces valeurs et les enregistrer sous forme de variables distinctes afin que nous puissions les utiliser pour calculer résolution des collisions et pousser deux joueurs dans la bonne direction, loin de l' obstacle auquel il se heurte actuellement et de sa largeur Je vais utiliser ce que l'on appelle une assignation de restructuration. Écrivons-le et je l' expliquerai quand nous aurons tout vu. Je dis que let variable est ce tableau. Et cela revient à vérifier la collision entre cet objet du joueur et l'obstacle qui, pour chaque méthode, est en train de franchir. Je dois remplacer cette première expression un nom de variable. Je voulais appeler ça, je veux appeler ça une collision. Ce sera cette valeur vraie ou fausse en fonction de la distance entre le point central du cercle. Donc, si c'est vrai, il y a collision. Si c'est faux, il n'y a pas de collision. Cette structure et cette syntaxe d' affectation sont une expression JavaScript qui permet de décompresser des valeurs provenant de tableaux ou propriétés d'objets dans des variables distinctes. En gros, ici, créez cinq variables pour moi. La première variable appelée collision est le tableau renvoyé lorsque nous appelons la méthode check collision entre ce joueur et l'indice d' obstacle zéro. La variable de distance est l'indice 1 du tableau, et ainsi de suite. Cette structure et cette mission le font automatiquement en arrière-plan. Il crée ces cinq variables et les associe. Les valeurs situées à ces index dans le tableau sont renvoyées par la méthode check collision. Cela peut être un peu étrange si vous ne l'avez jamais vu avant JavaScript, cette structuration est une bonne chose pour vous familiariser. Les frameworks modernes les utilisent beaucoup et se contentent de prendre le tableau renvoyé par la méthode check collision. Et j'attribue chaque valeur à ses noms de variables distincts afin de pouvoir les utiliser ici. Nous voici donc dans la méthode de mise à jour de la classe du joueur. Nous parcourons à vélo un ensemble d' obstacles en comparant le joueur à chaque objet d'obstacle. S'il y a collision entre le joueur et l'obstacle, si la variable de collision est vraie, la console enregistre AAA. Cela fonctionne. Je voulais créer un vecteur, une sorte de petite ligne, à 1 pixel de long. Cette ligne indiquera la direction dans laquelle le joueur doit être poussé pour résoudre la collision circulaire, afin de s'assurer que la collision entre le joueur et obstacle se repoussent, faisant glisser le joueur le long du rayon de l'obstacle au lieu de le traverser directement. vecteur horizontal sera le rapport entre Dx, distance entre le joueur et le point central de l' obstacle sur l'axe X horizontal, et la distance réelle entre ces deux points que nous avons calculée avant d'utiliser la méthode check collision. Parce que dx sera toujours inférieur à la distance, parce que la distance est l'hypoténuse est toujours le côté le plus long du triangle droit imaginaire. L'unité x aura toujours une valeur de 0 à 1, car nous divisons une valeur plus petite par une valeur plus grande. L'unité y sera le rapport entre Dui, la distance entre les points centraux sur l'axe vertical et la distance réelle entre les deux points centraux. Encore une fois, ce sera une valeur comprise entre 0 et 1. Il peut également s'agir de valeurs négatives en fonction de la position de nos objets les uns par rapport aux autres sur les axes horizontal et vertical. Donc, en fait, les unités x et y auront une valeur comprise entre moins un et plus un. Si je console les unités x et unité, pourquoi nous pouvons voir ces valeurs La combinaison de ces deux valeurs ajoutées à la position horizontale et verticale du joueur position horizontale et verticale pour chaque image d'animation la fera se déplacer dans une certaine direction et certaine vitesse par rapport au point central de l'obstacle. Pour ce faire, je prends l'exposition aux collisions du joueur, le point central du cercle de collision du joueur, pour la pousser hors du rayon de l'obstacle avec lequel il entre en collision. Je le déplace horizontalement jusqu'à la position du point central du cercle d'obstacles, plus la somme des rayons du cercle du joueur et du cercle d'obstacles, plus un pixel supplémentaire en dehors des termes, ce ratio unitaire x qui lui donne la bonne direction en s' éloignant du point central de l'obstacle. Nous faisons la même chose verticalement. point central du cercle de collision du joueur sera déplacé à la position du centre de collision du cercle d'obstacles plus la somme des rayons de l'obstacle et du cercle du joueur plus un pixel (unité Y) pour lui donner la bonne direction de poussée. J'essaie d'expliquer cela d'une manière très conviviale pour les débutants, mais ne vous inquiétez pas si ce n'est toujours pas clair. C'est une technique importante et chaque fois que vous l'utiliserez, vous vous familiariserez de plus en plus avec ce manteau. Finalement, il cliquera pour vous expliquer comment cela fonctionne. Tout ce que vous devez comprendre ici, c'est que ce code pousse le joueur d'un pixel en dehors du rayon de collision de l'obstacle dans la direction opposée au point central. Et c'est ainsi que vous créez une très simple mais très efficace simulation physique très simple mais très efficace dans votre jeu. Essayez de déplacer le joueur. Ça fait du bien, n'est-ce pas ? Soudain, nos cercles d'obstacles se sont transformés en objets solides et impossibles. Bravo si vous avez suivi jusqu'au bout, c'est la principale astuce que nous utilisons aujourd'hui pour notre jeu de physique. J'ajuste le modificateur de vitesse à une valeur plus petite. Nous avons appris à faire en sorte que le joueur se déplace vers une souris ou vers un point précis dans un espace 2D, et comment le faire contourner automatiquement des obstacles solides. C'est une technique puissante et vous pouvez en faire plus que vous ne pouvez l'imaginer. Nous allons explorer certaines de ces questions aujourd'hui. J'espère que tu t'amuses bien. 13. animation de sprite directionnelle: J'ai préparé une feuille de sprite directionnelle spéciale pour les joueurs pour ce cours. Vous pouvez le télécharger dans la section des ressources ci-dessous. Je vais inclure quelques couleurs alternatives. Le mien est probablement trop bleu pour les champignons dans mon jeu. Je vais le cacher avec du CSS ici. Constructeur de classe Inside Player. Je crée une référence à cette image en utilisant get element by ID, et je l'enregistre en tant que propriété d'image à points. Dans notre méthode de dessin personnalisée, je prends des contextes et j'appelle des toiles intégrées la méthode de dessin d'image que nous utilisions déjà auparavant. Nous avons déjà dit que la méthode draw image nécessite au moins trois arguments. L'image que nous voulons dessiner et x et y devaient la dessiner. Cela ne fera que dessiner la feuille de calcul entière. Nous pouvons lui transmettre la largeur et la hauteur pour insérer la feuille de calcul entière dans la zone spécifiée. En fait, nous n'avons pas défini ces propriétés. sprite ayant la largeur d' une seule image sera de 255 pixels. La hauteur du sprite est également de 255. Ensuite, nous créons des propriétés de largeur et de hauteur distinctes pour tenir compte du potentiel si nous voulions l' introduire ultérieurement. Maintenant, nous insérons l'intégralité de la feuille de calcul dans la zone d' un seul cadre de sprite. Vous savez probablement déjà que nous aurons besoin version la plus longue de la méthode de dessin d' image dans laquelle nous ajouterons la source x, y, la largeur et la hauteur de la source. Ces valeurs vont d'abord découper une partie de l'image, dans notre cas, une seule image de sprite. Ensuite, nous dessinons ce cadre, la position définie par les quatre derniers arguments. Dessiner le cadre supérieur gauche à la coordonnée zéro-zéro est simple. Nous venons de le faire avec une feuille de calcul des obstacles, source x, y, z, zéro pour définir le début du rectangle de recadrage. Et Sprite with et Sprite height comme arguments de largeur de source et de hauteur pour définir sa taille. Maintenant, nous ne voyons qu'un seul cadre. Je vais calculer la position de l'image de la feuille de calcul par rapport à la collision et aux coordonnées Y de collision du joueur. Il inscrirait ces deux propriétés distinctes juste pour plus de clarté. Gardez donc à l'esprit que ces propriétés définissent le point central du cercle des collisions entre joueurs. Ces deux propriétés, nous allons définir le coin supérieur gauche de l'image du cadre de la feuille de calcul que nous sommes en train de dessiner pour représenter le joueur. Sur nous. Les coordonnées sphériques r à partir du point central, rectangle et les coordonnées de l'image proviennent de son coin supérieur gauche. Et l'image et le rectangle vont vers le bas à droite, en fonction de leur largeur et de leur hauteur à partir de là. Nous devons en tenir compte lors de l' écriture du code suivant. Sprite X sera positionné par rapport à la zone de collision. Ce sera la collision x, le point central du cercle de collision moins la moitié de la largeur du cadre du joueur. Comme ça. Je dois utiliser le sprite X dans le dessin comme argument de destination x ici. Pour que cela fonctionne, nous devons recalculer cette valeur chaque fois qu' une collision x est mise à jour. Je dois donc mettre cela dans la méthode de mise à jour ici. Et je le fais aussi pour Sprite y, qui sera la collision y moins la moitié de la taille du joueur. Je peux le supprimer ici. Et j'utilise Sprite. Pourquoi cette propriété est ici un argument Y de destination transmis à la méthode Draw Image. Il est maintenant positionné sur le dessus. En fait, je veux que ce cercle de collision corresponde le plus possible à la petite ombre au sol sous le joueur, car c'est le point de contact que nous utiliserons lorsque nous interagirons avec d'autres objets dans notre jeu. Comme le lecteur a une taille de pixel fixe, je peux la compenser par une valeur codée en dur. Si nous devions redimensionner nos personnages dans ce jeu, j'utiliserais une valeur relative ici. -100 déplace l'image du joueur vers le haut. C'est bon pour le moment. 14. angles d'animation: Comme nous l'avons fait avec la feuille de calcul des obstacles. Je voulais naviguer dans notre feuille de calcul en passant d'une image à l'autre. La navigation horizontale est gérée en multipliant sprite par un entier représentant la colonne du passé de la feuille de calcul en tant qu'argument source ici. Lorsque nous aurons parcouru cette étape, nous animerons des directions individuelles, boucles d'animation individuelles pour passer d'une direction à l'autre dans la feuille de calcul De la même manière que notre feuille de calcul spécifique est organisée aujourd'hui, nous devons multiplier la hauteur du sprite par un entier représentant le rôle du sprite, vous pouvez voir une ligne, zéro étant joueur orienté vers le haut, loin de nous. Rho One est en haut à droite et le joueur fait-il face à la droite ? Trois est en bas à droite car il est orienté vers le bas vers la caméra. cinquième ligne de notre feuille de calcul représente la face du joueur en bas à gauche, sixième est tournée vers la gauche. Je pense que tu as compris l'idée. J'ai mis ces nombres entiers dans les propriétés de classe. Cadre x pour une navigation horizontale. Châssis Pourquoi, pour la verticale, je remplace ces valeurs codées en dur par mes nouvelles variables, et maintenant je peux modifier image que nous sommes en train de découper de la feuille de sprite du joueur en valeurs différentes à l' image x et à l'image pourquoi ? Je voulais changer de cadre, vient la ligne que nous sommes en train d'animer à partir de la feuille de sprites, où vient la ligne que nous sommes en train d'animer à partir de la feuille de sprites, qui déterminera la position du joueur. Je veux que cela dépende l'angle actuel entre la souris et le joueur et de la position où ils se trouvent actuellement l'un par rapport à l'autre. Pour cela, nous avons une méthode intégrée appelée Math dot eta. Et pour Martha, atan2 renvoie un angle en radians entre l'axe X positif et la ligne projetée de zéro à zéro vers un point spécifique. Nous allons l'utiliser pour calculer l'angle entre le joueur et le curseur de la souris. Et en fonction de cet angle, nous sélectionnerons la ligne la feuille de calcul que nous voulons animer afin que le joueur soit toujours face à la direction dans laquelle il se déplace. Vers le curseur de la souris. Nous aurons besoin de DX et de DY. Je les ai donc déplacés ici. Ces valeurs ont donc calculé la distance entre le joueur et le curseur de la souris horizontalement et verticalement. Gardez à l'esprit que cela fait une différence si vous utilisez d'abord la souris ou le joueur en premier. Dans ce calcul, j'ai déjà écrit ce code ici auparavant. Sans réfléchir, nous l' utiliserions pour cela, se peut donc que nous devions nous y adapter un peu. Je vais vous montrer exactement ce que je veux dire. Les données de Martha s'attendent à ce que dy, dy et dx soient le deuxième argument. Je vais consulter l'angle que nous calculons et je peux voir qu'il change. Et les valeurs vont de -3,14 moins pi à plus 3,14 plus Pi. Cela est vrai parce que nous savons que le cercle complet est égal à deux pi, soit environ 6,28 rad, ce qui se convertit en 360 degrés. Je vais répéter cette méthode. Atan2 renvoie un angle en radians entre l'axe X positif et l'alignement projeté de zéro à zéro vers un point spécifique. Comme j'utilise la souris d'abord et la position du joueur ensuite, lorsque je calcule DX et DY, j'obtiens des valeurs à partir de données de base. Pour en savoir plus, la position actuelle de la souris représente 0,00 et position du joueur est le point vers lequel nous projetons une ligne. Pour des raisons de qualité visuelle, cela fonctionnerait bien mieux si Player était composé de zéros statiques, zéros, d'un important, mais je vais le laisser tel quel. Et à partir des valeurs que j' obtiens dans la console, je vais créer ce graphique avec des points d'arrêt en radians. C'était en fait facile à créer car je n'avais besoin que d'une seule valeur comme point d'ancrage. Et je savais que toute la zone se situait entre -3,14, deux plus 3,14. Et nous avons huit instructions pour les joueurs. Chaque tranche était donc de 6,20 8/8. Quoi qu'il en soit, vous n' avez pas nécessairement besoin de comprendre tout cela, n'est-ce pas ? Maintenant, lorsque nous aurons le code complet, vous pourrez jouer avec les valeurs qui espérons-le, apporteront plus de clarté. Il m'a fallu un certain temps pour utiliser les mathématiques mais atan2 avant de bien comprendre. Donc, si c'est la première fois que vous le voyez, ne vous mettez pas trop de pression. Si je mets l'écran en pause, c'est le 0,00, c'est la ligne projetée vers un autre point. Et les données de Martha et deux nous donnent un angle en radians entre cet axe X positif et cette droite. Donc, en utilisant ce journal de console pour obtenir un point d'ancrage afin que je puisse voir quelles valeurs d'angle nous obtenons. J'ai créé ce visuel d'assistance, que je vais maintenant utiliser pour échanger correctement les lignes notre feuille de calcul afin que le joueur soit toujours face à la souris. Si l'angle est inférieur à -1,17, définissez le cadre y sur zéro. Je vais le copier à quelques reprises. -0,2, 39 est une image y un plus 0,39 est une image. rayonnement de Y à 1,17 est encadré. Y3, 1.96 est le cadre Y4. Voyons voir. Jusqu'à présent, cela fonctionne très bien. Je pense que nous l'avons. Je peux supprimer la console. log 2.74 est la cinquième image. Cette zone est un peu étrange car le cercle se termine et commence. Je dois dire si l' angle est inférieur -2,74 ou si l'angle est supérieur à plus 274. Je souhaite utiliser Frameworks Six. Si l'angle est inférieur à -1,96, le cadre y est égal à sept. Faites attention aux crochets ici, moins n valeurs plus et moins que les opérateurs. Si vous obtenez un comportement inattendu, assurez-vous que tout ce code est le même que le mien. Il est facile de faire une petite erreur ici et de casser votre code accidentellement. Pour que cela fonctionne dans toutes les directions, je dois l'ajuster un peu. Je peux par exemple prendre ces diapositives et les mettre ici, car avec l'instruction else-if, il est important de savoir laquelle est cochée en premier. Parfois, je réduisais le modificateur de vitesse du joueur à trois pour que nous puissions clairement voir comment il évolue. Alors que Destin. Nous pouvons maintenant faire pivoter le joueur dans les huit directions. Parfait. Nous en apprendrons davantage sur l'animation des sprites plus tard dans le cours. Pour l'instant, j'en suis content. 15. Mode de débogage: Puisqu'il s'agit d'un jeu de physique où nous plaçons des zones de collision à la base de chaque objet. Nous voulons pouvoir passer rapidement d'une vue où ces zones de collision sont visibles à une vue invisible. Cela nous aidera à peaufiner la physique et les éléments de jeu au fur et à mesure que nous les développons , tout en nous donnant un moyen facile de vérifier comment les modifications que nous venons d'apporter seront visibles pour les joueurs qui ne verront pas ces cases. Je veux créer un mode de débogage en appuyant sur la lettre D du clavier Nous activerons et désactiverons tous les éléments de collision auxiliaires sur la classe principale du jeu, je crée une propriété appelée ainsi pour déboguer. Au départ, je l'ai défini comme vrai ici, là où nous avons placé les auditeurs de nos événements, puis j'en crée un autre. Nous écouterons l'événement clé. Disons simplement un objet d'événement dans le journal de la console. Lorsque je sélectionne Canvas en cliquant dessus, puis que j'appuie sur n'importe quelle touche du clavier, nous obtenons cet objet d'événement de clavier généré automatiquement. À l'intérieur, nous avons une propriété appelée clé. Vous pouvez voir que j'appuie sur la lettre R, donc la clé dont le prix était fixé se trouve à l'intérieur de la propriété à point E. Je dis que si la touche E est D, définissez la propriété de débogage de la ligne 123 à sa valeur opposée. Donc, si c'est actuellement vrai, définissez-le sur faux. Si c'est faux, définissez-le sur vrai. De cette façon, si vous présentez la même lettre clé D, vous activerez et désactiverez le mode de débogage. J'ai testé en testant ou en déboguant la connexion à la console. J'appuie sur le d encore et encore. Et dans la console, je vois qu'il bascule entre vrai et faux. Parfait. Je supprime le journal de la console, apparais dans la méthode de dessin selon la classe d'obstacles. Je dis que si ce chien est venu vérifier si c'est vrai dans un restaurant, dessine le cercle de la zone de collision. Maintenant, je peux appuyer sur la lettre D, les afficher et les masquer. Cela fonctionne bien. Je veux faire de même pour le joueur. Si ce jeu à débugger est vrai dans un restaurant, tracez le cercle de collision ainsi que la ligne entre le joueur et la souris. Dans ce cas, la position et la taille des boîtiers principaux ne sont pas encore parfaites, mais nous avons maintenant toute la logique en place, excellent travail. Je peux réduire le rayon de collision de chaque obstacle pour qu'il corresponde mieux à la partie où il touche le sol. Nous avons ici différents types d' obstacles. Le champignon et cette grosse plante carnivore devraient probablement avoir des cercles de collision différents , ce qui peut être facilement fait. Mais pour l'instant, j'en suis content. Vous pouvez voir que la formule de collision nous avons écrite auparavant est tout ce dont nous avons besoin pour donner au joueur une capacité de recherche de chemin très simple. Il contournera simplement les obstacles automatiquement. Et comme nous avons placé les obstacles de manière à ce qu'ils soient toujours des espaces entre les deux, il est peu probable que le joueur reste bloqué. Je peux également constater que je n'obtiens que les quatre premières images d'obstacles, ce qui me rappelle d'aller jusqu'à la ligne 10008 et d'inclure la valeur Y de l' image aléatoire comme source. Pourquoi argumenter dans la méthode de dessin d'images par obstacles. Maintenant, je reçois au hasard l'une des images du 12e obstacle. Vous pouvez jouer avec cela, positionner et dimensionner. Votre manuel dit autre chose si vous le souhaitez. Je suis content de ce que nous avons fait jusqu'à présent. 16. Limites de mouvement du joueur: Je voulais m'assurer que le joueur ne puisse pas marcher trop haut au point de se trouver au-dessus de cette zone d'illustration d' arrière-plan. Créons des limites horizontales. D'abord. Si le point central cercle de collision du joueur est inférieur à la coordonnée x zéro plus le rayon de collision, définissez-le sur zéro plus le rayon de collision. Ainsi, lorsque le bord gauche du cercle touche le bord gauche de la zone de toile, ne le laissez pas aller plus à gauche. Je veux faire la même chose pour le bord droit. Bien entendu, nous pouvons supprimer ce zéro plus ici et ici. Si le point central du cercle de collision du joueur est supérieur la largeur du jeu moins le rayon du cercle de collision du joueur. Assurez-vous que ça ne peut pas aller plus loin, non ? Agréable. Limites verticales. Si la collision y est inférieure coordonnée verticale zéro plus la marge supérieure, nous l'avons définie comme étant à 260 pixels du haut plus le rayon de collision. Assurez-vous que le joueur ne peut plus monter. Cela fonctionne bien. Oui, c'est ce que je voulais. Encore une fois, nous pouvons supprimer zéro plus ici et ici. Limite inférieure. C'est simple. Si la collision y est supérieure à la hauteur du jeu moins le rayon de collision, assurez-vous qu'elle s'arrête là comme suit. Cela fonctionne si je réduis le rayon de collision des joueurs à celui des obstacles. En raison de la marge que nous avons définie lors du positionnement des obstacles, un joueur pourra toujours se faufiler entre les obstacles. Les bords de la zone de jeu. Il n'y en a pas. Donc, ici, j'augmente cette marge. Ils devraient le faire. Vous pouvez comparer votre code avec le code source en cours que je vais inclure et télécharger dans la section projet ci-dessous à plusieurs reprises au cours de ce cours au fur et à mesure que nous progressons dans plusieurs reprises au cours de ce cours au notre projet. 17. FPS: Je peux voir que le bas de la feuille de calcul est coupé sur les rangées inférieures. C'est parce que la hauteur d'une image est en fait de 256 pixels. Maintenant c'est corrigé. Dans l'éditeur de code Visual Studio, je sélectionne l'option Afficher le texte pour en faire un saut de code vers une autre ligne s'il ne tient pas. Si c'est trop long. Je voulais configurer FBS pour l'ensemble du jeu, car dans mes projets précédents, beaucoup d'entre vous ont mentionné que les jeux tournaient trop vite sur votre jeu. Les écrans à taux de rafraîchissement élevé demandent une image d'animation ou une méthode que nous utilisons ici s' ajustera automatiquement au taux de rafraîchissement de l'écran. Donc, pour les écrans normaux, ce sera environ 60 images par seconde. Mais sur certains des nouveaux écrans de jeu que les utilisateurs utilisent, cette vitesse serait le double, ou peut-être pas exactement le double, mais beaucoup plus rapide. Nous allons calculer le temps delta, le nombre de millisecondes qui se sont écoulées entre chaque objectif de l'image d'animation de la demande. Et nous n'autoriserons le jeu à diffuser l'image d'animation suivante que lorsqu' un certain nombre de millisecondes se sera écoulé. Nous pouvons calculer le temps delta ici dans notre fonction d'animation personnalisée. Tout d'abord, j'ai défini la dernière fois en dehors de la fonction comme ceci. Au départ, je l'ai mis à zéro. Cette variable contiendra toujours une référence à l' horodatage de la boucle d'animation précédente afin que nous puissions le comparer à l'horodatage actuel. Et la différence entre eux sera le temps delta. Le cadre d'animation de la demande présente deux caractéristiques spéciales. Comme nous l'avons dit, il essaiera automatiquement de s' adapter au taux de rafraîchissement de l' écran, dans la plupart des cas, 60 images par seconde. Il générera également automatiquement un horodatage que nous pourrons utiliser. Et il transmettra cet horodatage comme argument à la fonction qu'il appelle. Dans notre cas, animez. Imaginez qu'il passe cet horodatage ici, comme ça. Automatiquement, il est généré automatiquement. Pour l' utiliser, il suffit de lui attribuer un nom de variable ici. Je vais appeler cela un horodatage, orthographié comme ceci Faites attention aux lettres minuscules et majuscules lorsque vous définissez les noms de vos variables en JavaScript, c'est important. Faisons un journal de console cette variable temporaire de timbres générée automatiquement, que cette image d'animation de demande nous a donnée juste pour voir de quel format il s'agit. Vous pouvez voir que cela nous donne des millisecondes puisque la première animation a été appelée. 1 s, c'est 1 000 millisecondes. Donc, ici, je peux littéralement voir que le jeu a commencé 9101112, il y a 13 s. Je supprime ce journal de console. Nous savons que nous avons accès à l'horodatage actuel Utilisons-le donc pour calculer le temps delta. Ce sera la différence entre l'horodatage de cette boucle d'animation et celui de la boucle d'animation précédente. temps delta est le nombre de millisecondes nécessaires à notre ordinateur pour afficher l'image d'animation suivante. Une fois que nous avons utilisé la dernière fois pour calculer l'heure delta, nous l'attribuons à l'horodatage actuel. De cette façon, l' horodatage actuel peut être utilisé dans la prochaine boucle d'animation en tant qu'ancien horodatage. Pour la toute première boucle d'animation, dernière fois sera nulle, mais ensuite, elle contiendra toujours la valeur de l'horodatage de l'image d'animation précédente afin que nous puissions la comparer à la valeur de l' horodatage de cette image d'animation en cours d'exécution. Et la différence entre eux est le temps delta. Nous allons donc enregistrer le temps delta sur la console pour voir si cela a fonctionné. Mon temps delta est d'environ 16,6 millisecondes. Mille millisecondes divisées par 60 font 16,6. Donc, ça se vérifie. Je me demande combien d'entre vous ont obtenu le même temps Delta et combien d'entre vous ont obtenu un chiffre différent. Si votre écran de rafraîchissement est élevé, votre temps de delta sera beaucoup plus petit. Si vous avez un vieil ordinateur qui a du mal à animer notre jeu, votre temps delta sera peut-être beaucoup plus long si vous avez une seconde ici, temps delta dans les commentaires. Nous savons donc que si la plupart des gens obtiennent des valeurs identiques ou très différentes des miennes, cela m'aidera à mieux optimiser mes futurs cours. Si je fais défiler la console vers le haut jusqu'au tout premier horodatage, vous pouvez voir que les deux premières valeurs du temps delta ne sont pas des nombres. C'est parce que le tout premier horodatage n'est pas défini car ce n' est que dans la deuxième boucle cette valeur d'horodatage est générée automatiquement par le cadre d'animation de la demande. La première boucle n'est pas déclenchée par le cadre d'animation de la requête, elle est déclenchée par cette ligne. Donc, au début, lorsque nous disons que le temps delta est indéfini moins zéro, nous n'en obtenons aucun, pas un nombre. Il se corrige automatiquement au fur et à mesure que la boucle s'exécute. Mais ces deux valeurs initiales et non numériques pourraient casser votre code. Cela dépend du temps delta, à moins que vous ne le preniez en compte par une sorte de déclaration orale. Par exemple, le moyen le plus simple de résoudre ce problème est de passer zéro ici comme horodatage de la première boucle d'animation. À partir de la deuxième boucle, la valeur deviendra le tampon tau généré automatiquement. Parce qu'après cela, animate sera appelé par request animation frame. Comme vous pouvez le voir, nous avons des chiffres ici et il n'y a plus de valeurs non valables. Parfait. Je supprime ce journal de console. Utilisons le temps delta pour définir la fréquence d'images de notre jeu. Nous aurons besoin de certaines variables d'assistance. Fps, les images par seconde seront par exemple 20. Le chronomètre comptera encore et encore à partir de zéro. Vers une valeur spécifique. Lorsqu'elle atteint cette valeur, elle déclenche l'image d'animation suivante et elle revient à zéro. L'intervalle sera la valeur du point d'arrêt qui , une fois atteinte, réinitialisera le chronomètre. Ce sera mille millisecondes, 1 s divisées par FBS. Cela nous donnera le nombre de millisecondes nécessaires pour atteindre ce FBS spécifique. Nous allons gérer cette logique de gestion des cadres ici dans la méthode de rendu. Si le compte à rebours est supérieur à un intervalle, faites quelque chose. Dans le même temps, continuez à augmenter le chronomètre de la valeur du temps delta encore et encore. Lorsque le chronomètre a accumulé suffisamment de temps delta, suffisamment de millisecondes pour que sa valeur soit supérieure à un intervalle. Nous allons animer l'image suivante. Nous allons également remettre le chronomètre à zéro afin qu' il puisse à nouveau être pris en compte pour la prochaine mise à jour du cadre. Je vais prendre tout ce code et le mettre dans l'instruction if. Comme ça. Nous utilisons la valeur du temps delta à la ligne 173. La valeur du point sera transmise en tant qu' argument pour la méthode de rendu ici. Et dans la boucle d'animation, nous calculons le temps delta ici et nous le transmettrons pour obtenir un rendu comme celui-ci. OK, il se passe donc quelque chose. La raison pour laquelle tout clignote est que nous supprimons constamment de la vieille peinture, mais que nous ne redessinons notre jeu lorsque le chronomètre atteint un intervalle. J'ai obtenu ce rectangle clair à partir d'ici. Maintenant, nous ne sommes plus du tout clairs avec la vieille peinture. Et tout s'anime à 20 images par seconde. Et tout laisse des traces. Et je n'effacerai l' ancienne peinture que lorsque nous serons prêts à redessiner le cadre A de la prochaine mise à jour du jeu ici. Donc, contexte, rectangle clair entre les coordonnées zéro et zéro jusqu'à cette largeur de point, cette hauteur de point pour vider toute la zone de jeu, une optimisation serait de dessiner notre jeu sur plusieurs éléments liés au cannabis et de ne les portions de cannabis qui le mettent réellement à jour. De cette façon, nous n'aurions pas à tout redessiner tout le temps. Pour l'instant, cela fonctionnera bien. Vous devriez pouvoir constater un ralentissement de vitesse d'animation du jeu, car nous avons fixé images par seconde ici à 20. Pour le rendre encore plus évident, je ne veux peut-être animer que cinq images par seconde. 30405060. Je suis certain que FBS passe à 60 images par seconde, mais nous n' animons pas vraiment notre jeu à mais nous n' animons pas vraiment notre jeu à 60 images par seconde, car chaque fois que je remets le chronomètre à zéro, il reste du temps delta dont je ne tiens pas compte. Donc, même si je dis 60, le FPS réel est un peu plus bas. Je peux descendre et je peux expliquer le temps delta restant. Mais peut-être que je veux garder ce code léger. Peut-être que je ne veux pas créer JavaScript pour faire encore et encore plus de calculs. Donc, tout en gardant cela à l'esprit, je saurai que je dois régler FBS une valeur légèrement plus élevée ici pour obtenir quelque chose d' environ 60 images par seconde. Si je mets cette valeur à 70, je pense que nous obtenons des mouvements suffisamment fluides et que nous n'obligerons pas JavaScript à calculer le delta tan restant, ce qui augmenterait légèrement la demande de performances dans notre jeu. Je viens d' y penser maintenant, je ne sais pas quelle est la meilleure solution. Je vais laisser mon code comme ça pour le moment, mais je suppose que la bonne solution dépendra des préférences personnelles de chacun. Donc trois pour en discuter dans les commentaires. Je tiendrai compte de vos commentaires dans mes futurs projets. Maintenant que nous savons comment contrôler la vitesse d'animation de notre jeu en utilisant le temps delta, le jeu fonctionnera à la même vitesse sur toutes les machines, même pour ceux d'entre nous qui utilisent des écrans à taux de rafraîchissement élevé. 18. Cours d'œufs: Je voulais ajouter des œufs qui peuvent être déplacés pour apporter encore plus de physique à notre jeu Ces x se transformeront en créatures au bout d'un certain temps ou après un certain temps. Et le travail des joueurs sera de protéger les créatures que Hodge. Le x peut être bousculé par les ennemis, mais ils ne seront pas détruits. Le défi pour le joueur est que lorsqu'ils éclosent, les ennemis mangent les nouveau-nés. Dans notre jeu, le travail des joueurs sera donc de positionner le x, de le protéger ou d' éloigner les ennemis de la trajectoire des créatures nouvellement écloses. La larve qui sort de chaque œuf essaiera toujours de se mettre en sécurité et de se cacher dans les buissons à l'intérieur de la forêt de champignons située au sommet. Cela offrira un large choix aux joueurs et leurs options dans notre jeu , tout en utilisant la physique que nous avons mise en œuvre J'ai eu l'idée de cette mécanique de jeu en regardant un documentaire sur la nature dans lequel petites tortues éclosent sur la plage et essaient de se rendre en mer pour des raisons de sécurité. Dans notre jeu, nous contrôlons la balle bleue. Son travail consiste à protéger les nouveau-nés en repoussant X, laves et les ennemis. Ce jeu est entièrement axé sur la physique et le positionnement. J'aurai une classe personnalisée que j'appellerai, par exemple constructeur s' attendra à une référence Comme d'habitude, le constructeur s' attendra à une référence à l' objet principal du jeu, afin de s'assurer que la classe Ec a accès à de nombreuses propriétés importantes de l'objet de jeu. X fera partie de la physique du jeu. Je dois donc m'assurer de définir x et y distinctes coordonnées x et y distinctes pour le point central du cercle de collision. Et pour la feuille de sprite. Commençons par la propriété collision x. Il s'agira d'une valeur aléatoire comprise entre zéro et la largeur de la zone de jeu. collision y sera comprise entre zéro et la hauteur du jeu, comme celui-ci, le rayon de collision, par exemple 40 pixels. Cette image de chargement sera le document point à obtenir élément par ID, et l'ID se trouve dans index.HTML. En fait, je dois créer cet élément d'image. Comme toujours, les images peuvent être téléchargées dans la section des ressources ci-dessous. Je le cache avec du CSS ici. Je conserve les mêmes conventions de dénomination tous mes objets. C'est une bonne pratique. La largeur du sprite sera donc 110 pixels et la hauteur du sprite de 135. La largeur et la hauteur seront définies sur les mêmes valeurs. Dans notre jeu, chaque objet a une collision x et une collision. Pourquoi les propriétés qui représentent le point central de la collision constituent un cercle, même le joueur et les obstacles portent les propriétés ainsi nommées afin que nous puissions utiliser une méthode de détection des collisions réutilisable pour appliquer notre physique à tout. Il en va de même pour Sprite x et Sprite. Pourquoi des propriétés ? Elles représentent la position du coin supérieur gauche à partir de laquelle l' image de l'objet sera dessinée. sprite X de l'image sera une collision x plus la moitié de la largeur de l'image. Pour centrer l'image horizontalement au-dessus du cercle de collision. sprite y sera la collision y plus la moitié de la hauteur de l'image. Nous devrons peut-être ajuster cela un peu plus tard, car verticalement, nous voulons que la zone de collision se situe à la base du cou, et non au milieu. Nous y reviendrons bientôt. La méthode Draw s'attend à un contexte comme argument. Comme d'habitude, nous appelons draw image, et cette fois, nous n'avons besoin que de trois arguments. L'image que nous voulons dessiner et les coordonnées x et y où la dessiner. Si nous devions effectuer une mise à l'échelle, nous inclurions également des arguments facultatifs de largeur et de hauteur comme celui-ci. Mais je vous donne toutes les images de la même taille. Nous les dessinons dans le jeu. Ce n'est donc en fait pas nécessaire. Comme pour tous les objets du jeu, nous ne dessinons pas seulement l'image représentant l'objet, nous dessinons également cercle de collision si le mode de débogage est actif Comme nous conservons les mêmes conventions de dénomination pour les propriétés sur l'ensemble de notre base de code, nous nous facilitons la vie. Je peux simplement copier l'intégralité de ce bloc de code et l'utiliser ici. Nous dessinons donc x MHz et si le mode de débogage est activé, nous dessinons la zone de collision. Oui, c'est probablement une bonne idée de placer ce code dans des méthodes réutilisables, car nous utilisons le même code pour dessiner des cercles de collision pour tout. Je le ferai peut-être plus tard. Pour l'instant, je voulais créer une méthode qui ajouterait périodiquement un nouvel œuf à notre jeu. Dans la classe de jeu, nous aurons un tableau contenant tous les objets contenant des œufs actuellement actifs. J'aurai également une autre propriété appelée nombre d'œufs. Ou un x maximum le décrit encore mieux. Nous n'ajouterons de nouveaux éléments au jeu que jusqu'à ce que le total soit inférieur ou égal à la valeur x maximale. 19. Ajouter périodiquement de nouveaux œufs: Dans la méthode de rendu, nous allons gérer la logique pour ajouter x périodiquement. Nous l'avons déjà fait. Nous avons créé un événement périodique dans cette base de code où nous utilisons le temps delta et n'avons déclenché une nouvelle trame de jeu que lorsqu'une certaine valeur d' intervalle était atteinte. Nous allons en fait faire la même chose ici. Nous aurons besoin de variables d'assistance pour cela. Le chronomètre à œufs passera de zéro à la valeur d'intervalle x. Ensuite, il ajoutera un nouvel œuf et il se réinitialisera pour pouvoir compter. Encore une fois. Nous fonctionnons en temps delta, donc en millisecondes, je veux ajouter un nouvel œuf, disons toutes les 500 millisecondes. Ici, je vais vérifier si le minuteur à œufs est supérieur à l'intervalle x. Nous ajoutons un nouvel œuf en appelant cette méthode à partir de la ligne 220. À l'intérieur, je prends simplement la matrice d'œufs, que j'appelle méthode de poussée intégrée . Je vais y ajouter une nouvelle instance de nos clients, par exemple class. Comme d'habitude, nous savons que le verre à œufs s'attend à ce que le jeu soit une dispute. Je lui passe donc ce mot clé parce que nous sommes à l'intérieur de cet objet de jeu ici. Donc, si le compteur d'œufs est supérieur à l'intervalle x, nous appelons ajouter un œuf. Nous allons également remettre le chronomètre à zéro afin qu'il puisse à nouveau compter pour le prochain œuf. Sinon, nous continuons à augmenter le temps des œufs en fonction du temps delta, que nous transmettions déjà ici à la méthode de rendu d'avant. Je consigne ce point x sur la console pour voir si les objets sont ajoutés. Désolé, cela ne fera que créer un tableau qui s'agrandira à l'infini. Je dois créer une condition supplémentaire ici, ajouter un nouveau x uniquement tant que la longueur du tableau x est inférieure à la valeur maximale de x, c'est mieux. J'inspecte l'un des objets. Je dois m'assurer que toutes les propriétés ont des valeurs. Si, par exemple, je n'ai pas défini comme coordonnée x de collision, mon x ne serait pas dessiné sur Canvas car JavaScript ne saurait pas où les dessiner. Je vois des valeurs dans tout. Ça a l'air génial. Dans la méthode de rendu, je voudrais également dessiner mon x. Je copie simplement cette ligne et j'ai ajusté chaque élément en rayons X, nous l'appellerons par exemple. Nous appellerons la méthode de dessin dessus. Parfait. Nous obtenons maintenant des visuels qui nous permettront de peaufiner les détails et de les peaufiner encore plus facilement. La première chose que je remarque, c'est que tous les œufs sont ajoutés presque instantanément, même si j'ai dit que je voulais un œuf toutes les 500 millisecondes. Si j'augmente l'intervalle x à 1 s ici, je peux voir que quelque chose ne va pas avec mon code. Je sais que le problème doit être dans ce bloc de code. Et comme le chronomètre à œufs est bien plus qu'un intervalle et que ce n'est qu'ensuite qu'il faut ajouter un nouvel œuf, nous devons utiliser cet opérateur de comparaison ici. Désolée pour cette faute de frappe. Vous l'avez probablement déjà remarqué. Maintenant, ça marche. Un nouvel œuf est ajouté toutes les 1 s, tant que nous en avons moins de dix. Je peux également voir que les images sont positionnées en dehors des cercles de collision. Je change ce plus en moins ici et aussi ici. Maintenant, c'est mieux. Je souhaite ajuster la feuille de calcul en fonction de son cercle de collision. Plus 35 le déplacera vers le haut de -35, nous le déplacerons vers le bas de -30. Je voulais que le bas de l'image soit le plus proche possible, mais je ne voulais pas non le cercle de collision soit trop haut, car je veux que le joueur puisse marcher derrière l'œuf sans le pousser, pour avoir l'illusion que notre zone de jeu est en 3D et qu' elle a une certaine profondeur, même si en réalité il ne s'agit que d'une surface plane. Nous ferons davantage pour l' appliquer dans un instant. Maintenant, je veux créer une marge pour m'assurer que le x apparaît à une certaine distance minimale des bords de la zone de jeu, afin que le joueur puisse placer le joueur entre l'œuf et le bord pour le pousser où bon lui semble. Je veux que la marge soit, disons que les termes du rayon de collision à la position x initiale du cercle de collision seront une valeur aléatoire en partant de la gauche. À partir de cette valeur de marge, nous venons de définir et de jouer avec moins cette marge. Ici, je règle l'intervalle de 200 millisecondes. Je veux 50 x juste pour avoir une meilleure idée de l'endroit où ils peuvent apparaître dans notre jeu. Nous avons la marge gauche que je voulais, mais je vois que le x est trop éloigné du bord droit. Donc, ici, j'augmente cette marge droite comme ceci. Oui, j'en suis content. Dx sont désormais toujours entièrement visibles horizontalement, avec un espace supplémentaire à gauche et à droite entre les âges de la zone de jeu. Verticalement, je vais faire quelque chose de similaire. La position aléatoire doit commencer en dessous la zone de marge supérieure que nous avons définie précédemment. Je ne veux pas de x devant cette illustration d'arrière-plan. La façon dont Math.random fonctionne, j'ai juste poussé la fourchette d'ici à ici. Je dois également réduire la plage en réduisant la plage de valeurs aléatoires que nous obtenons. Donc hauteur de jeu moins marge supérieure. Maintenant, x peut apparaître d'ici à ici. Je vais réduire la valeur aléatoire par marge pour lui donner un peu d'espace en bas, comme ceci. Parfait. Si vous êtes débutant, Math.random peut ne pas être intuitif. C'est en fait très simple. Cela peut juste demander un peu de pratique. Donc, ici, je dis «  Définir la collision ». Pourquoi choisir une valeur aléatoire commençant par la marge supérieure ici ? Parce que nous partons du haut et que la plage de valeurs aléatoires correspond à la hauteur du jeu moins cette marge, moins cette autre marge. Donc x peut apparaître n'importe où entre ici et ici. Verticalement. J'ai réglé l'intervalle à 500 millisecondes et le maximum x à dix, par exemple . Pour l'instant, cela signifie qu'un œuf apparaîtra toutes les demi-secondes jusqu'à ce que le nombre total soit de dix. Comme il s'agit d'un jeu de physique, nous voulions que le joueur soit capable de pousser les œufs pour les éloigner des ennemis, ou de les positionner stratégiquement pour donner à la larve qui en sortira ou de les positionner stratégiquement pour donner à la larve qui les meilleures chances de survie. Dans ce jeu, j'ai choisi que x soit indestructible. ennemis repousseront simplement le x s'ils entrent en collision, mais la larve qui éclot sera mangée si l'ennemi l'attrape. donc très important de positionner et de déplacer le x. Donnons un peu de physique au x. 20. Physique des œufs: Je donne à chaque œuf et à chaque méthode de mise à jour à l'intérieur, nous allons créer un tableau d'assistance temporaire appelé objet de collision. Il contiendra tous les objets de notre jeu avec lesquels x interagira. Nous vérifierons la collision entre chaque œuf et ces objets. Nous aurons donc besoin d'un joueur ici, jeu à points, d' un joueur de points comme celui-ci. Et bien entendu, nous avons besoin de solides obstacles. Je veux que tous ces éléments soient au même niveau. Dans un tableau d'objets en collision. Nous avons un objet de joueur ici. Et nous allons répartir le réseau d' obstacles dans le tableau d' objets de collision à l'aide d'un opérateur de propagation. Comme ça. L'opérateur de propagation nous permet d'étendre rapidement les éléments d'un tableau à un autre tableau. Je vais en fait appeler cette collision un objet avec de la glace. Je vais appeler pour chacun de ces objets, pour chacun de ces objets. Donc, dans ce cas, pour le joueur et pour tous les obstacles individuels que nous avons ici, je souhaite utiliser cette méthode de vérification des collisions nous avons définie à la ligne 225. Si vous vous en souvenez, il prend l'objet a et l'objet B comme arguments. Et il renvoie un tableau qui nous donne la valeur vraie ou fausse pour la distance de collision entre points centraux des cercles de deux collisions, certains de leurs rayons et la distance horizontale et verticale entre les deux points centraux. Je copie ce tableau. Je le colle ici. Encore une fois, nous utiliserons cette structure pour définir rapidement ces cinq variables en utilisant une seule ligne de code J'ai besoin d'un nom de variable ici, donc je vais appeler la première collision vraie ou fausse, qu'elle entre en collision avec un joueur ou un obstacle quelconque. Nous l'avons déjà fait. Je veux que ce soient des variables principales et qu'elles soient égales à ce jeu de points. Ne vérifiez pas la collision entre cet œuf car nous sommes dans la méthode de mise à jour de la classe Ec et de l'un des objets du tableau d'objets des collisions. Ainsi, lorsque la méthode forEach s'exécute, nous exécutons la méthode de vérification de collision entre cet œuf et chaque élément de ce tableau. Et nous obtenons cinq variables qui nous fournissent plus de détails sur la position et la collision des deux objets que nous comparons. Si une collision est détectée, nous utiliserons en fait toutes ces valeurs pour calculer jusqu'où et dans quelle direction nous voulons pousser l'œuf. direction horizontale de la poussée sera le rapport entre le x, la distance horizontale entre les deux points centraux et la distance hypoténuse de ce triangle droit imaginaire. Comme dx est un site de ce triangle et que la distance est l'hypoténuse, le côté le plus long, nous sommes divisés en valeur plus petite par une valeur plus grande. En raison de cette unité, x sera compris entre moins un et plus un. D x peut être positif ou négatif. Unité y. direction de poussée verticale sera le rapport entre D et la distance. Maintenant, nous allons l'utiliser pour déplacer l'œuf. Nous sommes à l'intérieur d'un bloc de code qui ne s'exécutera que si x entre en collision avec le joueur ou l'un des obstacles. Ainsi, lorsqu'une collision se produit, nous prenons la collision x de l'œuf et nous le poussons d'un pixel en dehors du rayon de l'objet. C'est la collision et la largeur. Donc, collision x de l' objet, point central, plus un pixel supplémentaire pour déplacer l'œuf en dehors de la zone de collision. Voici donc la distance et la direction horizontale de ce mouvement qui seront définies en la multipliant par l'unité x, qui, comme nous l'avons dit, peut être positive ou négative. Nous devons également déplacer la collision et l'œuf verticalement. point central de collision y de l'œuf sera la collision y de l'objet. Il entre en collision avec plus le rayon de l'œuf plus le rayon de l'objet plus un pixel supplémentaire. Donc, dans la boucle suivante, la condition est fausse. Termes direction verticale définis par l'unité y. Notez qu'ici nous détectons une collision et que je me déplace collision et collision, pourquoi de l'œuf en fonction de la position de l'obstacle ? C'est juste mon choix et cela fera bouger l'œuf et tous ces éléments seront solides dans cette interaction. Lorsque l'interaction se produit, nous déplacerons le joueur et les obstacles resteront solides. Ils ne seront pas poussés par l'œuf. Ici, nous appelons méthode de dessin sur chaque œuf. Nous voulons également appeler cette nouvelle méthode de mise à jour que nous venons d'écrire. Nous allons tester cela. Nous sommes en train de pousser le cercle de collision de cet œuf. Je dois m'assurer que la zone de collision et le Sprite restent solidaires. Le moyen le plus simple serait de prendre ce code qui positionne le sprite X et le Sprite. Pourquoi, en ce qui concerne la collision et la collision y et je l'appellerai méthode de mise à jour des informations. Je peux supprimer les valeurs ici et maintenant nous pouvons pousser dx en utilisant le joueur, et elles entreront également en collision et glisseront autour de nos champignons et de nos plantes, autour des obstacles solides. Les Dx n'interagissent pas les uns avec les autres. C'est juste mon choix. Je veux que les x se chevauchent pour qu'un joueur expérimenté puisse pousser plusieurs œufs, les blesser ensemble et les pousser tous en même temps. Ce choix simplifiera également notre code, car nous apprenons. 21. Dessiner l'ordre: Nous dessinons tout sur un seul élément de toile. Ainsi, l'ordre de dessin de nos objets de jeu, la position du drone derrière et ce qui se trouve à l'avant dépendra de l'ordre dans lequel nous appelons les méthodes de dessin sur chaque objet à partir de la méthode de rendu ici. heure actuelle, j'ai dessiné des obstacles, donc des champignons et des plantes. Ensuite, je dessine des x. Donc, les x sont dessinés au-dessus des obstacles, comme vous pouvez le voir ici. Ensuite, nous dessinons le joueur. Le joueur est dessiné au-dessus de tout le reste. Si je prends le x et que je le dessine en premier, il y aura toujours un dessin derrière les obstacles derrière le joueur. Et ici, nous pouvons voir que cela n'a pas vraiment de sens visuel. Je voulais créer une illusion de profondeur, fausse 3D ou peut-être deux d et demi. objets bas devraient être placés à l'avant. Au fur et à mesure que nous montons, les objets dessinés sur cette ligne de base verticale doivent être dessinés derrière, par exemple cet œuf doit être dessiné devant cette plante, et non derrière elle. Nous ne pouvons pas vraiment y parvenir. Si nous dessinons tous les x, puis tous les obstacles , puis le joueur, nous devons ajuster légèrement notre code. Je vais devoir mettre tous ces objets dans un seul tableau, et je vais trier ce tableau en fonction de coordonnées verticales. Laisse-moi te montrer ce que je veux dire. Je crée une nouvelle propriété sur la classe de jeu principale. Je vais appeler cela des objets de jeu. Au début, ce sera un tableau vide. Dans la méthode aléatoire, je vais prendre un objet de jeu et j'utiliserai opérateur de propagation pour étendre l'ensemble du tableau qu'il contient. Je vais également élargir l'ensemble des obstacles ici. Et je vais ajouter le joueur. Maintenant, nous regroupons tous les objets du jeu dans un seul tableau. Ce tableau sera recréé chaque fois méthode de rendu nécessite une bonne optimisation. Un conseil serait de n' effectuer cette opération qu' une seule coordonnée verticale de tout changement d'élément. Ou lorsque nous ajouterons ou retirerons un œuf, je réutiliserai ce bloc de code. Au lieu d'appeler chaque méthode sur array, je vais l'appeler sur ce nouveau tableau d'objets de jeu. Pour chaque élément du tableau, je vais lui attribuer un nom de variable temporaire, par exemple l'objet de chaque objet du tableau d'objets du jeu appelle ses méthodes de dessin et de mise à jour associées. Pour que cela fonctionne, il est important que tous les objets que nous ajoutons au tableau d'objets du jeu à la ligne 217 aient des méthodes de dessin et de mise à jour définies en fonction de leurs classes. Sinon, le code se casserait car JavaScript ne serait pas en mesure de trouver cette méthode. Nous appelons donc à dessiner et à mettre à jour tous les objets du jeu , tous les x, tous les obstacles et le joueur. Cela signifie que je peux maintenant supprimer ces lignes de code. frappe, j'ai orthographié les objets du jeu avec un S. Maintenant, nous dessinons le premier obstacle, puis nous obtenons une erreur. Nous appelons le tirage au sort sur le premier obstacle. Et lorsque nous avons essayé d' appeler la mise à jour dessus, nous obtenons une erreur de type indiquant que mise à jour par points de l'objet n' est pas une fonction. Je passe à ma classe d'obstacles et vous pouvez voir, comme je l'ai dit, que nous avons une méthode de dessin ici, mais il n'y a pas de méthode de mise à jour. Nous demandons à JavaScript d'appeler une méthode qui n' existe pas sur cet objet, je vais créer une méthode de mise à jour ici. Dans le cadre de cette méthode, nous pourrions par exemple animer des feuilles de calcul représentant ces plantes et champignons chaque fois que le joueur en collision avec eux ou quelque chose comme ça Peut-être que j'ajouterai des obstacles interactifs plus tard. Pour l'instant, nous allons laisser cette méthode vide. Maintenant, cela fonctionne et nous appelons Draw and Update sur tous les x, tous les obstacles et sur le joueur. Sinon, j'aurais également pu résoudre l'absence de méthode de mise à jour sur les obstacles en utilisant une sorte de déclaration « sinon » ici, il y a toujours plusieurs façons de faire quelque chose. N'hésitez pas à discuter de la façon dont vous aborderiez cela différemment. Peut-être trouverons-nous de meilleures solutions dans les commentaires que je pourrais utiliser dans les prochains cours. J'apprécie lorsque vous me faites part de vos commentaires sur mon code et lorsque vous suggérez des améliorations. Bon, maintenant, nous appelons tirage et mise à jour lorsque nous parcourons les objets du jeu, ce qui signifie que x sont dessinés en premier, les obstacles sont au-dessus de x et le joueur est dessiné au-dessus de tout. Si je modifie l'ordre de ces éléments ici, le joueur est désormais attiré par X et les obstacles sont au-dessus de tout. Nous pouvons donc maintenant comprendre comment fonctionne la superposition. Cela dépend de l'ordre dans lequel nous appelons la méthode de dessin sur chaque objet pour dessiner nos objets de jeu dans l'ordre qui convient visuellement. Je peux maintenant trier le tableau des objets du jeu en fonction de la position verticale de chaque objet. Je prends un tableau d'objets de jeu et j'appelle la méthode de tri intégrée . Cette méthode trie les éléments d'un tableau et renvoie le même tableau maintenant trié. Par défaut, si nous l'appelons sans passer d'arguments, il convertira simplement les éléments du tableau en chaînes. Et il les triera en fonction de leurs valeurs Unicode. n'est pas ce que nous voulons vraiment, alors nous allons en discuter. Cet argument facultatif que nous pouvons transmettre à la méthode de tri des tableaux est une fonction de comparaison, une fonction personnalisée qui définit une certaine logique. Il définit un ordre de tri spécifique que nous souhaitons. Cette fonction spéciale prendra deux arguments, l'élément a et l'élément étant tous les éléments du tableau. Dans notre cas, dans les objets du jeu, le tableau sera représenté par a et B utilisés dans la logique que nous définissons ici Je peux renvoyer comme ceci, et je veux trier les éléments par ordre croissant en fonction de la valeur de chaque collision d'objets. Pourquoi l'immobilier ? Nous trions donc en fonction du point central vertical de la zone du cercle de collision. Nous pouvons également trier par le bas de l'image du sprite, qui serait triée en fonction de la valeur de Sprite y plus la hauteur du sprite. La méthode de tri peut être compliquée à comprendre si vous êtes débutant, tout ce que vous devez comprendre ici, c'est que je place tous mes éléments dans un tableau d'objets de jeu. Alors je suis la méthode de tri intégrée de Colin sur ce tableau. Et j'organise ces éléments en fonction de leur position verticale. Cela ne fonctionne pas maintenant parce que je crée un tableau que je dessine puis que je trie. Je dois trier les éléments après avoir créé le tableau, mais avant de les dessiner. Donc comme ça. Parfait. Maintenant, il est dessiné devant la plante, mais si j'utilise le joueur pour le pousser vers le haut, la position verticale des œufs devient inférieure à la position verticale de la plante. Maintenant, l'œuf est dessiné derrière la plante. Il s'agit d'un moyen simple de dessiner des éléments dans un jeu 2D d'une manière plus logique sur le plan visuel. Il s'agit d'une technique très puissante à ajouter à votre boîte à outils de codage. Vous avez des questions ? Laisse un commentaire. Vous n'avez pas à faire la chose suivante que je vais faire maintenant. J'ai réglé l'intervalle à 20 millisecondes et le x maximum sera de 150. suffit de tester s'il y a des problèmes à résoudre. Au fur et à mesure que je les parcoure, la physique semble très bonne. Tout fonctionne bien. fait d'avoir autant d'œufs à tester me donne également une assez bonne idée de l'endroit où ils pourraient potentiellement apparaître. Ils apparaissent dans la zone que nous avons spécifiée avec une grande marge supérieure et une marge plus petite à gauche, en bas et à droite. Nous avons X, de bons codeurs. J'ai dit intervalle de 2000 millisecondes, un œuf par seconde, et le maximum x sera de 20. Comme cette formule de collision est en place, si elle apparaît au-dessus d' un obstacle ou du joueur, elle est automatiquement poussée hors de son rayon de collision. Je supprime ce journal de console à la ligne 237. Nous avons notre monde de jeu. Nous avons réparti aléatoirement des obstacles solides. Nous avons un personnage de joueur contrôlé par la souris qui peut se déplacer dans une direction. Et nous avons x qui apparaissent dans un intervalle spécifique. En plus de cela, tout entre en collision et réagit à tout. Nous pouvons créer tellement de jeux différents avec ça, ajoutons des ennemis. 22. Cours ennemi: Je crée une classe personnalisée que j'appelle, par exemple ennemi. Comme d'habitude, le constructeur prendra un jeu comme argument et nous convertirons cette référence en propriété de classe. Nous faisons cela pour accéder facilement à toutes les propriétés de la classe de jeu principale depuis la classe ennemie grâce à cette référence en matière de jeux pour chiens. Nous devons conserver les mêmes conventions de dénomination ici. Ainsi, le rayon de collision de 30 pixels, la collision x, le point central du cercle de collision seront le bord droit du Canvas. Ce jeu de points a la largeur des points. Collision y sera une valeur aléatoire comprise entre zéro et la valeur de hauteur de jeu provenant d'ici. Vitesse X vitesse horizontale sera une valeur aléatoire comprise entre 0,5 et 3,5. Vous pouvez télécharger l'image de l'ennemi dans la description de la vidéo. Dans un premier temps, nous allons commencer par le cadre unique statique. L'identifiant sera remorqué, source sera indiquée par le point PNG. Je le cache avec du CSS parce que nous voulons dessiner là où le JavaScript sur Canvas, cette propriété d'image par points sera obtenue élément par ID. Et la carte d'identité que nous lui avons donnée a été remorquée. Sprite avec, dans ce cas 140 pixels et la hauteur du Sprite est de 260. Je vais également créer des propriétés de largeur et de hauteur. Et nous allons définir les positions du sprite X et du sprite y de l'image de la feuille de calcul qui sera positionnée par rapport aux coordonnées du cercle de collision. La méthode Draw prendra le contexte comme argument. Méthode de dessin d'image intégrée. Et parce que le fichier image que j'utilise a déjà la même résolution que la taille. Je veux qu' il l'affiche dans le jeu. Je n'ai qu'à lui présenter trois arguments. L'image que je voulais dessiner et x et y devaient la dessiner. Je vais également copier le visuel du cercle de collision qui n' apparaîtra que lorsque la propriété du mode de débogage est définie sur true. Uniquement lorsque le mode de débogage est actif. Je ne fais que le copier et le coller ici. Puisque ce code est le même pour tous nos objets. Méthode de mise à jour. À l'intérieur, je veux que les ennemis se déplacent vers la gauche dans le sens négatif sur l'axe horizontal X à la vitesse x, une valeur que nous avons définie sur la ligne 179. Nous déplaçons donc les ennemis vers la gauche si le bord droit de la feuille de calcul est caché derrière le bord gauche du cannabis. Nous pouvons remettre sa position x sur la largeur du jeu afin qu'il puisse à nouveau traverser l'écran à gauche. Nous allons également modifier sa position verticale en Y de manière à ce que les ennemis empruntent des voies différentes. J'aurai donc des ennemis qui marchent de droite à gauche, puis qui se réinitialisent et marchent à nouveau. Sinon, j'aurais pu créer de nouveaux objets animés encore et encore, les détruire, les jeter lorsqu' ils sortent de l'écran. Le code serait simple, mais réutiliser des objets en réinitialisant leur position plutôt que d'en créer de nouveaux et de les supprimer ultérieurement est une bonne technique d'optimisation. Réutilisons vos objets et réinitialisons leurs positions si possible Plutôt que d'en créer de nouveaux, l'utilisation du nouveau mot clé pour créer un nouvel objet coûte plus cher que la réinitialisation d'un objet existant. la classe de jeu principale, je crée une méthode personnalisée que j'appelle par exemple at, NME. Ici, nous aurons un tableau qui contiendra tous les objets animés actuellement actifs. Chaque fois qu'un ennemi court, nouvel objet animal est projeté dans le réseau ennemi. En ligne 174, je peux voir que le constructeur de la classe ennemie attend le jeu comme argument. Je lui passe donc ce mot clé, car nous voici dans cette classe de jeu. faisant cela, je transmets simplement une référence qui pointe vers un espace de la mémoire où un objet de jeu est stocké. Je ne suis pas en train de créer une copie de l'objet du jeu. À chaque fois, je crée un nouvel ennemi. La méthode Init s'exécutera. Je veux juste initialiser notre jeu et tout configurer à l'intérieur. Nous sommes déjà en train de créer des obstacles. Nous allons également créer des ennemis dans cette boucle FOR qui s'exécuteront, disons, trois fois. Et chaque fois qu'il fonctionne, il appelle. Et puis, selon la méthode que nous venons de définir, je peux sélectionner ce point, les ennemis. Et comme prévu, il contient trois objets animés. J'inspecte l'un d'entre eux juste pour assurer que rien n'est indéfini, ce qui pourrait poser problème. Tout va bien ici. Je peux supprimer le journal de la console. C'est une bonne idée de toujours vérifier vos objets et vos tableaux à l' aide des journaux de console lorsque vous créez vos projets étape par étape afin détecter les bogues et les fautes de frappe potentiels à temps. Pour dessiner et mettre à jour des ennemis, il me suffit d'étendre le tableau d' ennemis à l'objet du jeu à l'aide de l'opérateur de propagation. Nous l'avons déjà fait. Je ne vois que des zones de collision, je dois donner quelques valeurs au sprite X et au Sprite y pour que le JavaScript sache où dessiner la position des images du sprite. Nous allons déménager. Lorsque les cercles de collision se déplacent. J'ai donc mis ce code dans la méthode de mise à jour. Commençons par le centroïde, puis nous le décalons. Sprite X est une collision x moins la moitié de Sprite avec un sprite comme celui-ci. Pourquoi la collision est-elle égale à la mi-hauteur ? Je veux que les cercles de collision correspondent à l'ombre au sol. En dessous, les ennemis flottent le plus près possible. Nous devons ajuster les positions de l'image verticalement. -40 -60. Qu'en est-il de la hauteur négative ? Plus de 40 ans ? Je peux activer et désactiver mode de débogage pour afficher et masquer les zones de succès en appuyant sur la lettre d. Nous avons des ennemis qui viennent de droite à gauche puis se réinitialisent. Je veux qu'ils se réinitialisent complètement derrière le bord droit afin que nous ne les voyions le bord droit afin que nous ne les voyions pas simplement apparaître. les avons donc réinitialisés à la largeur des points du jeu plus la largeur de l'ennemi. Et en plus de cela, un autre jeu avec le terme 0,5 pour donner à chacun un délai aléatoire différent. Pourquoi est-ce ici ? Je supprime ça. Juste pour les tests. Augmentons la vitesse. réinitialiser de manière aléatoire derrière le bord droit fonctionne bien, c'est peut-être un peu trop rapide. Je dois restreindre leurs positions verticales. Disons que nous partons de la marge supérieure. Et à partir de là, une fourchette aléatoire entre zéro et la hauteur de jeu moins la marge supérieure. Je copie cette valeur pour l'utiliser comme position x de collision initiale dans le constructeur. Et je prends cette nouvelle collision expliquer pourquoi je l'utilise dans le cadre de la méthode d' enregistrement et de mise à jour du récepteur. Cela ne fonctionnera pas car ici, à la ligne 176, j'utilise cette largeur de point, mais elle n'est définie que plus tard ici à la ligne 183. Ici, l'ordre est important. Je prends simplement ces deux lignes et je les mets ici. Nous avons maintenant des ennemis qui marchent de droite à gauche dans un couloir correct et se réinitialisent derrière le bord droit. De cette façon, nous pouvons réutiliser les mêmes ennemis encore et encore, à moins que je ne décide ajouter d'autres fonctionnalités, comme permettre au joueur détruire des ennemis ou quelque chose comme ça. Nous allons voir. Encore une fois, vous n'êtes pas obligé de faire cette partie. Je suis juste en train de tester notre code. Je crée donc 30 ennemis. fait d'avoir autant d'ennemis me donne une meilleure idée de la façon dont ils se réinitialisent et je peux détecter les problèmes potentiels plus rapidement. Tout semble bien fonctionner. Ce serait une forêt très dangereuse. Heureusement pour nos créatures naissantes, le jeu final ne comportera pas tels essaims d'ennemis, à moins que vous ne vouliez créer une vague périodique d'ennemis comme celui-ci. En tant que jeu et mécanique, le joueur doit se préparer et éviter. Nous pouvons faire tellement de choses en termes de conception de jeux ici Je vous donne simplement les outils et techniques et je vous montre certaines de mes idées. N'hésitez pas à développer ce jeu avec vos idées créatives. Une fois le cours terminé, revenons à trois ennemis. heure actuelle. Les ennemis volent simplement à travers la forêt sans interagir avec quoi que ce soit. Tout d'abord, je veux qu'ils réagissent à obstacles solides et que le joueur ait déjà du code qui utilise cette méthode de mise à jour des informations sur la classe EKG. Je peux littéralement utiliser le même bloc de code et le placer dans la méthode de mise à jour de la classe ennemie. Cela transformera les ennemis, traitera les obstacles et les joueurs deviendront des objets solides et impossibles et ils glisseront autour d'eux. Nous utilisons la méthode de mise à jour interne de la classe ennemie, et nous passons l'ennemi comme objet a, joueur et les obstacles comme objet B. Et ici, nous disons ajuster position de a en fonction de la position de B. Le joueur et les obstacles seront solides et dominants dans cette interaction, et les ennemis seront bousculés autour d'eux. Ce simple enregistrement en cas de collision créera également une intelligence artificielle très basique. Comme vous pouvez le voir, les ennemis marchent de droite à gauche dans la zone de jeu. Et ils se glissent automatiquement vers intérieur et évitent les obstacles et le joueur, ils l'ont évité de cette façon, nous pouvons également utiliser le joueur pour repousser les ennemis, même manière que nous pouvons pousser le x J'ajuste la vitesse de l'ennemi. Si j'ajoute x à la matrice d' objets de collision d'une classe ennemie, x deviendra également un obstacle solide et impossible pour les ennemis. Et les ennemis devront les contourner. Cela peut être une bonne chose selon la façon dont vous concevez votre jeu. Au fait, je veux que mon jeu soit, je voulais en fait supprimer le x d'ici. Au lieu de cela, je passe à la classe et à la méthode de mise à jour interne, j'ajouterai des ennemis aux objets de collision. Ici. Cela fera des œufs un chemin pour vérifier la méthode des collisions. Et les ennemis seront solides, les objets impossibles, car les ennemis pousseront le x. Si je le fais de cette façon, nous avons implémenté de nombreuses fonctionnalités. Je vais donc laisser le code source de cette étape dans la section ressources ci-dessous, vous pouvez le télécharger et le comparer à vos fichiers. Si vous codez seul. J'espère que tu t'amuses bien. 23. Cours de Larva: Ici, entre les classes d'œufs et les classes ennemies. Et je crée une nouvelle classe que j'appelle, par exemple larve. Je veux que x ait une minuterie cachée et qu'après un certain intervalle de temps, chaque œuf éclose en une larve plus petite. Cette larve va essayer de se cacher dans la forêt. Et notre travail en tant que joueur est de le protéger en le rapprochant de la zone de sécurité ou en éloignant les ennemis de celle-ci. Le constructeur de la classe des larves sera légèrement différent car je veux que chaque larve apparaisse à la même position que l'œuf d'où provient l'œuf éclos. Nous allons donc lui transmettre une référence à l' objet principal du jeu comme d'habitude, mais nous lui transmettrons également les coordonnées x et y. Maintenant, je convertis tous ces arguments en propriétés de classe. Je dois nommer ces coordonnées x et y, collision et collision, pourquoi ces variables seront impliquées dans la détection des collisions. Nous devons donc les nommer de la même manière que les autres objets de notre jeu de physique, afin pouvoir utiliser notre méthode réutilisable de vérification et de collision et d'impliquer ces larves dans la boucle du jeu de physique. Nous aurons également besoin d'un rayon de collision ici, disons 30 pixels pour le moment. Vous pouvez télécharger l'image de la larve dans la description de la vidéo. J'ai ajouté ici un identifiant de larve et un point de larve source PNG. Il s'agit d'une feuille de calcul à deux cadres. Dans ce rôle, nous avons une larve audacieuse et celle-ci a un peu de duvet derrière le cou, juste pour lui donner une certaine variété visuelle. Le duvet a plus de sens si vous savez ce que deviennent ces nouveau-nés lorsqu'ils sont adultes. J'intègre l' image de la larve dans le projet utilisant get element by ID, comme ceci. Largeur et hauteur d'un seul cadre. Maintenant, la largeur du sprite est de 150 pixels, hauteur du sprite est également de 150 pixels. Si vous êtes débutant, je vous suggère fortement suivre mon code à la lettre et d'utiliser les mêmes images. Amusant. Une fois le projet terminé, il sera plus facile d'apporter vos propres modifications personnalisées. Changer le code au fur et à mesure tout en suivant ce tutoriel n'est pas une bonne idée. À moins que vous ne soyez un développeur JavaScript expérimenté qui apporte vos propres modifications avant la fin du projet, nous allons le rendre plus difficile à déboguer. Nous aurons également besoin des coordonnées Sprite X et Sprite Y de l'image de la feuille de calcul. Chaque larve devra dessiner et mettre à jour des méthodes. Comme d'habitude. La méthode Draw prendra les contextes comme argument. Dans le site, nous appelons image intégrée dans un tiroir et nous lui transmettons l'image que nous voulons dessiner et les coordonnées x et y où la dessiner. Je veux que chaque larve remonte vers la sécurité de la forêt de champignons. Cette zone ouverte est pleine d' ennemis et elle est très dangereuse. Vitesse, pourquoi la vitesse verticale sera une valeur aléatoire, 1-2, par exemple, nous avons défini le sprite X et le Sprite. Pourquoi des propriétés qui déterminent où la feuille de sprite sera dessinée. Mais comme ils devront se déplacer à chaque fois que les larves se déplacent, je dois les mettre à jour encore et encore à l'aide de la méthode de mise à jour interne. Sprite X correspondra à une collision x moins la moitié de sa largeur. sprite y sera la collision y moins la moitié de la hauteur. Je cache cette image avec du CSS. Nous lui avons donné un identifiant de larve. 24. Couvertures d'œufs: Nous avons donc une classe que nous pouvons utiliser comme modèle pour créer une larve chaque fois qu'un œuf éclot Écrivons l'éclosion d'un œuf en logique, nous devrons aider nos variables. Le chronomètre passera de zéro à l'intervalle d'éclosion. Cela comptera des millisecondes. Disons que je veux que l'œuf éclose au bout de cinq millisecondes après 5 s. Dans la méthode de mise à jour, nous gérons les collisions dans cette zone. Et ici, nous nous occuperons de l'éclosion. Si le délai d'éclosion que nous venons définir est supérieur à un intervalle d' éclosion, nous faisons autre chose. Nous continuons à augmenter le temps d' éclosion en fonction du temps delta. Compter et accumuler en millisecondes. Le terme Delta sera transmis à la méthode de mise à jour ici à la ligne 159. Cette méthode de mise à jour le recevra ici. Rendu intérieur. Nous avons calculé la valeur du temps delta avant la boucle d'animation intérieure temps delta contient le nombre de millisecondes qui se sont écoulées entre cette image d'animation et l'image d'animation précédente. chronomètre accumule donc ce temps delta en millisecondes entre les images. Si le temps d'éclosion est supérieur à l'intervalle d'éclosion, nous supprimerons l'œuf et le remplacerons par une larve. Ici, je crée une propriété appelée marquée pour suppression. Ici, nous avons défini la valeur True pour suppression. Je peux enregistrer et supprimer ces objets marqués pour suppression pour chaque image d'animation. Il serait peut-être un peu plus efficace de restructurer notre effacement uniquement lorsque quelque chose est réellement marqué. appellerons donc ici une méthode personnalisée. Je vais appeler, par exemple, supprimer les objets d'un jeu. Ici, dans la classe de jeu principale, je vais définir cette méthode. Jusqu'à présent, nous ne marquons que X pour suppression. Donc, chaque fois que cette méthode s'exécute, je prends le tableau entier et j'appellerai la méthode de filtrage de tableau intégrée dessus. Ou une méthode de filtrage créera simplement une copie de ce tableau. Mais ce nouveau tableau filtré ne contiendra que les éléments qui passent la vérification fournie dans la fonction de rappel. Dans ce cas, la vérification sera je veux uniquement que le tableau X contienne des éléments dont la propriété de suppression est définie sur false. Si un élément marqué pour suppression est défini sur vrai, il sera filtré hors du tableau. C'est ce que l'on appelle la syntaxe de la fonction de flèche ES6. Je dis de prendre les éléments d'un tableau un par un, attribuer à chacun un nom de variable temporaire. Et sur chacun de ces objets, vérifiez s'ils sont marqués pour suppression. La propriété est fausse. point d'exclamation signifie faux. Si la case marquée pour suppression sur cet œuf est vraie, cet œuf sera filtré hors de ce nouveau tableau. Et cette nouvelle matrice filtrée est affectée à la radiographie d'origine et remplace. Suis-je en train de trop expliquer ? Et encore une fois, enregistrons ce point X du jeu de points sur la console pour voir si x est supprimé et ajouté. Oui, cela fonctionne parfaitement. Lorsque nous sommes en mode debug, je veux que le chronomètre du Hajj soit visible sous la forme d'un chiffre flottant au-dessus chaque œuf dans la méthode de dessin que j'appelle ici la méthode FiltText intégrée. Cette méthode nécessite au moins trois arguments, le texte que nous voulons dessiner et les coordonnées x et y pour le dessiner. La modification de la taille de police, plutôt que de changer la taille de la police à chaque fois que la méthode de dessin s'exécute sur chaque œuf, je vais la configurer ici, à la dixième ligne, lors du chargement de la première page. Il s'agit d'une technique d'optimisation puissante. La police fait partie d'un état et les modifications fréquentes d'un état peuvent affecter les performances. Propriétés du Canvas définies telles que FillStyle, largeur de ligne , style de trait et phonation dans un bloc de code qui s'exécute le moins possible. idéal, évitez d' utiliser une méthode qui s'exécute 60 fois par seconde sur plusieurs objets en même temps. Bien que dans certains cas , cela puisse être inévitable. Tout ce que je veux dire ici, c'est que si vous pouvez définir les propriétés du canevas sur la première page, charger comme ceci, tout ce code ne s'exécutera qu'une seule fois. J'ai dit que j' aimais les 40 pixels. Helvética. J'aurais également pu définir la police Canvas ici dans cette méthode de dessin. Mais comme je l'ai dit, cette ligne de code s'exécuterait 60 fois par seconde sur chaque œuf actif. Cela représente un grand nombre d' opérations qui peuvent être facilement évitées en faisant ce que je viens de dire. Ij dimer est ce nombre ridicule avec tant de chiffres après la virgule décimale. Nettoyons tout ça. Je crée une variable d'assistance appelée display timer. Ici, nous allons formater un peu ce nombre avant de le dessiner. Je peux, par exemple utiliser une minuterie et appeler une méthode intégrée ou fixe. Javascript en méthode fixe convertit un nombre en chaîne et arrondit la chaîne à un nombre de décimales spécifié. En fait, je veux le zéro décimal. Je veux juste voir les millisecondes. J'utilise cette variable de minuterie d'affichage ici pour réellement la dessiner. Je peux ajuster la position verticale du texte, peut-être en fonction d' un rayon de collision comme celui-ci. Ici, je vais placer la ligne de texte au centre. Cela alignera les minuteries et x horizontalement. Agréable. Je voulais pousser les chronomètres encore plus haut au-dessus des œufs. Peut-être même plus. Allons-y avec 2,5. Au lieu de millisecondes, je veux juste voir les secondes. Je ferme donc le compte à rebours entre parenthèses et je le multiplie par 0,001. Maintenant, c'est plus lisible. Nous pouvons voir le nombre de secondes au-dessus de chaque œuf. Faisons éclore chaque œuf au bout de 3 s. Bien. Lorsque l'œuf éclot, il est éliminé par la méthode du filtre. la classe de jeu principale, je crée une propriété appelée hatchlings, Dans la classe de jeu principale, je crée une propriété appelée hatchlings, et je la définis d'abord sur un tableau vide. Chaque fois qu'un œuf éclot, nous introduisons une nouvelle larve dans ce réseau. Ici, sur la ligne 190, je peux voir que la larve attend gibier et des coordonnées x et y. Donc, quand un œuf éclot, je l'apporte à la gamme Game Dot Hatchlings et j'y insère de nouvelles larves. Je le passe à Distort Game. Et je lui transmets les coordonnées x et y de ces œufs qui ont éclos Je retire ce journal de console. Dans la méthode de rendu, j'utilise l'opérateur de propagation ou pour transformer les nouveau-nés en objets de jeu, en tableaux, afin qu'ils puissent être triés, dessinés et mis à jour. Parfait, nous progressons. Maintenant que nous pouvons voir à quoi ressemblent nos nouveau-nés, nous pouvons passer à la classe des larves et nettoyer tout cela. Tout d'abord, nous vérifierons si la larve se met en sécurité. Ils sont en sécurité dès qu'ils atteignent cette zone de champignons et de buissons où ils peuvent se cacher. Donc, si la collision y est inférieure à cette marge supérieure de points du jeu de points, si la larve dépasse ce point, nous pouvons définir la valeur True pour suppression. Nous allons supprimer cette larve parce que nous ne voulons plus la dessiner. Et nous appellerons supprimer les objets du jeu en ligne 350 insights, méthode de suppression de l'objet du jeu. Je fais la même chose que nous avons fait pour x, filtre le tableau des nouveau-nés. Et si un objet larvaire de ce tableau dont propriété est marquée pour suppression est définie true, filtrez-le. Juste pour consulter les objets du jeu dans le journal de notre console. Chaque fois que nous retirons un œuf ou une larve, je reçois une erreur. Et c'est parce que ce doit être ce jeu de points à supprimer des objets de jeu, car cette méthode appartient à notre classe de jeu principale. Je veux que tu dessines des cercles de collision sur les nouveau-nés. Je copie ce bloc de code de la classe ennemie. Et je viens de le coller ici parce que nos classes ont les mêmes conventions de dénomination pour leurs propriétés. Il est facile de réutiliser du code comme celui-ci. heure actuelle, nous sommes en train de dessiner la feuille de calcul complète pour chaque larve. Je voulais recadrer une seule image à partir de la coordonnée zéro-zéro deux. Cela a l'air d'une largeur éclatante et de cette hauteur de sprite à points. Et nous voulons dessiner cette image recadrée à la position sprite, sprite y. Et nous devons lui donner une largeur et une hauteur comme celles-ci. Neuf arguments. Je voulais positionner l'image de la feuille de calcul de la larve par rapport à son cercle de collision. J'essaie -50. Oui, ça va marcher. Je veux que le cercle de collision soit aligné avec le bas de son corps. Je pense que c'est ce qui aura le plus de sens visuel lorsque vous interagissez avec les environnements de jeu et les personnages. Je supprime ce journal de console sur la ligne 362. 25. Sprites et collisions Larva: feuille de calcul Larva comporte deux cadres, mais nous ne dessinons que celui du haut. Réduisons ce cadre de manière aléatoire. Y sera une valeur aléatoire de 0 à 2. Et comme il n'y a pas de ligne 1.5, nous avons par exemple besoin d'entiers, de nombres entiers sans décimales. Je l'intègre donc dans Math.floor. Cette ligne de code nous donnera zéro ou un, car Math.floor arrondira la valeur jusqu'à l'entier inférieur le plus proche. Le cadre X sera toujours nul jusqu'à la fin du cours où je vous donnerai une feuille de calcul avancée. Pour l'animation. Nous utiliserons frame x times sprite avec ici comme source x l'argument transmis à la méthode draw image. Et nous devons également définir une source. Pourquoi la combinaison des coordonnées x et y de la source déterminera la zone de la feuille de calcul dans laquelle nous sommes recadrés à partir de source Y sera encadrée par y fois la hauteur du sprite. Agréable. Puisque frame why est randomisé pour être égal à zéro ou à un. Certains nouveau-nés utilisent l' image du sprite de la ligne zéro, tandis que d'autres utilisent l' autre de la première ligne. collisions entre les nouveau-nés et les objets du jeu seront traitées ici. Je vais ici dans la méthode de mise à jour d'une classe et je copie ce bloc de code, nous y apporterons quelques modifications, mais la plupart seront les mêmes. Nous pourrions donc tout aussi bien le copier ne pas avoir à écrire tout cela. Encore une fois. Je le colle ici dans la méthode de mise à jour sur la classe Larva. Je retirerai les ennemis des objets en collision car les ennemis auront un type d'interaction différent. Ainsi, la larve évitera automatiquement le joueur et les obstacles. Et nous pouvons également utiliser le joueur pour déplacer les larves de cette manière, ce qui sera une mécanique de jeu importante. collisions avec des ennemis seront gérées ici. Je prends un tableau d'ennemis et j'appelle chacun d'entre eux. Pour chaque objet ennemi, je les appellerai ennemi, par exemple pour chacun d'entre eux, appelez cette fonction de rappel. En gros, je veux dire si cette larve et cet ennemi que nous sommes actuellement en train de traverser à vélo avec cette méthode ForEach entrent en collision. Une façon de vérifier facilement si deux objets du jeu entrent en collision est d'utiliser notre méthode de vérification et de collision personnalisée. Encore une fois, je veux vérifier la collision entre cette larve. Nous appartenons à la classe des larves et à chaque ennemi individuel. Comme cette méthode s'exécute pour chaque méthode, nous savons que notre méthode de vérification par collision personnalisée renvoie un tableau de valeurs. Cela nous donne la distance de collision, certains rayons, DX et DY. Je ne veux ici que le premier argument, le collagène, qui sera vrai ou faux selon que cette larve et cet ennemi entrent en collision ou non. Check Collision renvoie un tableau et je veux que l'état de collision soit vrai ou faux. Je veux que le premier élément de l'index du tableau soit zéro, comme ceci. Nous utilisons donc ici la structuration pour extraire les cinq variables individuelles de la méthode Check Collision. Ici, j'accède directement à la première valeur avec l'indice zéro car je n'ai pas besoin des autres. Si je n'ai pas besoin ces autres valeurs en cas de collision entre une larve et un ennemi , c'est parce qu' il n'y aura pas bousculades ni de physique. La larve va juste être mangée. J'ai donc dit « marqué pour suppression » sur cette larve. Object à vrai. Je vais également appeler Supprimer les objets du jeu pour filtrer cette larve hors du réseau de nouveau-nés. Je vais également suivre le nombre de nouveau-nés que nous avons perdus à cause du dégoût et de la variabilité. Ce jeu à points qui a perdu nouveau-nés sera augmenté d'un point. Et ici, lorsque nous vérifions si la Floride déplace la sécurité de la forêt de champignons, nous augmentons le score d'un point. Donc, si nous protégeons la larve par position et x, en repoussant les ennemis ou en poussant larve vers la forêt. Si la larve atteint sa hauteur dans les buissons, nous obtenons un point. Si la larve est mangée, nouveau-nés perdus augmentera d'une unité. Ici, dans notre classe de jeu principale nous créons ces propriétés. Le score sera initialement fixé à zéro et les nouveau-nés perdus seront également initialement fixés à zéro. 26. Gagner des points de score: Je peux utiliser les journaux de la console ou quelque chose comme ça pour vérifier si le code que nous venons d'écrire fonctionne, mais nous avions quand même besoin que ce texte soit affiché au joueur. Donc, ici, nous allons dessiner le texte du statut du jeu. Encore une fois. Nous utiliserons la méthode de remplissage de texte intégrée au cannabis, qui attend le texte que nous voulons dessiner et les coordonnées x et y où le dessiner ? Je veux dessiner le mot score aux coordonnées 25 horizontalement et verticalement. Le problème que nous avons actuellement est que je veux que ce texte soit aligné à gauche. Et si vous vous souvenez du texte ci-dessus, qui indique que ce chronomètre est aligné au centre, je devrai isoler ce FiltText appelé en l'insérant entre des méthodes Canvas sécurisées et des méthodes de restauration intégrées. Ensuite, je peux régler l' alignement du texte sur la gauche. Et j'appelle une restauration. Les méthodes de sauvegarde et de restauration fonctionnent ensemble et nous les utilisons lorsque nous voulons appliquer des paramètres spécifiques uniquement à un certain appel de dessin sur le canevas sans affecter le reste de notre projet. Je sauvegarde l'état du canevas. J'ai réglé l'alignement du texte sur la gauche, qui n'affectera que cet appel FiltText où nous dessinons le score , puis la méthode de restauration réinitialisera toutes sortes de paramètres à ce qu'ils étaient. Safe a été appelé. Dans ce cas, il ne reviendra à la ligne X de la gauche au centre . C'est logique. C'est une technique très utile, surtout si vous souhaitez redimensionner et faire pivoter vos dessins sur toile. Je le fais dans d'autres classes, par exemple dans ma classe de fractale de codage créatif, si vous voulez en savoir plus à ce sujet. Maintenant, le score est aligné à gauche et les chronomètres situés au-dessus des œufs sont alignés au centre. Parfait. J'ai ajusté le texte pour le dessiner, je veux dire marquer l'espace entre deux points entre guillemets , plus cette variable de score par points pour le rendre dynamique. Maintenant que les nouveau-nés se mettent en sécurité et se cachent dans la forêt, nous pouvons voir notre score augmenter en mode débuggage. Je veux aussi pouvoir voir les nouveau-nés perdus. Donc, si ce jeu à débugger est vrai, je copie cette ligne de code. Le texte indiquera perdu plus ce point pour la variable «  hatchlings perdus ». En fait, nous sommes dans la classe du jeu, donc je dois dire juste ce point de débogage. Oui, je change la coordonnée verticale ici. Et maintenant, en mode débuggage, nous pouvons également suivre le nombre de nouveau-nés qui ont été mangés nombre de nouveau-nés qui sont entrés en collision avec des ennemis. 27. Effets de particules: Parfois, la larve éclot rapidement et se nourrit trop vite, ou parfois la larve disparaît très près bord supérieur alors que l' ennemi se trouve à proximité. Il se peut donc qu'il ne soit pas clair à 100 % s'il a réussi à se mettre en sécurité ou s'il a été mangé. J'aimerais ajouter un effet visuel supplémentaire qui nous aidera à rendre notre jeu clair et facile à lire. Je voulais ajouter deux types d'effets de particules. Lorsque la larve atteint la hauteur des buissons, elle interrompt un essaim de lucioles qui se trouvaient sur les branches et elles s'envolent dans les airs. Un joueur voit ces lucioles. Ils savent que la larve est sans danger. Si la Floride se fait dévorer, j'essaierai de créer un mouvement de particules différent et très distinct. Donc, s'il y a de nombreux objets de jeu dans la même zone, nous pouvons toujours savoir ce qui se passe en observant type de particules qui s'en échappent. Je profiterai également de cette occasion pour parler du sous-classement en JavaScript Nous aurons une classe de particules parente qui contiendra toutes les propriétés et méthodes partagées entre tous les types de particules. Il s'agit d'une classe dite parent, également appelée classe de superclasse. Firefly étend cette classe de particules. Il s'agit d'une classe pour enfants, également appelée sous-classe. Nous aurons également une classe que j'appelle spark qui étend la classe de particules comme celle-ci. Nous avons une classe pour parents et deux classes pour enfants. Les classes enfants hériteront automatiquement des propriétés et des méthodes de la classe parent, ce qui nous évitera des répétitions inutiles. Écrivons le code et parlons-en un peu plus au fur et à mesure. Le constructeur de la classe de particules parent s'attendra à la position X et Y du jeu, car les lucioles et les étincelles s' envoleront toujours à partir de la position où la larve a disparu. Et ajoutons une autre couleur, par exemple, ici. Peut-être que je veux qu'un type de particule soit doré et un autre bleu, selon l'endroit où cette particule a été créée dans notre base de code. Je vais te montrer ce que je veux dire. Je convertis tous ces arguments en propriétés de classe comme d'habitude. Je dis de prendre la couleur qui a été transmise en argument ici et de l'enregistrer en tant que propriété scalaire sur cette instance de classe de particules. Vous savez comment cela fonctionne maintenant, rayon sera une valeur aléatoire de 5 à 15. Mais je l'intègre dans Math.floor pour n'autoriser que les entiers, donc pas de décimales. Si nous créons de nombreuses particules, vous remarquerez une grande différence de performance lorsque nous utilisons des valeurs aléatoires comme celles-ci, par rapport à la définition du rayon initial une valeur fixe de, disons dix pixels pour toutes les particules. attribution aléatoire des valeurs d'un objet lorsque la création de plusieurs objets coûte très cher en termes de performances. Vous pouvez améliorer les performances de votre jeu en évitant autant que possible Math.random. Si vous le savez, vous allez créer de nombreuses copies de cet objet en particulier. Je sais que nous allons créer de nombreuses particules. Nous n'avons qu'un seul objet pour le joueur, donc là, cela n'a pas vraiment d'importance. Il n'est créé qu'une seule fois. Mais au cours de notre jeu, nous allons probablement créer des milliers de particules. Une façon d'éviter cela serait d'utiliser une technique appelée regroupement d'objets. Vous créez un pool d'objets particulaires ne les dessinez et vous ne les utilisez qu'en cas de besoin. En termes de performances, ce sera bien mieux que d'en créer constamment de nouveaux et de les supprimer. La vitesse x sera une valeur aléatoire comprise entre moins trois et plus trois. Cela signifie que certaines particules se déplaceront vers la droite dans la direction positive sur l'axe horizontal des X, tandis que d'autres se déplaceront vers la gauche si leur vitesse x est une valeur négative. Pour la vitesse verticale, il s' agira d'une valeur aléatoire comprise entre 0,5 et 2,5 pixels par image d'animation. Je veux utiliser un peu de trigonométrie pour faire tourner, flotter et tourbillonner les particules . Nous aurons donc besoin d'une valeur d' angle au départ, je l'ai mise à zéro. V. La vitesse de l'angle déterminera rapidité avec laquelle la valeur de cet angle augmente. Je vais vous montrer exactement comment l'utiliser dans une minute. Ne t'inquiète pas. Le a sera une valeur aléatoire entre ces deux très petits nombres. Nous allons supprimer les particules qui se déplacent hors de l'écran. Au départ, j'ai dit qu'ils étaient destinés à être supprimés en raison faux drames qui porteront de faux drames qui porteront également sur la classe de particules parent. Il sera donc partagé pour toutes les Fireflies et toutes les Sparks. Je veux m'assurer que les modifications apportées à un état que nous effectuons ici restent isolées de cette particule en particulier. J'ai donc regroupé le code de dessin entre les méthodes Canvas intégrées sécurisées et restaurées. Nous avons attribué FillStyle à cette couleur de point à partir de la ligne 3/3. J'appelle commencer un chemin pour commencer une nouvelle forme. La méthode d'arc intégrée prendra l'horizontale, point central, la verticale, le point central, rayon, l'angle de départ et l'angle final. Je veux que tu dessines un cercle complet. Ainsi, de zéro à math.pi fois et math.pi fois deux, on obtient une valeur en radians et elle est convertie en 360 degrés. boucle est bouclée. Nous devons utiliser des valeurs en radians ici lorsque nous les transmettons à la méthode arc. Ensuite, j'appelle fill pour remplir la couleur de la largeur du chemin. Et je vais aussi le caresser car dans notre jeu, tout a ce style d'art vectoriel avec des contours noirs. Je veux que les particules correspondent à cela. De plus, Firefly ne contiendra que la méthode de mise à jour. Idem pour Spark plus tard lorsque nous appellerons la méthode draw sur la classe Firefly. Comme cette classe étend les particules, JavaScript recherchera automatiquement méthode de dessin et le constructeur dans la classe de particules parente. Cela nous évitera de répéter le code. Je n'ai pas besoin de définir deux fois le constructeur et la méthode de dessin si c'est partagé pour les lucioles et pour les étincelles, nous ne pouvons le définir qu'une seule fois dans la classe parent et le JavaScript le trouvera, il sera hérité. Les lucioles auront un mouvement unique, je pense qu'elles flottent vers le haut et se balancent, de gauche à droite, ce qui est très facile à mettre en œuvre. Tout d'abord, nous allons augmenter l'angle de VA, la vitesse angulaire pour chaque image d'animation. Ensuite, nous augmenterons la collision x de la vitesse x. Comme la vitesse x peut être positive ou négative, ils peuvent commencer à tourner à gauche ou à droite manière aléatoire. La collision y sera moins égale à la vitesse. Pourquoi ? Parce que je veux qu'ils flottent dans la direction négative sur l'axe vertical Y. Si une luciole se déplace complètement vers le haut et qu'elle est cachée au-dessus du bord supérieur de la zone de jeu. Donc, s'il s'agit d' une collision, le point central est inférieur à zéro moins son rayon. Nous avons indiqué que la suppression était marquée comme étant « vrai », et nous appellerons «  supprimer des objets du jeu ». Dans la classe de jeu principale, je crée une propriété appelée particules. Ce sera un tableau qui contiendra tous les objets particulaires actuellement actifs. Je transforme les particules en objets de jeu afin qu' elles puissent être triées, dessinées et mises à jour. Dans Supprimer les objets du jeu, j'ajoute une ligne de code supplémentaire pour filtrer les objets particulaires dont la propriété marquée pour suppression est définie sur true comme ceci. Essayons de créer des particules. Je vais les créer ici en classe de larve. Dans ce bloc de code qui s'exécute lorsque la larve atteint sa hauteur dans la forêt, nous obtenons un point. Je veux qu'un essaim de lucioles s'envole des buissons. Je prends ce réseau de particules aux allures de jeu haut de gamme, et j'y insère une nouvelle Firefly. Je me souviens que les constructeurs de classes de particules attendent pour les arguments, une référence à l'objet principal du jeu, comme d'habitude. Je le transmets donc à ce jeu de points de Larva Constructor. x et y de départ initiaux de cette particule seront les dernières positions X et Y de la larve que nous venons supprimer et la couleur sera rouge, par exemple juste pour le tester. Super, nous avons des particules rouges avec des contours blancs. Si j'en veux plus d'une, je viens de créer une boucle à quatre. Disons que je veux trois lucioles à chaque fois. Je vais changer de couleur en jaune. Voyons à quoi cela ressemble. Les belles particules ont besoin d'un trait noir. Je peux le définir dans la méthode de dessin sur chaque particule. Mais dans ce projet, je n'utilise pas un trait pour beaucoup d'autres choses. Je peux simplement régler le trait sur noir dans le monde entier ici, sur la ligne 9, ce qui sera plus efficace en termes de performances. Cela donnera également des traits noirs pour les cercles de collision pendant que nous sommes en mode debug. Mais je ne pense pas vraiment que ce soit un problème. Ça pourrait être encore mieux comme ça. 28. Mouvement des particules: Les lucioles ont un mouvement très basique vers le haut vers la gauche et la droite. Nous n'utilisons pas cet angle. Nous augmentons sans cesse sur la ligne 327. Un moyen simple de faire en sorte que quelque chose fasse des allers-retours est de transmettre chaque augmentation de la valeur de l'angle à la méthode du sinus ou du cosinus de Masdar. Lorsque votre code est comme ça, va, l'augmentation de l'angle pour chaque image d'animation déterminera la vitesse de balancement. Et cette vitesse x déterminera la courbe, le rayon, la distance parcourue, gauche et à droite, par le mouvement. Parfait. Chaque fois que la larve hauteur dans la forêt, nous obtenons un point et nous en obtenons confirmation en observant cet effet de luciole. Je veux que les étincelles aient un aspect différent, de sorte que, au cas où larve et l'ennemi seraient cachés derrière des obstacles ou quelque chose comme ça, vous puissiez toujours voir que la larve a été mangée fonction de l' effet de particules qui s'y produit. Ici, je vais définir une méthode de mise à jour différente avec un code différent à l'intérieur. Firefly et Spark sont donc toutes deux des classes enfants de la particule mère . Elles héritent toutes deux du code du constructeur de classes de particules. Elles partagent également leur méthode de dessin, mais chacune aura une méthode de mise à jour unique dans Elles partagent également leur méthode de dessin, mais chacune aura une laquelle nous gérons le mouvement. Je vais à nouveau augmenter l'angle en fonction de la vitesse angulaire VA, mais je vais le ralentir. Ainsi, multipliée par 0,5, la position horizontale sera moins égale au cosinus maîtrisé. Nous lui transmettons cette valeur d'angle toujours croissante pour la cartographier le long d'une courbe en cosinus. Et nous définissons le rayon de cette courbe en utilisant la vitesse x. La collision y sera égale au signe de la méthode et je lui transmets la même valeur d'angle et rayon de la courbe est la valeur de la vitesse y. Nous remontons à la classe des larves. Et ici, si la Floride entre en collision avec un ennemi, nous le supprimons. Et je voulais créer un tourbillon de particules. Je vais simplement copier ce bloc de code que nous avons utilisé pour créer trois lucioles et je le copie ici. Dans ce cas, nous voulons créer trois étincelles et la couleur sera bleue. Comment puis-je m'y prendre ? Maintenant, je dois pousser la larve devant un médecin, voir ce qui se passe quand elle est mangée. Super, on a des étincelles bleues et une sorte de mouvement circulaire. Juste à des fins de test, je créerai des étincelles même lorsque larves atteignent la hauteur, en toute sécurité, afin que l'animation se produise automatiquement plus souvent sans que j'aie à les poursuivre. J'ai besoin de le voir pour pouvoir ajuster le mouvement. Que pouvons-nous faire avec ces particules d'olive ? Vous pouvez faire tellement de mouvements différents si facilement. Par exemple, faisons-les rétrécir. Si vous essayez de dessiner un cercle en utilisant la méthode de l' arc dont le rayon est inférieur à zéro, vous obtiendrez une erreur. Nous devons donc être très prudents à cet égard. Je dis que si le rayon est supérieur à 0,1, continuez à réduire le rayon d'une petite valeur. Cette valeur doit être inférieure à 0,1 pour nous assurer que nous ne pouvons pas descendre en dessous de zéro. De plus, si vous vous souvenez bien, nous ne retirons les anciennes particules que si elles dépassent le bord supérieur de Canvas et les particules tourbillonnantes ne le font jamais. Donc, j'ai besoin d'une autre condition. Si le rayon est inférieur à 0,2, par mesure de sécurité, il est marqué pour suppression vrai et appelle la méthode de suppression des objets du jeu. Super, ça a l'air intéressant. Je veux qu'ils soient explorés des deux côtés. Je ne l'ai pas mentionné auparavant car il n'est pas nécessaire de bien comprendre la trigonométrie pour ce cours. Sinus et cosinus et travaillez ensemble pour tracer une trajectoire circulaire. Si nous leur donnons les mêmes valeurs, regardez ce qui se passe si j' échange le sinus et le cosinus. Tout ce que vous devez comprendre à propos du sinus et du cosinus à des fins d'animation, c'est que si vous les passez, valeur de l'angle augmente toujours. Et lorsque vous associez ces valeurs aux positions verticales et horizontales de votre objet, vous obtenez un mouvement circulaire. La meilleure façon d'obtenir un peu de clarté est de jouer avec les valeurs essayées pour le déchiffrer, ajuster le code et de voir ce qui se passe. Ne vous inquiétez pas pour bien comprendre la trigonométrie aujourd'hui, elle peut être compliquée pour les débutants et sa maîtrise prend un certain temps. Je dessine 30 particules ici pour me donner une meilleure idée du mouvement qui se produit. Et si des cas extrêmes apparaissent, il faut en tenir compte. Tu n'es pas obligée de le faire. Je recommande de n'utiliser que trois particules par terme pour des raisons de performance Vous pouvez voir que les étincelles sont des sortes d' explosions tourbillonnantes. Je l'aime bien. Le mouvement est très différent de celui des lucioles. Je leur donne une couleur jaune ici, et je vais recommencer à utiliser des lucioles. Voyons à quoi ça ressemble. Nous savons donc comment étendre classe JavaScript pour éviter les répétitions de code Nous avons créé une classe de particules parente et une classe secondaire, Firefly, qui indique au joueur que des larves ont réussi à se cacher dans la forêt en perturbant un essaim d' insectes en pleine croissance qui flottent vers le haut. Et lorsque la larve est mangée par un ennemi, elle se transforme en un tourbillon d' étincelles magiques qui rétrécissent lentement et disparaissent. Je vais en revenir à trois lucioles ici. Et ici en bas. Créons trois étincelles, ou peut-être cinq, car elles rétrécissent si rapidement et sont souvent masquées par des obstacles et d'autres objets du jeu. Nous voulons nous assurer qu'ils se font remarquer lorsqu'ils apparaissent. J'aimerais également permettre au joueur de déplacer les x vers la forêt pour marquer des points immédiatement Je veux que X éclore instantanément lorsque nous les poussons assez haut dans la zone de sécurité, cet œuf se transformera automatiquement en larve et en lucioles instantanément. Et nous obtiendrons un point. Je peux le faire ici, sur la ligne 179, où nous vérifierons si chronomètre de Hodge est supérieur à l'intervalle entre le clapier et redevenir une larve Je veux que ce bloc de code fonctionne également si l'œuf a été poussé vers la zone de sécurité. Si une collision en position verticale y est inférieure à ce jeu de points (marge supérieure en pointillés). Pour le tester, je devrais peut-être augmenter l'intervalle d'éclosion. Sinon, ces œufs éclosent trop vite. Je vois un œuf ici, pas ici, et je l' enfonce dans la moelle. OK, maintenant on y va. Il a éclos instantanément alors que le temps d' éclosion n'était que 7 s. J'essaie à nouveau avec cet œuf, et oui, cela fonctionne et nous obtenons également des points pour cela. Parfait. 29. Peaux ennemis randomisés: Je repousse de nombreux ennemis différents pour toi. Vous savez comment nous avons un seul fichier image avec plusieurs types d'obstacles. Je vous ai également préparé de nombreux gains de crapauds qui joueront le rôle d'ennemis dans notre jeu. J'ai eu beaucoup de plaisir à créer différentes variations et à imaginer quels types de capacités spéciales et de mouvements spéciaux ils pouvaient avoir. Disons que pour des raisons de performance, nous voulons utiliser uniquement un ensemble d'images statiques pour les ennemis. Nous les animerons également plus tard. Si c'est ce que vous souhaitez dans la version finale du jeu, tout sera animé. Toutes les images du projet peuvent être téléchargées à partir de la section des ressources ci-dessous. Comme d'habitude, je vous offre toutes ces illustrations de jeu premium gratuitement. Ce cours est conçu pour vous donner la valeur maximale possible. N'hésitez pas à utiliser ces ressources artistiques pour vos propres projets si vous le souhaitez. J'intègre donc cette feuille de calcul contenant quatre cadres pour les types d'ennemis au projet. L'identifiant correspond à des crapauds et la source est dirigée vers le point PNG. Je le cache avec du CSS comme d'habitude. Dans script.js, dans le constructeur de classes ennemies, nous créons deux variables auxiliaires qui nous aideront à naviguer dans la feuille de calcul et à recadrer une image aléatoire pour chaque objet ennemi, l'image x. Nous allons parcourir la feuille de calcul horizontalement. Et il sera initialement mis à zéro pour que MY navigue verticalement et il commence également à zéro. J'aurai besoin de la version la plus longue de méthode Draw Image pour définir l'image que je voulais dessiner, la source x, y, largeur et la hauteur de la source afin de spécifier la zone rectangulaire que je voulais recadrer à partir de l'image source et de la destination. Destination. Pourquoi la destination avec et la hauteur de la destination pour définir pourquoi nous avons placé cette image recadrée sur le canevas de destination. Neuf arguments au total. Image pour dessiner une zone de recadrage. Et où placer cette image recadrée. Commençons par recadrer uniquement le cadre supérieur gauche. Nous recadrons donc à partir de la coordonnée zéro à zéro, deux coordonnées, un sprite avec une peau de sprite. Cette feuille de calcul ne comporte qu'une seule colonne, donc le cadre x restera à zéro. Je veux recadrer un cadre vertical au hasard. Donc, expliquez pourquoi la zone de recadrage sera à la hauteur du sprite, poussant le début de la zone de recadrage ici, étant donné ce cadre, pour vraiment le voir, je dois utiliser la nouvelle image avec un identifiant de crapauds. Donc, pour être clair, zéro fois la hauteur du sprite nous donnera ce cadre. Ce cadre sera découpé en deux fois la hauteur du sprite. La valeur que nous transmettons à une source. La méthode Pourquoi dessiner une image déterminera où commencer le recadrage à partir de la verticale. Au lieu de cette valeur codée en dur, nous pouvons utiliser frame. Pourquoi ? Maintenant, quand je donne un cadre, pourquoi une valeur différente ? Cela nous donne différents types d' ennemis. Je veux que chaque objet ennemi soit attribué au hasard à l'une de ces images lors de sa création. Nous avons donc quatre lignes, Math.random multiplié par quatre. Et si je l'enveloppe dans Math.floor cadre y sera soit zéro, soit un, deux ou trois. Je remplacerai également la source X par une trame à points sur disque x fois sprite. Cela deviendra pertinent un peu plus tard lorsque je vous donnerai la prochaine feuille de calcul. Pour l'instant, laissons le cadre x à zéro. Ce serait également bien de réattribuer l'image au hasard à chaque fois, puis déplacer hors de l'écran et de la réinitialiser. Nous utilisons donc toutes les images disponibles. Je place simplement l'image y au hasard, comme ceci pour y parvenir. Pour tester rapidement cette vitesse ou augmenter la vitesse de l'ennemi à une valeur aléatoire, 5 à 8 pixels par image d'animation. Les ennemis se réinitialisent et les images changent de manière aléatoire à chaque réinitialisation. Parfait. Revenons à une vitesse plus basse. J'ai réglé x à cinq, étant donné que nous utilisons des images statiques pour les ennemis à ce stade, les dessiner coûte très peu cher en termes de performances Peut-être pourrais-je également augmenter le nombre d' ennemis à cinq. Cela commence à avoir l'air vraiment bien. 30. Gagnez et perdez l'état: Je voulais afficher un message de victoire et de défaite sur la classe de jeu principale J'ai créé une propriété que j' appelle par exemple le score gagnant. À des fins de test, je l'ai réglé à cinq. Nous allons tirer au sort les messages gagnants et perdants ici. Si le score est supérieur ou égal au score gagnant, je l'emballerai dans un coffre-fort et je le restaurerai pour restreindre certains paramètres de tirage. Nous n'utiliserons désormais que deux messages de victoire ou de défaite. Je souhaite dessiner une couche semi-transparente pour indiquer que le jeu est terminé, et aussi pour rendre le message plus contrasté par rapport à l'arrière-plan. J'ai donc dit FillStyle pour bloquer les zéros, zéros, l'opacité de 0,0, 0,5. Ensuite, nous allons dessiner ce rectangle noir semi-transparent sur toute la toile, de la coordonnée 00 à la largeur et à la hauteur de la zone de jeu. Exécutons ce code pour le tester. Lorsque nous atteindrons le score trois, nous devrions obtenir la couche semi-transparente hollandaise. Oui. Une fois ce rectangle dessiné, je vais changer FillStyle en blanc pour m'assurer que le texte contraste avec le fond sombre. J'ai réglé l'alignement du texte au centre. Nous aurons un message principal en gros caractères et un message secondaire en caractères plus petits. Je vais simplement les définir comme des variables principales. Et la valeur de ces messages dépendra de la qualité de notre jeu. Dans tous les cas, ce message ne s'affichera que lorsque le score sera supérieur ou égal au score gagnant. Mais disons que si nous avons bien joué et nous ne perdons que cinq nouveau-nés ou moins, nous recevrons un message gagnant. Si nous en perdons plus de cinq, nous recevrons un message perdant. Le but du jeu est de pousser des œufs, des maillons et des ennemis pour nous assurer en protéger le plus possible. Donc, si nous jouons bien, disons un message, jouons un peu avec les mots. Vous pouvez écrire ce que vous voulez comme message gagnant ou perdant ici. Donc, si nous obtenons le message principal en grosses lettres sur l'écran, nous dirons cible et quelques points d'exclamation. Le message secondaire, plus petit, dira : « Vous tirez sur les intimidateurs ». Si nous perdons, le message principal indiquera, secondaire plus petit de Borlaug indiquera que vous avez perdu. De plus, nous afficherons une valeur de variable dynamique pour montrer combien de nouveau-nés ont été mangés. Et le coma des nouveau-nés. Ne soyez pas un jeu d'enfant. Il s'agit d'un jeu de physique qui consiste à bousculer les choses. Nous devons apprendre à mieux pousser. J'utilise une bonne vieille concaténation de chaînes pour construire ce message dynamique serait encore mieux d'utiliser un modèle de littéraux ici, si vous connaissez la syntaxe JavaScript moderne. Maintenant, nous voulons réellement dessiner ces messages. Le message de grande taille sera, par exemple, 130 pixels. Helvética. La méthode Filttext prendra le texte que nous voulons dessiner dans le message 1 et les coordonnées x et y seront au milieu du canevas horizontalement et verticalement, comme ceci. Le second message sera plus petit pour les pixels. Helvética. Filttext affichera également le message 2 au milieu du cannabis. Encore un objectif FiltText : nous indiquerons l'espace des scores finaux et nous y afficherons la valeur du score final, plus un point pour terminer la phrase. Et une autre phrase dira : appuyez sur R pour vous cogner à nouveau. Je veux vous montrer comment implémenter une fonctionnalité de redémarrage très simple. Chaque fois que nous appuyons sur la lettre R sur le clavier, je la dessine également au milieu verticalement et horizontalement. Maintenant, je dois espacer ces messages qu'ils ne soient pas dessinés les uns sur les autres. J'ajuste la position verticale du message d' un par -20 pixels, le déplaçant vers le haut dans le sens négatif sur l'axe vertical Y. Le message 2 sera plus 30, en le poussant vers le bas. Le message trois sera plus 80. Voyons à quoi cela ressemble. Oui, cet espace est bien meilleur. Nous avons notre message gagnant. Lorsque le score est supérieur au score gagnant, nous avons dit game over à true. Sur l'objet principal du jeu, je définis le jeu par rapport à la propriété et, au départ, je le définis sur false. La chose la plus simple que nous puissions faire ici est de figer l'animation lorsque Game Over se produit. Je peux le faire, par exemple , ici, je dis ne diffuser que l'image d'animation suivante. Si la fin de la partie est fausse, lorsque la fin de partie devient vraie, la partie se fige. J'ai dit score de victoire à un, juste pour les tests. Et il affichera un message gagnant ou perdant. Et ça va geler comme ça. Je descends à la ligne 519 et je supprime ce passage. J'aimerais que le jeu continue de fonctionner, mais nous allons faire en sorte que le nouveau X cesse apparaître et j' empêcherai les ennemis de se réinitialiser. Ils flottent donc hors de l'écran et y restent. Ainsi, chaque fois que la partie sera terminée, les objets qui se trouvent déjà dans la zone de jeu termineront simplement l' action qu'ils sont en train de faire, mais de nouveaux objets n'apparaîtront plus. Nous finirons simplement de jouer derrière le message gagnant ou perdant, mais le nouveau x n' apparaîtra plus et les ennemis s' arrêteront et entreront. Le joueur sera toujours interactif et nous pouvons toujours le déplacer dans le monde vide du jeu. Comment mettre cela en œuvre ? C'est simple. Tout d'abord, supposons qu' un message de victoire ou de défaite apparaisse et il nous reste encore des œufs qui éclosent . Nous nous assurerons de marquer des points uniquement si la fin de la partie est fausse. Lorsque Game Over aura lieu, nouveau-nés apparaîtront toujours sur les x restants, mais quoi qu'il arrive, cela n' affectera plus nos points de score. Sur la classe ennemie. Je veux que les ennemis soient réinitialisés uniquement si la fin de partie est fausse, comme ça, quand GameOver se produira, et cela leur permettra terminer leur déplacement dans la zone de jeu, mais ils ne seront plus réinitialisés vers la droite. Ainsi, de nouveaux ennemis cesseront d'arriver. Ici, nous voulons ajouter un nouveau x au jeu uniquement si la fin de la partie est fausse, si message de victoire ou de défaite apparaît, si le x existant, nous allons quand même terminer de hacher, mais le nouveau x cessera d'apparaître. Nous allons le tester. J'ai un message gagnant. Il me reste quelques œufs, mais ces nouveau-nés n'augmentent plus notre score. Il nous reste quelques ennemis, mais ils quittent lentement l'écran et ne reviennent pas. Le joueur reste interactif et nous pouvons toujours le déplacer. Parfait. Je voulais tester le message de relâchement Plutôt que de pousser intentionnellement des nouveau-nés devant les ennemis pour qu'ils se fassent manger, je vais simplement définir manuellement les nouveau-nés perdus, les dix ici sur la ligne 380. Oui, nous recevons un message perdant. C'est génial. J'ai dit plus touchez les liens pour revenir à zéro. L'ajout d'une police personnalisée est facile. Vous pouvez choisir la police de votre choix. Je vais accéder à Google Fonts. Des milliers de polices y sont disponibles. Je souhaite utiliser cette police inspirée des bandes dessinées appelée bankers. Je clique ici pour sélectionner la police, et je clique ici, ce qui générera du code que je pourrai utiliser pour inclure cette police dans mon projet. Je copie ces trois balises de liens et je les colle ici dans l'en-tête de mon fichier HTML d'index, en attendant mes feuilles de style personnalisées, afin que la police soit disponible à partir de là. Ensuite, je copie la règle CSS. Je l'utilise ici. Dans le cas de ce projet, je peux simplement appliquer cette famille de polices à tous les éléments. Vous pouvez être plus précis et ne l'appliquer qu'à l'élément de toile. Par exemple , la police est désormais disponible dans notre projet. Donc, ici, à la dixième ligne, j'ai dit toile pleine de banquiers de 40 pixels. Cela affectera le texte qui affiche score et les chronomètres au-dessus des œufs à éclore. Nous voulons également définir des banquiers ici et ici Si nous voulons l'utiliser pour les messages de fin de partie, allons-y rapidement quand la partie sera terminée . Ça a l'air mieux, n'est-ce pas ? Parce que nous utilisons Safe and Restore. Écoutez, tout ce que je fais dans cette zone restera limité au message Game Over est Canvas. Les ombres sont coûteuses en termes de performances et certains navigateurs ne les gèrent pas bien, mais si je les limite à ce bout de texte, tout ira bien. Essayons-le. Nous devons définir la distance horizontale entre la forme et l'ombre. Il peut s'agir d'une valeur positive ou négative selon que vous souhaitez placer l'ombre à gauche ou à droite. décalage d'ombre y peut également être positif ou négatif. Il déterminera la position verticale de l'ombre par rapport à sa forme d'origine. La couleur de l'ombre sera noire. Nous pouvons également définir le flou des ombres si nous le souhaitons. Celui-ci est facultatif, je vais donc le laisser sur zéro par défaut, ce qui signifie plus noble. Gardez à l'esprit que les ombres ne seront dessinées si la couleur de l'ombre est définie sur une valeur non transparente. Et si au moins l'une des propriétés de flou d'ombre, décalage d' ombre X ou de décalage d'ombre y est définie sur une valeur différente de zéro. Les ombres mettent le texte en valeur et le font ressortir un peu plus de l'arrière-plan. J'ai encore dit « bébés perdus » à dix, juste pour comprendre le message de relâchement. À quoi cela ressemble avec une nouvelle police et de nouvelles ombres. Super, ça a l'air super. J'ai dit de remettre la soie dentaire à zéro pour les nouveau-nés. 31. Redémarrer le jeu: Nous avons ce message ici qui dit appuyer sur R pour vous heurter à nouveau, ce qui signifie que vous devez appuyer sur R pour redémarrer le jeu. Ce que je vais vous montrer est le moyen le plus simple d' implémenter la fonctionnalité de redémarrage du jeu dans la classe des joueurs. Je crée une méthode personnalisée que j'appelle, par exemple redémarrer. À l'intérieur, je veux définir propriétés des joueurs telles qu' elles sont au début d'une nouvelle partie. Jetons un coup d'œil à ce que nous avons ici. Je veux que le joueur revienne à la position initiale. Nous allons réinitialiser la collision x et la raison de la collision ? Nous nous assurerons également que image du sprite se déplace en même temps que le cercle de collision. Je vais donc avoir besoin de ces deux lignes de code. La méthode de redémarrage du jeu ramènera donc la zone de collision du joueur et la feuille de sprite du joueur à leur position de départ. Nous descendons ici vers la classe de jeu principale et ici, dans l'écouteur d'événements Key Down, je dis que si la touche qui a été enfoncée est notre méthode de redémarrage des appels sur une classe de jeu comme celle-ci. Je définis cette méthode ici. Et ici, nous allons remettre toutes les propriétés à leur état initial. Cela sera différent d'un projet à l'autre. Nous venons d'écrire cette base de code afin de la connaître et comprendre ce qui doit être modifié pour le jeu revienne à son état initial. Tout d'abord, nous appellerons la méthode de redémarrage que nous venons de définir sur la classe du joueur. Nous allons le tester. Je déplace le joueur et lorsque j'appuie sur la lettre R sur le clavier, joueur revient à sa position de départ. Jusqu'ici, tout va bien. Nous pouvons utiliser une technique similaire pour donner au joueur la possibilité de revenir en arrière. Par exemple, nous avons simplement défini l'état et la position de x et n est n nouveau-nés tels qu'ils étaient, disons il y a 5 s. Cela pourrait nous donner un gameplay intéressant. Quoi qu'il en soit, nous voulions relancer le jeu. Donc, ici, dans le constructeur, je vérifie ce qui doit changer. Je sais que je vais devoir réinitialiser le contenu de mes tableaux. Je prends des obstacles, des x, des ennemis, des nouveau-nés et des particules. Et j'ai dit tout cela pour revenir à des tableaux vides comme celui-ci. Je le teste. OK, donc quand j'appuie sur R, cela se produit et je dois réexécuter la méthode init pour recréer les ennemis et obstacles depuis que nous les avons supprimés. Oui, maintenant, lorsque je redémarre, les obstacles se régénèrent à des positions aléatoires et nous générons également de nouveaux ennemis. Je peux voir que je dois également réinitialiser la position actuelle de la souris. Je prends cette souris à points et je la règle sur ces valeurs de départ, donc je peux simplement la copier. J'ai également remis le score à zéro et j'ai également perdu des nouveau-nés. Je dois également régler le jeu sur False pour m' assurer que x continue d'apparaître et que les ennemis continuent de se réinitialiser. Nous allons le tester. Je joue. Je gagne la partie. J'appuie sur le côté de l'artère. Je joue. Quand je le redimensionne, je joue, je gagne, j'ai l'air de fonctionner. Très bien. J'ai dit score de victoire à 30. OK, je passe un peu de temps à tester le gameplay et il y a encore quelques points que nous pouvons ajuster. Comme vous le savez, nous pouvons activer et désactiver le mode de débogage en appuyant lettre D. Je suis ici sur notre classe de larves personnalisée. J'aimerais que nos liens Larva Hatch interagissent avec x dans la méthode de mise à jour classe Larva. J'ai utilisé l'opérateur de propagation pour étendre x dans un tableau d' objets de collisions. Cela rendra le X solide impossible à surmonter et les nouveau-nés devront ramper autour d'eux. Cela rendra le jeu un peu plus difficile et le joueur devra s'impliquer davantage pour éliminer le x et s' assurer que les nouveau-nés atteignent la zone de sécurité le plus rapidement possible. Parfois, les nouveau-nés peuvent même se retrouver coincés entre plusieurs œufs et des obstacles. Et si nous ne les libérons pas à temps, ils seront dévorés par les ennemis. Sinon, je peux supprimer X d'ici. Je passe à la classe d'œufs et à la méthode de mise à jour des informations. Dans un cours, je vais étendre nouveau-nés à un tableau d'objets en collision. Cela, en revanche, facilitera le jeu, car non seulement les nouveau-nés seront capables de pousser le x à l'écart. Ils placent également parfois le x devant eux, plus près de la zone de sécurité. Vous pouvez choisir vous-même ce que vous voulez faire ici, selon que vous voulez que votre jeu soit facile ou plus difficile à ce stade, vous connaissez assez bien ce code. Donc, si vous le souhaitez, vous pouvez prendre une certaine liberté et ajuster le gameplay comme vous le souhaitez. Je veux également que les cercles de collision des nouveau-nés correspondent mieux à la feuille de sprites -40 ici. Cela fonctionnera bien Je pense que pour mieux aligner le bas des cercles de collision là où se trouve le bas du corps des nouveau-nés. Je veux que ces zones de collision correspondent le plus possible à l'œuvre d'art. Nous sommes maintenant en mode debug, mais gardez à l'esprit que le jeu est censé être joué avec des cercles de collision cachés. Lorsque le mode de débogage est désactivé. Vous pouvez utiliser la même technique pour mieux aligner les cercles de collision sur ennemis avec la petite ombre au sol sous chaque ennemi. Je le ferai dans une minute car dans la prochaine leçon, nous nous concentrerons sur l'ajout de nouveaux types d'ennemis. Je vais également vous donner les feuilles de calcul de tous les personnages et nous ajouterons de nombreuses animations à ce projet. J'ai eu tellement de plaisir à concevoir ces créatures et à les faire bouger. J'espère qu'il vous plaira. J'ai remarqué un petit avantage, lorsque nous recevons un message de fin de partie et ennemis restants mangent des nouveau-nés restants. Les variables relatives aux nouveau-nés perdus continuent d'augmenter. Nous devons nous assurer que la valeur des nouveau-nés perdus reste la même après l'affichage du message Game Over. Je n'exécuterai donc ce bloc de code que si la fin de la partie est fausse. Cela rendra également les nouveau-nés vulnérables pendant le jeu à l'écran. Si vous ne le souhaitez pas, vous pouvez appliquer cette instruction if uniquement à une ligne de code qui augmente le nombre de nouveau-nés perdus. Si la fin du jeu est fausse, nouveau-nés perdus sont plus, plus. 32. Élargir la classe ennemie: OK, plusieurs types d'ennemis. Je souhaite créer deux classes pour enfants qui s'étendent. Classe ennemie parent. La peau dorée sera cette peau verte visqueuse, scan de l' écorce sera le bois creux avec des bois, des pointes et des feuilles. Nous travaillons sur le thème de la forêt magique. Je me suis donc amusée à dessiner des créatures sur celui-ci. Encore une fois, nous étendons la classe JavaScript ici. Nous le faisons pour éviter les répétitions à froid. Toutes les propriétés et méthodes partagées par tous les types d'ennemis appartiendront à la classe endémique parente. Seules les propriétés spécifiques à chaque type d' ennemi seront incluses dans les classes enfants. Vous pouvez télécharger toutes ces versions premium ou les ressources dans la section projet ci-dessous. Nous allons commencer par ajouter huit scans d'aboiement différents. Que pensez-vous de trop de mes créations ? Je voulais que celui-ci soit en bois et qu'il soit creux à l'intérieur, mais que la lumière sorte des yeux et de la bouche, un peu comme une citrouille d'Halloween. Je cache l'image avec du CSS. J'ai également remplacé l'image du crapaud. Au début, nous avions quatre personnages dessus. Il existe désormais huit versions différentes. Beaucoup de mots, de boue, d' yeux et de tentacules. qui concerne la classe ennemie principale, je peux voir que le constructeur s'attend à ce que le jeu soit un argument. Je veux exécuter le constructeur sur la classe ennemie mère et y ajouter un peu de matière depuis la classe de skin TO. Principalement les propriétés qui ne seront spécifiques qu'au type d'ennemi de la peau du crapaud. Ainsi, dans le constructeur de la classe enfant, nous nous attendrons à ce que le jeu soit un argument. Ensuite, nous devons d'abord exécuter constructeur sur la classe ennemie parent, également appelée superclasse. Nous appelons constructeur de superclasse. Et nous transmettons la référence, l'objet principal du jeu , car nous savons ce qui est attendu ici à la ligne 264. Toutes ces propriétés seront spécifiques uniquement à l' habillage NMAI car l'image sera différente. La taille des sprites, ainsi que leur largeur et leur hauteur, dépendront également de la taille de ce sprite. Et la collision x utilise la largeur et sa formule. J'ai donc supprimé tout cela, basant sur la classe pour enfants ici. Ces propriétés auront donc une valeur différente pour chaque classe enfant. Ils ne seront pas partagés. Je vais copier ce bloc de code et le mettre sur Bark Skin. Ici, nous devrons ajuster les valeurs. La largeur du sprite est ici de 183 pixels. La hauteur du sprite sera de 280, largeur et hauteur d'un seul cadre. Cet ennemi sera plus grand. Cette image à points sera l'identifiant de Barack. Lui avons-nous donné un index HTML ? Ce sont donc les propriétés communes à toutes les classes ennemies. Ils partageront également ce tiroir et cette méthode de mise à jour. Les propriétés des classes enfants seront uniques pour chaque type d'ennemi Nous avons deux types d'ennemis. Je voudrais ajouter l'un ou l'autre au hasard. Je m'occupe de l'ajout d' ennemis ici dans la méthode d'ajout de lavement sur la classe de jeu de domaine. Ici, je peux dire que si Math.random est inférieur à 0,5, Math.random appelé seul Math.random appelé seul de cette manière renverra un nombre aléatoire supérieur ou égal à zéro et inférieur à un. On peut donc dire que ce sera moins de 0,5 et environ 50  % des cas. S'il est inférieur à 0,5, nous ajouterons une nouvelle peau de crapaud à notre réseau d'ennemis. Sinon, dans les 50  % restants, nous vendrons de la peau de daim neuve. Agréable. Maintenant, nous ajoutons aléatoirement les deux types d'ennemis. image x est définie sur zéro, nous n'obtenons donc que les images de la première colonne. Je veux que ce soit zéro ou un. Donc Math.random multiplié par deux dans Math.floor comme ça. Maintenant, nous avons toutes les images. Je vais également vous montrer comment animer ces feuilles de calcul, mais cela augmentera les performances du jeu, car les illustrations des personnages que j'ai choisi d' car les illustrations des personnages que j'ai utiliser pour ce projet sont très détaillées et les images sont assez grandes. Certaines techniques d'optimisation peuvent être utilisées pour l'animation de sprites, mais cela dépasse le cadre de ce cours adapté aux débutants. Nous en reparlerons un peu plus bientôt. Lorsque les ennemis se réinitialisent, nous sommes aléatoirement dans l'image y, mais pas x. Faisons-le en copiant la ligne 270 et en la plaçant ici dans ce bloc d'instruction if. Maintenant que nous sommes entièrement aléatoires dans l'image lorsque les ennemis réinitialisent leur position, je peux placer ces lignes qui ont aléatoirement x et l'image y dans une méthode de mise à jour partagée. Parce que mes deux types d'ennemis ont le même nombre d' images pour les lignes et les deux colonnes. Si chaque feuille de sprite ennemie avait un nombre d'images différent, je devrais étendre cette méthode de mise à jour. chaque sous-classe NMS, nous ajoutons et supprimons des objets tels que des particules, des nouveau-nés et des x. Il est toujours bon de vérifier nos objets pour nous assurer que les anciens objets été correctement supprimés et que nous n'avons pas un tableau qui ne s' agrandit pas à l'infini. Je pourrais l'enregistrer sur console dans ma méthode de mise à jour, par exemple, mais exécuter un journal de console comme celui-ci, 60 fois par seconde, coûte très cher en termes de performances. Nous pourrions simplement enregistrer des objets r sur console à la demande chaque fois que nous appuyons sur un bouton de notre écouteur d'événements Key Down Je dis que si nous appuyons sur C sur le clavier, console enregistre ces objets de jeu à points. Maintenant, je peux jouer au jeu et temps en temps, j'appuie sur C pour vérifier si le tableau des objets du jeu ne contient que les bons objets actuellement actifs dans le jeu. Si vous remarquez, par exemple, qu'il augmente sans cesse et qu'il contient de plus en plus de particules. Nous savons que nous ne supprimons pas correctement les anciens objets particulaires. Tout semble bon dans ce cas. 33. Mode plein écran simple: Ainsi, dans notre jeu, nous pouvons appuyer sur la lettre D pour activer et désactiver le mode de débogage, la lettre R pour redémarrer le jeu, C pour créer un journal de console personnalisé. Et je vais également vous montrer comment activer et désactiver un mode plein écran très simple en appuyant sur la lettre F. Nous vous appellerons pour discuter de la méthode, par exemple passer en plein écran. Nous allons le définir ici sur la classe de jeu principale. Javascript possède une fonctionnalité de plein écran native. Cette API intégrée contient un ensemble de méthodes qui nous permettent de présenter un élément spécifique et tous ses descendants en mode plein écran, en supprimant tous les éléments de l'interface utilisateur du navigateur et les autres applications de l'écran. Lorsque j'appelle un élément en plein écran du document point comme celui-ci, il renvoie l'élément actuellement présenté en mode plein écran. S'il renvoie la valeur null, cela signifie que le mode plein écran n'est actuellement pas utilisé. Donc, je veux dire que si nous ne sommes actuellement pas utilisés en mode plein écran sur cette page, je souhaite passer en mode plein écran. La méthode de demande en plein écran affichera l'élément auquel elle est appelée en mode plein écran. Dans ce cas, je voulais afficher l'intégralité de la page Web. Donc document, qui représente l'élément de document DOD de la page Web, qui représente l' élément racine du document, en l'occurrence la balise HTML. Je veux qu'il mette en plein écran l'ensemble de la page Web à partir du code de son élément racine pour quitter le mode plein écran. C'est simple, donc nous disons simplement « sinon » si le document sort du plein écran, Exécuter, le document qui quitte le mode plein écran. C'est un peu bizarre, mais ça va marcher. Pendant ce temps, toute la page Web tournera. Fullscreen Canvas n' occupera pas toute la largeur de l'écran. Nous déplaçons le joueur à l'aide de la souris, nous devons donc faire attention à la façon dont nous redimensionnons Canvas dans ce projet, car les coordonnées de la souris sont calculées d'une certaine manière. Si je donne une largeur dynamique à Canvas avec du CSS, il commencera à nous donner de mauvaises coordonnées. Dans le navigateur Google Chrome. Si je passe en plein écran comme ça et que je zoome pour que le jeu couvre tout l'écran, les coordonnées de la souris seront toujours calculées correctement et le gain sera jouable. Vous pouvez le tester par vous-même en appuyant sur F pour passer en plein écran, puis en maintenant la touche Ctrl enfoncée et en appuyant sur les touches plus ou moins pour zoomer avant et dézoomer. Sur Mac, nous utilisons plutôt la touche Commande. Nous sommes sur le point d'animer les feuilles de calcul. Ces images sont volumineuses et cela mettra à rude épreuve les performances de l'ordinateur lorsque nous commencerons à les parcourir très rapidement sur chaque objet animé actif Vous pouvez enregistrer la base de code telle qu'elle est actuellement et continuer dans une copie de ce dossier afin de conserver des bases de code statiques et entièrement animées et de les comparer côte à côte en termes de les performances de votre machine. C'est à vous de décider. Je laisserai également le code source complet de cette étape du projet disponible en téléchargement dans la section des ressources ci-dessous Le dossier contenant le code source complet de cette étape s'appelle code source version 5. 34. Animation complète de la feuille de sprite: Il est temps d'animer complètement la feuille de sprite du joueur. Nous utilisons déjà la feuille de sprites, mais nous ne recadrons que la première image chaque ligne pour faire pivoter le joueur dans différentes directions. Nous avons ici des variables auxiliaires, où une image x tournera sur la même ligne de gauche à droite en boucle dans cette animation particulière. Et l'image y déterminera la ligne que nous animons. Dans le cas d'une feuille de sprite, le même personnage est orienté dans des directions différentes sur différentes rangées . Nous utilisons la méthode draw pour dessiner cette feuille de calcul sur Canvas. Nous utilisons la version la plus longue avec une image à neuf arguments que nous voulons dessiner. Ensuite, nous définissons la zone de recadrage à l'aide des quatre arguments suivants. Source x, y, largeur et hauteur de la source. Et les quatre derniers arguments définissent où, sur la destination du cannabis, nous plaçons cette image recadrée sur la destination x, destination. Pourquoi largeur de destination et hauteur de destination ? Je l'ai expliqué à quelques reprises dans ce cours parce qu' il est très important comprendre si vous souhaitez utiliser l'image de dessin pour une animation de sprite. Nous avons déjà une fonctionnalité qui permet de remplacer l'image y par une ligne différente en fonction de l'endroit où le joueur doit se trouver. Tout ce que j'ai à faire maintenant pour être complètement animé, c'est de faire image X passe de l'image zéro à l'image maximale encore et encore. Nous allons gérer l'animation des sprites ici dans la méthode de mise à jour. Et nous réutiliserons également ce code pour d'autres objets. Nous aurons besoin d'une autre propriété d'assistance appelée max frame. La feuille Sprite comporte 58 images par ligne. C'est une énorme image de feuille de calcul. Nous allons le parcourir découpant différentes images pour créer une illusion de mouvement et d'animation. Laisse-moi te montrer. C'est facile Si l'image x est inférieure à l'image maximale, je souhaite que l'image x augmente d' une unité au fur et à mesure que la méthode de mise à jour s'exécute encore et encore. Cela se déplacera sur la ligne d'animation de gauche à droite. Lorsqu'il atteint la fin de l'image, x n'est plus inférieur à l'image maximale. Sinon, l'instruction s'exécutera. Il remettra l'image x à zéro afin qu'elle puisse recommencer. C'est ça Nous sommes en train d'animer le joueur. J'essaie de me balader, tourner le joueur dans toutes les directions possibles pour voir si tout va bien. Maintenant, notre joueur est bel et bien vivant. Lorsque vous préparez votre feuille de calcul vous pouvez créer correctement des illustrations de jeu, comme je l'ai préparé pour vous. L'animer avec du code est très simple. Tout ce dont vous avez besoin est ce simple bloc de code. 35. animation complète de la feuille sprite: Je copie ce bloc de code. Je vais le réutiliser en classe de larves. Je passe à la classe des larves. Ici. Nous aurons également besoin de la propriété maximale d'assistance au cadre. Dans ce cas, le nombre maximum d'images est de 38. feuille de calcul Larva comporte 38 images par ligne. Comme d'habitude, vous pouvez télécharger toutes les feuilles de calcul dans la section des ressources. Je le place dans mon dossier Projet et je l'intègre au projet ici. L'identifiant sera une larve, soulignera le sprite et source sera le même point de larve (sprite point PNG). Dans script.js, je pointe cette propriété d'image à points vers ce nouvel identifiant. Il compte 38 images par rangée. Et encore une fois, je veux alterner entre l'image zéro et l'image maximale. J'ai copié cette animation de sprite appelée blog à partir de la méthode de mise à jour de la classe du joueur, et je l'ai collée ici. C'est très simple, il n'est donc pas nécessaire d'apporter des modifications. Si l'image x est inférieure à l'image maximale, continuez à augmenter l'image x d'une unité. Sinon, remettez à zéro l'image x pour qu'elle puisse recommencer. Toutes les feuilles de calcul sont configurées de telle sorte que la dernière image et la première image se connectent dans une boucle d'animation continue. Ainsi, en les repassant encore et encore, vous créerez une séquence d'animation fluide. Vous pouvez maintenant voir nos nouveau-nés ramper avec leur Antonio, vaciller de haut en bas. Ce sont des corps spongieux qui se déplacent alors qu'ils rampent vers la sécurité d'une forêt de champignons. Parfait. 36. animation complète de la feuille sprite: J'ai également préparé des feuilles de calcul d'animation pour les ennemis. Je lui donne un identifiant de skin d'écorce et identifiant sera bark skin point PNG. Le slime vert. L'un sera l'identifiant de la peau adulte et la source de la peau PNG. Dans un skin Hyde Park avec CSS. Aussi dit à la peau. Et le sprite larvaire. Nous allons à nouveau copier ce bloc de code. Il est important de remarquer comment sont organisées les feuilles de calcul de ces ennemis. Nous devons tenir compte du fait que lorsque nous écrivons notre code, je peux voir que nous avons quatre types de crapauds et quatre types pour les peaux foncées, chaque type étant sur une ligne distincte. Dans ce cas, nous savons que l'image y contrôlera le type d'ennemi affiché. image X parcourra à nouveau cette ligne d'animation , donnant vie à cette créature. Il est également important de noter que j'ai la même structure pour les sprites fourre-tout et pour les sprites à la peau foncée. Les deux ont quatre rangées, 38 images par rangée. Je peux donc gérer l'animation sur la classe ennemie parent, car la logique sera partagée pour les deux sous-classes d' animus. J'ai dit image x à zéro ici. Expliquez pourquoi nous allons choisir au hasard l'un des quatre ennemis disponibles à animer. Le cadre maximum sera de 38. Dans la méthode de mise à jour, j'ai géré l'animation des sprites ici, je colle le bloc de code que j'ai copié. Tout d'abord, je voulais utiliser une feuille de calcul sur la peau de crapaud ici et de la peau d'écorce ici comme celle-ci. Lorsque vous voyez un problème d' animation comme celui-ci, cela signifie généralement que la taille d'image que nous avons définie est incorrecte. Les cadres se glissent donc un peu. Les skins foncés s'animent correctement. Je vérifie la taille d'un nombre incalculable d'habillages, et je constate que l' image unique de la feuille de calcul 154 pixels de large et 238 pixels de haut. Vous obtenez la largeur d'un seul cadre en divisant la largeur de la feuille de calcul entière par le nombre de colonnes, par le nombre de cadres par ligne. Et vous obtiendrez la hauteur d' un seul cadre en divisant la hauteur de l' ensemble de la feuille de calcul par le nombre de lignes. Parfait, nous animons les nouveau-nés du joueur et huit types d'ennemis différents. Nous voyons des cercles de collagène, mais le jeu est censé être joué avec le mode de débogage désactivé. Nous devons nous assurer que les zones de collision correspondent aux petites ombres qui se trouvent sous notre char et à celles de nos ennemis, car je veux qu'elles soient parfaites au pixel près. Et les peaux de crapauds, de cannes et de chevreuils ont des tailles de sprites différentes. Je ne peux pas décaler Sprite X et Sprite. Pourquoi ici dans la méthode de mise à jour partagée selon une certaine valeur et alignez les deux à partir du même endroit. Dans une situation comme celle-ci, je souhaite commenter cette ligne et étendre cette méthode de mise à jour à chaque sous-classe afin de lui donner valeurs légèrement différentes pour chaque type d'élément. Pour le faire aussi simplement. On torts can, une sous-classe qui étend classe parent de la superclasse NME, que nous appelons update. Si je définissais simplement la mise à jour comme ceci, cette méthode serait prioritaire et remplacerait complètement la méthode du même nom dans la classe parent. n'est pas vraiment ce que je veux. Je veux que le code contenu dans méthode de mise à jour de la classe ennemie soit exécuté. Et je voulais ajouter du code personnalisé spécifique uniquement à la classe de skin de crapaud ici dans cette méthode de mise à jour sur une classe enfant. Je le fais en utilisant le super mot clé représentant le parent. Et puis mon cours. Ici, je dis d'exécuter tout le code dans la méthode de mise à jour sur le parent, puis la classe sur la superclasse. Ensuite, je veux prendre cette ligne de code, et cette ligne n' exécutera que quatre scans toed. J'essaie plus 50. Mon objectif est d'aligner cercle de collision sur la petite ombre au sol sous les ennemis flottants le plus possible Nous avons cassé des skins parce que la valeur Y de leur sprite n'est pas mise à jour pour le moment, nous allons corriger ce problème dans une minute. Tout d'abord, je veux m'aligner vers la hauteur -100. OK, que diriez-vous de la hauteur de l'ennemi divisée par deux -100 ? Cela se rapproche de plus en plus de ce que je veux. Peut-être -90. Oui. Lorsque j'appuie sur le d pour activer et désactiver le mode de débogage, je peux constater que les skins de Little Ground Shadow Undertone s'alignent très étroitement sur la zone du cercle de collision. Parfait. Je copie ce bloc de code et je le place ici sur nos skins Bark. Ici, je vais faire -100. C'est ainsi que vous étendez une méthode qui existe sur une classe parent comme cette méthode de mise à jour que nous avons ici. Et pour chaque sous-classe, nous appelons d'abord le code dans la méthode de mise à jour de la classe parent à partir de la ligne 302. Ensuite, nous pouvons y ajouter du code supplémentaire qui ne sera unique qu'à cette sous-classe particulière. L'utilisation de cette technique peut donner chaque type d'ennemi un schéma de mouvement différent, un comportement différent, des attaques différentes, des animations différentes, etc. Vous pouvez télécharger le dossier de code source final que j'ai appelé code source version 6 dans la section des ressources ci-dessous et le comparer à votre propre code si vous rencontrez des problèmes. Il est maintenant temps pour vous d'ajouter des fonctionnalités supplémentaires. Essayez peut-être de consulter mes autres classes de développement de jeux où nous appliquons la gestion des sons ou des états et les utilisons pour ce jeu. Découvrez la collection d'actifs artistiques bonus disponible dans la section des ressources ci-dessous Je vais laisser de nombreuses œuvres d'art dans plusieurs formats avec pièces séparées afin que vous puissiez les mélanger et vous amuser si vous le souhaitez. Merci d'avoir passé du temps avec moi. J'espère que tu as beaucoup de valeur aujourd'hui. Bravo pour avoir terminé le projet. Je te verrai plus tard. 37. Projet bonus (optionnel): Créez des environnements de jeu animés pour des personnages contrôlés par clavier directionnel, obstacles positionnés au hasard et des ressources artistiques environnementales. Créons des jeux en utilisant du HTML, du CSS et du Javascript sans framework ni bibliothèque. Comme d'habitude, si je dessine tous mes éléments interactifs sur un seul élément du canevas superposition peut être un défi Nous pouvons utiliser la méthode de tri par tableau intégrée pour réorganiser objets du jeu en fonction leur coordonnée verticale y et les dessiner dans cet ordre Avec cette astuce simple en place, nous pouvons avoir un personnage de joueur qui contourne les obstacles d'une manière visuellement logique. Créons un jeu à partir de zéro et découvrons le développement Front and Y et la programmation orientée objet. 38. Mise en place de projet bonus: Nous travaillerons avec trois fichiers en index HTML. Je crée une page Web simple et générique et je lui donne un titre. Je lie une feuille de style CSS, je crée un élément HTML à cinq canevas avec un identifiant de canevas un, et je lie un fichier de script GS. Je crée un dip avec l'identifiant d' un emballage et j' y mets de la toile. Je crée une balise d'image avec une superposition Source, une superposition Alt et une superposition ID Vous pouvez télécharger tous les actifs artistiques dans la description de la vidéo dans la section des fichiers de projet. Je vous propose également toutes les pièces séparées en haute résolution afin que vous puissiez composer vos propres images d'arrière-plan uniques. Si vous voulez obtenir le conseil d'optimisation numéro un, utilisez du CSS brut. Pour les grandes images de fond, je peux tout dessiner et animer sur du cannavas J'ai l'habitude de le faire aujourd'hui. Je veux vous montrer comment combiner le CSS et méthode de dessin d'image sur toile pour maximiser les performances. Cela vous évitera d'avoir à dessiner ces grandes images sur le canevas encore et encore pour chaque animation Et cela améliorera les performances de nos jeux. Les transformations CSS utilisent le GPU. Ils sont plus rapides et leur balisage est plus simple car CSS contient de nombreux mots clés intégrés ce qui facilite grandement les transitions animées Peut-être que pour votre jeu, vous avez besoin que tout soit dessiné sur toile. Mais aujourd'hui, je vais le combiner avec du CSS pour tirer pleinement parti des outils et techniques proposés l'environnement de développement Web frontal. 39. Améliorer les mondes de jeu: Intalsias. Je donne à Canvas une image d' arrière-plan, vous pouvez la télécharger dans la description de la vidéo ou vous pouvez créer votre propre arrière-plan à partir des éléments individuels que je fournis. Comme vous pouvez le voir, nous avons créé deux couches. œuvres d'art de fond sur lesquelles notre personnage sera dessiné, et quelques images superposées, des feuilles et de l'herbe, figureront devant notre scène forestière Le personnage du joueur pourra se cacher derrière eux. À moins que nous ne définissions la largeur et la hauteur du canevas, valeur par défaut sera toujours de 300 fois 150 pixels. Nous lui donnerons la bonne taille avec le script Java dans une minute pour révéler l'illustration d'arrière-plan complète. J'aurais également pu mettre cette image de fond sur l'élément wrapper. Je donne une bordure à l' élément principal de l'emballage. Mon navigateur est zoomé pour que je puisse tout afficher à l'écran Les images que je vous présente aujourd'hui sont optimisées pour une résolution de 1 280 fois 720 pixels Le jeu que nous sommes en train de créer est assez vaste. Vous pouvez ajuster les tailles si vous le souhaitez. Si vous êtes débutant, ce serait peut-être une bonne idée de suivre exactement mon code, utiliser les mêmes tailles et les mêmes images, et de n'apporter des modifications qu'une fois que l'ensemble du projet aura fonctionné Je veux centrer le récipient, donc je lui donne une position absolue. Vous pouvez voir que l'emballage ne part pas du coin supérieur gauche Il existe des marges et des garnitures par défaut pour garantir que notre page s'affiche de la même manière dans tous les navigateurs Je vais effectuer une réinitialisation globale de tous les éléments de la page et je définis la marge à zéro, remplissage à zéro et la taille de la boîte dans la zone de bordure Pour m'assurer que les éléments de rembourrage et bordure sont inclus dans sa largeur et sa hauteur totales, je souhaite centrer le rapidive au milieu de la page verticalement Je lui ai déjà donné une position absolue. Maintenant, je peux lui donner 50 % du haut, 50 % à gauche et transformer, traduire -50 %, 50 %. Je dois également aligner la superposition Je lui donne la position absolue en haut à 50 % à gauche 50 % de transformation de traduction -50 % à 50 % Cela l'alignera exactement sur le dessus de l'emballage Il y a bien d'autres choses que nous pouvons faire ici. Par exemple, ajoutons deux autres images au projet. Je crée une image appelée leaves underscore left. Je lui donne le même ancien attribut et identifiant. Vous pouvez télécharger toutes ces images dans la description de la vidéo, je crée une autre image appelée leaves underscore, non ? Comme ça. Elles auraient pu n'être qu'une partie de l'image de superposition principale, mais je veux qu'elles soient animées et interactives Comme nous l'avons dit, les transformations CSS sont traitées par le GPU. Profitons-en pour rendre notre univers de jeu un peu plus vivant et interactif. Les CSS font du travail pour nous. Il n'est pas nécessaire de tout dessiner sur toile. Tout va très bien se mélanger et notre jeu sera superbe. Je cible les feuilles de gauche en position supérieure à 50 pixels, la position de gauche à -100 feuilles droite sera positionnée à -150 pixels derrière le bord droit, ici sur l'emballage principal Réglez Overflow sur Masqué, pour découper et masquer tout ce qui se trouve en dehors du conteneur de jeu principal Nous pouvons faire tellement de choses avec elle maintenant. Par exemple, nous pouvons faire bouger les feuilles. Lorsque nous survolons la toile, nous ne sommes qu'un observateur silencieux qui se cache dans les buissons Éloignons un peu les feuilles pour que nous puissions voir. Lorsque je survole le canevas, je souhaite appliquer du CSS aux feuilles de gauche Je vais changer leur position gauche, et je vais les faire pivoter de plus de 15 degrés. Cette déclaration CSS ne fonctionnera pas. Cela fonctionnerait si leaves left était un enfant d'un élément canvas, mais ce n'est pas le cas. Si nous regardons ici, nous pouvons voir qu'ils sont frères et sœurs. Ils sont au même niveau dans l'élément trois et ils partagent tous les deux le même emballage en tant que parent Pour appliquer quelque chose aux feuilles restantes, lorsque vous passez le curseur sur le canevas, nous devons utiliser ce que l'on appelle le sélecteur nous devons utiliser ce que l'on appelle général des frères et sœurs sélecteur général de frères et sœurs sélectionne tous les éléments qui sont les frères et sœurs suivants d'un élément spécifié Si je regarde la structure de nos éléments, nous avons une image de superposition d' éléments de toile directement au-dessus Cela empêche en fait le déclenchement de l'événement hover sur le canevas Je veux que l'image de superposition soit au-dessus, mais je veux qu'elle soit invisible pour toutes les interactions avec la souris Pour que je puisse interagir avec le canevas qui se trouve en dessous. Je peux le faire en définissant la propriété des événements du pointeur la superposition sur une valeur différente heure actuelle, le canevas ne se trouve que dans cette petite zone, mais nous le redimensionnerons bientôt pour remplir tout le conteneur afin de tester le survol. Pour l'instant, je dois déplacer ma souris sur la petite zone du canevas. Ici, cela fonctionne au survol, j'ai réglé la position gauche à -150 pixels Je vais donner aux feuilles un peu de temps de transition pour qu'elles s'animent réellement Essayons 0,3 seconde. Sympa. Je fais la même chose pour les feuilles, non ? Je lui donne également une certaine transition, peut-être juste 0,2 seconde. Ils ne sont donc pas complètement synchronisés. Nous pouvons faire tellement de choses. Par exemple, appliquez une animation d' images clés pour donner l'impression que les feuilles bougent sous l'effet du vent. Je l'appellerai wobble. À 0 %, il commencera au sommet des 50 pixels. Nous aurons un point d'arrêt de 50 % à 55 pixels. Et à 100 %, il reviendra à 50. Nous pouvons l'appliquer en donnant à leaves left la propriété d'animation. C'est ce que nous appelons vacillement. Le timing va s'assouplir. La durée de la boucle d'animation sera de 1,5 seconde. Comme ça, comme ça, ça ne fonctionnera qu'une seule fois, mais je veux une boucle infinie, je ne vois aucun mouvement. Réglons cela à 65 pixels, non ? Je dois m'assurer que j'ai la bonne syntaxe pour les images-clés. Ce point-virgule doit être là, nous avons des feuilles qui bougent dans le vent Essayons 56 pixels. Je copie cette ligne et je l'applique également aux feuilles, non ? Je veux les désynchroniser. boucle sur celui-ci durera 1,6 seconde, comme nous l'avons fait avec la superposition Je dois définir les événements du pointeur sur aucun sur les deux feuilles pour m' assurer qu'ils ne bloquent pas les événements de la souris sur le canevas qui se trouve en dessous. C'est ainsi que nous pouvons dessiner et améliorer une partie de votre scène de jeu avec du CSS. C'est une bonne pratique en matière de performance. Si votre projet le permet, n'hésitez pas à l'utiliser plus souvent. 40. Installation de JavaScript: Nous allons également dessiner quelques images avec Javascript, principalement notre personnage Alber animé contrôlé par clavier Lorsque nous travaillons avec des images en Javascript, nous devons toujours nous assurer que l'image est complètement chargée et disponible avant que le code qui dépend de cette image ne soit exécuté. Dans le cas contraire, nous aurons un message d'erreur. Il existe de nombreuses façons de le faire. Nous pouvons utiliser des promesses ou un moyen très simple consiste à encapsuler tout le code Javascript dans l'écouteur d'événements de chargement L'événement Load est déclenché lorsque la page entière est chargée, y compris toutes les ressources dépendantes telles que les feuilles de style et les images. De cette façon, je peux simplement placer ma feuille de calcul en tant qu' élément IMG normal dans l'index HTML, et Javascript attendra que cette image se charge dans la fonction de rappel anonyme Ici, j'ai installé mon canevas. Nous avons besoin d'une référence à l'élément canvas, une variable constante que j'appelle canvas et je veux pointer Javascript vers cet élément canvas que nous avons créé à Javascript vers cet élément canvas que nous avons la ligne 12 dans l'index HGML, nous lui avons donné un identifiant de canvas one Nous n'avons pas vraiment besoin d'utiliser get element by ID ici, car tous les navigateurs créent automatiquement des variables Javascript pour tous les éléments dotés d'un identifiant. Le nom de cette variable automatique est toujours le même que l'ID. C'est une bonne chose pour le bogue, mais comme les navigateurs placent toutes ces variables dans l'espace de noms global, il est facile de les remplacer accidentellement Il vaut mieux utiliser get element by ID, comme ceci. Le contexte Ctx est canvas point get context two D pour générer une instance de l'API Canvas Two D intégrée qui contient état du canevas et les deux méthodes de dessin L' élément wrapper parent a été défini sur 1 280 fois 720 pixels Assurons-nous que l' élément du canevas est de la même taille. Cela révélera l'illustration d'arrière-plan complète. Qu'est-ce que tu en penses ? Comme je l'ai dit, je partagerai également des pièces individuelles avec vous en haute résolution. Vous pouvez les mélanger et créer vos propres environnements de jeu uniques si vous le souhaitez. Toutes les ressources artistiques que je partage dans cette vidéo sont libres de droits. Ils ont été conçus et dessinés par moi ou par des artistes que j'ai engagés. Vous pouvez les modifier et les utiliser comme bon vous semble. Je vais commenter les animations CSS sur les lignes 39.31. Je pense que ce sera moins distrayant Nous avons maintenant du code Java à faire pour donner vie à notre personnage animé. Suivons les principes de programmation orientée objet aujourd'hui et divisons notre code en classes individuelles. Chaque classe aura des responsabilités différentes et nous les ferons communiquer et travailler ensemble pour créer le produit final. Classe personnalisée que j'appelle par exemple, le gestionnaire de saisie gérera les entrées au clavier Lorsqu'une touche est pressée sur un clavier, cette classe la traite, transforme et stocke cette valeur afin qu' elle puisse être utilisée par d'autres classes. Class Owl Bear sera notre personnage d'animation principal. Le joueur pourra le contrôler à l'aide du clavier. L'objet de classe sera utilisé comme plan pour créer des arbres, des buissons et de l'herbe générés de manière aléatoire Une fois que nous les aurons placés dans le monde du jeu, nous apprendrons à les organiser de manière à ce qu' ils soient dessinés devant et derrière le joueur, en fonction de la position actuelle du joueur . C'est très important car sans cela, dans un jeu comme celui-ci , dessiner un joueur au-dessus de tout n'aurait aucun sens visuel. Nous avons besoin d'une certaine logique pour que le joueur puisse contourner ces deux obstacles en D et je vais vous montrer un moyen simple de le faire. Enfin, nous aurons besoin d' un jeu de classe que j'appelle jeu. C'est là que toute la logique de toutes les classes est réunie. Ce sera le cerveau principal de notre base de code. Le constructeur de classe créera une instance d' une classe pour nous sur la base d'un plan que nous définirons Définissons un plan pour notre classe de jeu principale. Je veux que ces cours soient autonomes et modulaires. Nous allons le transmettre avec la hauteur de la zone de jeu comme arguments comme celui-ci. Nous les convertissons en propriétés de classe. Nous prenons la largeur et la hauteur comme arguments du constructeur de classe et nous les convertissons propriétés de largeur et de hauteur sur cette instance de classe de jeu Pour créer une instance de classe de jeu, je crée une variable constante. J'appelle par exemple game, et j'utilise le nouveau mot-clé. Le nouveau mot clé dans le script Java est utilisé pour créer une instance d'un objet doté d'une fonction constructeur nouveau mot-clé recherchera une classe portant ce nom et déclenchera son constructeur Le constructeur créera un nouvel objet de script Java vide et définira automatiquement son prototype dans les coulisses Il liera ce mot-clé pour pointe vers cet objet nouvellement créé et il attribuera à l'objet toutes les propriétés et valeurs telles que nous les définissons dans le plan ici Jusqu'à présent, notre objet de jeu n' aura que des propriétés de largeur et de hauteur. Dans ce cas, je peux voir que ces propriétés sont attendues sous forme de valeurs transmises de l'extérieur. Nous faisons cela pour que nos cours restent autonomes et modulaires. Je lui transmets la largeur du canevas à partir de la quatrième ligne. Comme pour la hauteur de la toile à partir de la ligne cinq comme hauteur. Comme je veux que le jeu soit de la même taille que le canevas, je veux que la zone de jeu utilise tout l'élément du canevas. C'est ainsi que vous créez une classe dans script Java et une instance de cette classe. Comment utiliser cette classe pour créer un objet basé sur le plan de classe Consolidons la variable de jeu de la ligne 26 pour vérifier si tout s' est bien passé Je peux voir que la variable de jeu stocke une référence pointant vers un objet de jeu avec des propriétés de hauteur et de largeur parfaitement définies sur les bonnes valeurs. Si vous rencontrez des erreurs lors écriture de votre base de code orientée objet, vous pouvez toujours configurer vos objets de cette manière et vérifier si toutes ces propriétés ont des valeurs Si vous voyez « non défini » ici, vous savez qu'il y a un problème dans votre code et vous pouvez suivre cette valeur dans votre base de code pour trouver le problème 41. Commandes de clavier: La classe de gestionnaire d'entrée est là pour suivre les touches du clavier lorsqu'elles sont pressées et relâchées par l'utilisateur Et il les convertira en valeurs utilisables par d'autres objets de notre base de code et les stockera. Je lui donne également un constructeur. C'est ainsi que nous allons faire communiquer nos objets entre eux. gestionnaire de saisie attendra une référence pointant vers l'objet principal du jeu comme argument L'objet entier qu'il contient convertit cette référence en une propriété de classe, comme ce jeu passé argument, est converti en propriété de jeu. Sur cette instance de gestionnaire d'entrée, objets de classe du script Java sont des types de données de référence Je ne crée pas une copie de l'objet du jeu ici, je crée simplement une variable qui pointe vers un espace de mémoire où l'objet de jeu principal est stocké. C'est génial car lorsque les valeurs des objets de jeu sont mises à jour, ces modifications sont immédiatement visibles à partir de cette référence au jeu de points. Ici, dans la classe de jeu principale, je crée une propriété appelée « point last key input handle class » qui mettra à jour cette valeur sur la classe à jour cette valeur sur la jeu au fur et à mesure que les touches sont enfoncées et relâchées. Au départ, je l' ai dit à Undefined. Aujourd'hui, nous allons en apprendre davantage sur les commandes du clavier et nous ne conserverons que la dernière touche enfoncée ou relâchée en mémoire. C'est tout ce dont nous avons besoin pour contrôler, quatre directions sur le personnage. Si je voulais suivre les pressions sur plusieurs touches, je créerais plutôt un tableau ici. Et j'ajouterais et supprimerais des clés à partir de là. Je l'ai déjà fait et je le ferai peut-être plus tard dans cette série. En fonction de la complexité et de la précision des commandes du clavier dont nous aurons besoin. Je souhaite également créer automatiquement une instance de gestionnaire de saisie lorsque je crée l'objet du jeu Mettons ici une console qui indique que le gestionnaire d'entrées a été créé dans le constructeur de classe de jeu Je crée une propriété appelée cette entrée. Je l'ai défini comme un nouveau gestionnaire de saisie comme celui-ci. À la huitième ligne, je peux voir que constructeur de la classe du gestionnaire d'entrées attend une référence à l'objet principal du jeu Ici, je crée une instance de gestionnaire d'entrée dans cette classe de jeu Je lui passe ce mot clé. Ce mot clé utilisé dans une classe de jeu pointe vers l'ensemble de la classe de jeu elle-même. Il représente l'objet dans lequel il a été défini. Bien parce que je mets ce code dans le constructeur de classe de jeu lorsque je crée une instance de classe de jeu sur la ligne 31, il crée également automatiquement une instance de classe de gestionnaire d'entrée pour Cela l'enregistrera sous forme de propriété de saisie de points dans la classe de jeu principale elle-même. Je peux confirmer que le gestionnaire de saisie a été créé car je vois cette console ici. Il s'agit d'un moyen simple de connecter vos classes et de les faire fonctionner ensemble pour créer un jeu complet. Il est également très modulaire, ce qui vous permet d' ajouter ultérieurement plus de fonctionnalités et de classes à votre jeu si vous le souhaitez. Comme nous le voyons avec cette console, tout le code contenu dans le constructeur de classe est automatiquement exécuté lorsqu'une instance de cette classe est créée Ce code ne doit pas toujours être simplement défini dans les propriétés de classe. Nous pouvons mettre n'importe quel code ici. Dans ce cas, je souhaite appliquer automatiquement les écouteurs d'événements Lorsqu'une instance de classe de descripteur d'entrée est créée, je les mettrai simplement ici. Nous écouterons l'événement key down dans la fonction de rappel Je vais exécuter une fonction de rappel consolo si l'écouteur d'événements en Javascript a accès à objet d'événement généré automatiquement qui contient tous les détails sur l'événement qui contient tous les détails sur l'événement Je peux lui attribuer un nom de variable ici, la convention est généralement une lettre comme celle-ci. Je l'ai déjà fait, donc je sais que cet objet d' événement généré automatiquement possède une propriété appelée clé qui nous donne le nom de la touche qui a été pressée touche console, je dois cliquer sur Canvas pour m'assurer qu'il est sélectionné Et lorsque j'appuie sur quelque chose sur le clavier, les noms des touches sont imprimés dans la console. Aujourd'hui, nous allons nous concentrer sur les flèches directionnelles. Donc flèche gauche, flèche droite, flèche bas et flèche haut. Je souhaite enregistrer ces valeurs clés dans dernière propriété clé de la ligne 28 de l'objet principal du jeu. Nous avons une référence à l'objet principal du jeu ici à la neuvième ligne. Mais lorsque je consulte ce jeu depuis l'écouteur d'événements, nous remarquons que la référence renvoie une valeur indéfinie C'est parce que cette fonction de rappel oublie qu'elle a été initialement définie ici dans la méthode du constructeur sur la classe du gestionnaire d'entrée Je veux que la fonction se souvienne, je veux limiter sa portée de manière à ce qu' une référence à ce mot-clé représentant dans ce cas cet objet de gestionnaire d'entrée ainsi qu' accès à cette propriété de jeu soient disponibles depuis cette fonction de rappel sur l'écouteur d'événements enfoncé chaque fois que cet écouteur d'événements s' écouteur d'événements s'exécute Later Je veux m'assurer que cette fonction n'oublie jamais qu'elle a été initialement définie à l' intérieur d'un objet Je peux utiliser la méthode de liaison Javascript pour le faire, ou je peux simplement utiliser la fonction ES à six flèches. Oui, les fonctions à six flèches ne lient pas leur propre fonction, mais elles héritent de celle de la portée parent C'est ce que nous appelons le cadrage lexical. La portée de la fonction de flèche dépendra toujours de l'endroit dans notre base de code où elle a été initialement définie par rapport à sa portée lexicale d'origine Dans notre cas, il a été défini ici dans cette méthode de constructeur Il aura donc toujours accès à cette propriété du jeu de points et à toutes les autres propriétés que nous pourrions définir dans ce constructeur Plus tard, lorsque je refactoriserai cette fonction de rappel en une fonction étroite, nous pourrons consolo did Et on voit qu'il pointe vers l'objet principal du jeu. Et toutes ses propriétés y sont visibles, y compris la dernière clé, si je consolo la dernière valeur clé de la ligne 28, elle est initialement définie sur undefined Nous prenons la propriété clé de objet de l' événement et je la lui assigne comme ceci. Désormais, la propriété de la dernière touche de la classe de jeu principale garde toujours une trace de la dernière touche pressée. J'ai également besoin de savoir quand la dernière clé a été publiée. Je crée un autre écouteur d'événements, cette fois pour l'événement key up Nous stockons maintenant le nom de la dernière touche qui a été enfoncée ou relâchée. Le problème est qu'il enregistre simplement le nom de la clé. J'ai besoin de savoir si cette touche a été enfoncée ou relâchée. Je vais concaténer la lettre majuscule P à l'intérieur événement key down pour indiquer que la touche correspondant à ce nom a été pressée J'ajouterai ensuite un R majuscule devant le nom de clé dans l'événement keyup afin que nous sachions que cette clé a été publiée Maintenant que nous obtenons ces valeurs dans la console, vous pouvez voir la valeur de ce gamet à points La dernière propriété clé est en train de changer. Nous appuyons sur la flèche ici et nous relâchons la flèche juste ici. Je peux retirer la console. D'accord. Maintenant que nous savons que cela fonctionne sur l'objet principal du jeu, nous avons défini la dernière propriété clé et nous avons créé une instance de la classe de gestionnaire d'entrée Au fur et à mesure que la classe de gestionnaire d'entrée est initialisée, nous appliquons une touche vers le bas et activons les écouteurs d'événements Cela mettra à jour dynamiquement dernière propriété clé afin que notre objet de jeu et tous les objets qui y sont connectés sachent toujours quelle touche a été enfoncée ou relâchée. Nous utiliserons ces valeurs pour contrôler le personnage du joueur, l'ourson hibou. Définissons-le ici. 42. Personnage de joueur: Tout d'abord, nous devons le connecter à l'objet principal du jeu. Nous nous assurons qu'il attend une référence à l'objet du jeu en tant qu'argument, nous le convertissons en propriété de classe comme d'habitude. Commençons par lui donner une largeur et une hauteur de 100 pixels. Sa position initiale sera de 200 pixels à partir du bord gauche et à 200 pixels du haut. Je lui donne une méthode de dessin pour le dessiner sur toile. Il attendra le contexte comme argument pour spécifier l' élément du canevas sur lequel nous voulons dessiner. Prenez cette variable de contexte et j' appelle la méthode du rectangle Phil intégrée. Le rectangle Phil attend une largeur et une hauteur x, y. Je lui transmets donc les propriétés du constructeur Owl Bear. Nous voulons d'abord dessiner un rectangle noir représentant le hibou, comme nous l' avons fait avec la classe Input Handler Je souhaite créer automatiquement une instance de l' objet Owl Bear Lorsque je crée une instance de la classe de jeu principale, je l'instancie ici dans constructeur de classe et je l'assigne à une propriété J'appelle ce hibou un ours sur la ligne 20, je vois qu'il s'attend à du gibier comme argument Je lui passe ce mot clé parce que nous sommes dans cette classe de jeu. classe de jeu aura une méthode spéciale que j'appelle render pour mettre à jour et dessiner tous les objets du jeu sur le canevas. Je prends Oil Bear de la ligne 42 et j'appelle sa méthode de dessin associée de la ligne 27. Cette méthode attend le contexte comme argument, qui est ce CTX de la troisième ligne Je dois le transmettre. J'appellerai toujours cela le contexte. Il sera attendu comme argument par la méthode de rendu principale, nous le transmettons à la méthode draw sur Owl Bear. Je prends un jeu, j'appelle sa méthode de rendu à partir de la ligne 44, et je lui passe CTX à partir de la ligne trois comme argument auquel un contexte de nom de variable sera attribué et transmis si nécessaire Parfait. Nous dessinons notre ourson hibou. Cela ressemble à un simple carré noir car c'est ce que nous avons défini ici dans la méthode draw on owl bear class. Faisons en sorte que ça bouge. Je lui donne une méthode de mise à jour personnalisée pour chaque image d'animation. Je veux que X augmente d'un, en le faisant marcher vers la droite. Nous devons réellement appeler cette méthode depuis le rendu interne de la classe de jeu. Ici, je supprime cette console pour voir réellement le mouvement Nous devons appeler cette méthode de mise à jour encore et encore. appeler depuis le rendu une seule fois lors du chargement de la première page, comme nous le faisons ici, n' animera rien. Nous aurons besoin d'une boucle d'animation. Je crée une fonction personnalisée. J'appelle par exemple animate inside. J'ai lancé cet appel de rendu. Pour le faire en boucle, j'appelle la méthode du cadre d'animation de demande intégrée . Cette méthode mettra à jour notre page Web avant la prochaine peinture en exécutant un code dans une fonction, nous le passons en argument Si je lui passe animate le nom de sa fonction parent, cela créera une boucle d'animation sans fin Animate est appelé. Il appelle Render pour dessiner et mettre à jour notre demande d'ourson hibou. Le cadre d'animation déclenchera à nouveau l'animation, sorte que le cycle se répétera cadre d'animation de la demande se trouve sur l'objet de fenêtre représentant la fenêtre du navigateur. Mais on peut aussi l'appeler directement comme ça. Sans mettre window.devant. Il est préférable d'utiliser un cadre d'animation de demande pour l'animation plutôt que d'utiliser une demande d'intervalle défini. L'image d'animation ajuste les images par seconde au taux de rafraîchissement de votre écran et génère également automatiquement un horodatage Nous en aurons peut-être besoin plus tard pour déclencher l'animation. J'appelle simplement animate. Comme si ce gentil joueur se déplaçait vers la droite, il laissait des traces Nous devons nous assurer de supprimer tous les dessins du canevas entre chaque boucle d'animation. Je le fais en appelant la méthode intégrée du rectangle clair. Je souhaite effacer l'ensemble du canevas à partir de la coordonnée 002, largeur du canevas et de la hauteur du canevas. Nous avons maintenant un carré noir en mouvement représentant le personnage du joueur. Parfait. Il se déplace vers la droite car ici, dans la méthode de mise à jour de la classe Alber, qui est notre joueur, nous augmentons position horizontale x d'une pour chaque image d'animation Je lui donne une propriété que j'appelle vitesse X. Au départ, je l'ai mise à zéro. Nous aurons également besoin de la vitesse Y, la vitesse verticale pour les mouvements de haut en bas. N'oubliez pas que nous sommes en train de créer un personnage contrôlé par clavier capable de marcher dans quatre directions. Je vais augmenter ce point x la valeur actuelle de la vitesse x. Par exemple, cette coordonnée verticale y du hibou augmentera de la valeur de la vitesse Y. C'est génial car je peux lui donner valeur positive pour un déplacement vers la droite, une valeur négative pour un déplacement vers la gauche Je peux le faire bouger plus rapidement en lui donnant une valeur plus élevée par image d'animation. Ici, ce nombre correspond aux pixels par image d'animation. Une valeur positive de la vitesse Y fera descendre le joueur. Une valeur négative le fera monter. Une valeur positive en X et en Y le fera descendre, n'est-ce pas ? Nous pourrions facilement l'utiliser pour des mouvements dans huit directions. Comme vous pouvez le voir ici à la ligne sept, nous avons la classe Input handle qui capture les saisies au clavier. Il transforme les noms des touches par défaut pour indiquer si la touche a été enfoncée ou relâchée. En pré-attente ou en R devant le nom réel de la clé. Il enregistre la valeur de la dernière touche qui a été pressée ou relâchée ici à la ligne 46. À l'intérieur de ce point, dernière propriété clé de la classe de jeu principale. Parce que je fais référence à l'ensemble de cette classe de jeu lorsque je crée Alber on line 48 L'objet Alber a accès à la dernière valeur clé grâce à cette référence au jeu de points ici sur la ligne 21 Je peux dire que si ce jeu fonctionne, dernière touche est la flèche gauche. Si vous appuyez sur la flèche gauche, réglez la vitesse x sur moins un pour que le personnage se déplace vers la gauche dans le sens négatif sur l'axe horizontal x. Si je clique sur le canevas et que j' appuie sur la flèche gauche, nous nous déplaçons parfaitement. Lorsque je relâche la touche, le joueur ne s'arrête pas là. Je peux constater que nous saisissons la valeur pour la presse et les communiqués. Je peux dire L, régler la vitesse x à zéro. Maintenant, nous pouvons nous déplacer vers la gauche et nous pouvons nous arrêter. Je pourrais également créer une méthode de réglage de vitesse qui, chaque fois qu' elle est appelée, définira la vitesse x et la vitesse Y. Celles-ci lui seront transmises en tant qu'arguments Nous prenons ces arguments et nous mettons à jour les propriétés de classe à partir de la ligne 26.27. Maintenant, je peux remplacer cette ligne par cette vitesse définie Et je lui donne moins un pour la vitesse x et zéro pour la vitesse y. Dans l'instruction L, j'ai réglé les vitesses horizontale et verticale à zéro. Il est préférable d'avoir une variable de vitesse maximale globale plutôt que de coder en dur un et moins un ici. Si cette vitesse doit être dynamique, joueur peut bénéficier d'une augmentation de vitesse temporaire. Ou peut-être que le joueur se déplace plus lentement en rampant et en rôdant Pour ce faire, nous définissons la propriété de vitesse maximale. Nous le fixons à trois pixels par image d'animation, et nous le remplaçons ici. Développons cette déclaration. Je vais également vérifier L si la dernière touche de ce point est enfoncée avec la droite R, comme ceci. Dans ce cas, nous réglons la vitesse x sur plus la vitesse maximale y sur zéro. Nous pouvons maintenant nous déplacer à gauche et à droite et nous arrêtons de bouger lorsque la touche RO est relâchée. Perfectionnez un autre bloc L if. Faites attention à la syntaxe et aux crochets. Il est très facile de rater un crochet et casser toute la base de code en procédant ainsi. Lorsque nous appuyons sur la touche R, nous appelons « set speed ». Nous réglons la vitesse x à zéro et la vitesse Y à moins vitesse maximale parce que nous voulons nous déplacer vers le haut dans le sens négatif sur l'axe vertical Y. Nous faisons un autre L si nous bloquons si dernière touche est d'appuyer sur la flèche vers le bas comme ceci. Nous réglons la vitesse x à zéro et la vitesse y à la vitesse maximale. Nous pouvons également nous déplacer vers la gauche, droite, le haut et le bas. Je veux m'assurer que le joueur ne peut pas quitter le canevas. Je dois définir des limites horizontales. Si la position horizontale x du joueur est inférieure à zéro , remettez-la à zéro, c'est la limite gauche. Sinon, si la position horizontale des joueurs est supérieure à celle de ce jeu avec la largeur de la zone de jeu, ce jeu vient d'ici. De là, nous naviguons vers cette propriété. À la ligne 64, la position actuelle du joueur est supérieure à la largeur de la partie moins la largeur du joueur définie à la ligne 22. Cela signifie que le bord droit du rectangle du joueur touche le bord droit du canevas. Assurez-vous que le joueur ne peut plus se déplacer vers la droite. Ainsi, je vais augmenter la vitesse du joueur à dix pixels par image d'animation. Vous pouvez désormais vous déplacer vers la gauche et vers la droite pour tester les limites horizontales. Les limites verticales seront légèrement différentes car dans notre monde de jeu, le terrain s'arrête là. Je ne veux pas que le joueur traverse cette zone à moins qu'il ne s'agisse d'une créature volante. Je suppose que ce hibou est définitivement trop lourd pour voler. Je me demande s'il existe des espèces rares de chouettes volantes Nous les rechercherons peut-être plus tard dans la série Nous avons cette zone en haut où je ne veux pas que le joueur puisse marcher. Je crée une propriété de classe appelée top margin. Au départ, je l' ai réglé sur 200 pixels. Mettons-le ici. Ici, nous allons définir des limites verticales. Supposons que si ce point y est inférieur à zéro, y est égal à zéro. Cela créera une limite ici. Le joueur ne peut pas dépasser le bord supérieur du canevas. En fait, je veux que la limite soit plus basse parce que toutes ces œuvres d'art environnementales, je dis zéro, plus cette marge de doop dans le jeu comme celle-ci Je peux supprimer zéro plus ici. Bien sûr, la limite supérieure est maintenant là, 200 pixels du bord supérieur. Nous pouvons nous promener, mais nous ne pouvons plus monter ici. Parfait, cela aura plus de sens visuel lorsque le joueur est un véritable personnage animé, pas simplement un carré noir, nous y arriverons rapidement. La limite inférieure est simple si la position verticale Y du joueur est supérieure à la hauteur du jeu moins la hauteur du joueur. Cela signifie que le bas du rectangle du joueur touche le bord inférieur des canavas Ne le laissez pas descendre plus bas comme ça. Nous allons le tester. Oui, nous avons les quatre limites. Parfait. Transformons ce simple rectangle noir en feuille de calcul animée à quatre caractères 43. 4 feuilles de sprite directionnelles: Je commence par ajouter image de feuille de calcul dans l' index HTML comme ceci Nous procédons de cette façon parce que tout notre Javascript se trouve dans l'écouteur d'événements de chargement Si je place ma feuille de calcul ici, Javascript attendra que ces images soient complètement chargées et disponibles avant de commencer à les animer Vous pouvez télécharger toutes les ressources artistiques du projet dans la section des ressources du projet ci-dessous. Je lui ai donné une idée, sortons-le de son emballage comme ça Vous pouvez voir que nous avons huit lignes d'animation dans la feuille de calcul, quatre directions, et chaque direction comporte un ralenti et une boucle de marche Nous examinerons cela plus en détail dans une minute, masquerons l'image elle-même avec du CSS. Nous voulons le dessiner avec le script Java sur canevas. Vous pouvez voir que tout le code se trouve dans l'écouteur d'événements de chargement Tout ce code contenu ne sera exécuté que lorsque Owl Bear et toutes les autres images auront été complètement chargées ici , dans lorsque Owl Bear et toutes les autres images auront été le constructeur classe Alber, qui est notre personnage de contrôle du joueur Nous ajouterons une référence pointant vers cette image de feuille de calcul en tant que propriété de classe Je l'appelle cette image, et je l'ai définie comme égale à une variable appelée al bear. Cette variable n'a pas été déclarée par nous, mais tous les navigateurs créent automatiquement des références, variables globales générées automatiquement pour tous les éléments dotés d'un identifiant Cet élément possède un identifiant. Nous savons donc que notre navigateur automatiquement généré une variable globale pour celui-ci. Normalement, nous utiliserions get element by ID ici à la ligne 29, mais ce n'est pas obligatoire. Le seul problème est qu'il s'agit d'une variable globale. Alors que nous intégrons des variables globales dans nos classes en ce moment, ces variables risquent constamment d'être écrasées accidentellement Nous allons juste tester si cela fonctionne. Quoi qu'il en soit, je prends le contexte faisant référence à la variable CTX de la troisième ligne J'appelle la méthode d'image de dessin intégrée à Canvas. Draw image attend au moins trois arguments. Je lui passe cette variable globale générée automatiquement qui a été créée à partir de l'identifiant des éléments comme image que nous voulons dessiner. Et je passe ce point x à partir de la ligne 24 et ce point y à partir de la ligne 25 pour indiquer au script Java où nous voulons dessiner l'image sur le canevas. Nous dessinons maintenant la feuille de calcul complète à ces coordonnées x et y. Nous pouvons nous déplacer à l'aide des touches fléchées. En raison de la logique que nous avons écrite plus tôt, il est plus sûr d'utiliser get element by ID ici. Alors allons-y. J'utilise cette image à points ici. OK, ça marche toujours. Bien pratique pour animer n'importe quelle feuille de calcul, nous devons connaître les dimensions d' une seule image d'animation dans cette feuille Je vais les mettre dans des variables distinctes. J'appelle le premier sprite width, et je l'ai réglé sur 200 pixels. La hauteur du sprite sera également de 200 pixels. Si vous utilisez une autre feuille de sprites, vous pouvez calculer la largeur du sprite en divisant la largeur de l'ensemble de la feuille de sprites par le nombre hauteur du sprite est la hauteur de l'image complète de la feuille de sprites divisée par le nombre de lignes Dans ce cas, les propriétés de largeur et de hauteur seront les mêmes que celles de largeur et de hauteur du sprite Mais les séparer peut être une bonne pratique, car nous pouvons ensuite utiliser mise à l'échelle ou la randomisation des tailles ici sans affecter ces valeurs qui doivent toujours rester les mêmes Pour recadrer correctement les cadres individuels de la feuille de sprites, Draw Image est disponible en trois versions La première version attend trois arguments, nous venons de le faire ici à la ligne 35. La deuxième version prend cinq arguments, quatrième et cinquième arguments facultatifs définissent la largeur et la hauteur de l'image et l'image sera étirée ou comprimée pour s'adapter à ces dimensions. Maintenant, je comprime l' intégralité de la feuille de calcul massive dans une zone de 200 fois 200 pixels La troisième version de la méthode draw image attend neuf arguments pour nous donner le meilleur contrôle sur l' image que nous voulons dessiner. C'est la version que nous devons utiliser pour animer notre feuille de calcul Ces neuf arguments sont l'image que nous voulons dessiner. Source x, source Y, largeur de source et hauteur de source, la zone que nous voulons recadrer à partir de l'image source. Les quatre derniers arguments sont appelés destination X, destination Y, largeur de destination et hauteur de destination. Cela définira l'endroit sur le canevas sur lequel nous voulons dessiner cette image recadrée Disons que je veux juste recadrer le cadre en haut à gauche. Je vais recadrer de la coordonnée 00 à la largeur du sprite. Et les valeurs de hauteur des sprites que nous avons définies exactement de la même taille qu' une seule image dans notre feuille de calcul, dans ce cas 200 fois 200 pixels Bien, nous utilisons la méthode de dessin d'image pour recadrer un seul cadre. Je peux multiplier la largeur du sprite ici par un nombre et la hauteur du sprite ici également Maintenant, j'ai un moyen de contourner la feuille de sprite d'une image à l'autre. C'est 1100 ? Est-ce que c'est 1200 ? Est-ce un cadre ? Ce numéro navigue horizontalement. Cet autre chiffre déterminera quelle ligne de la feuille de sprites nous nous trouvons Vous pouvez voir que nous pouvons passer à une ligne d'animation différente chaque fois que je change ce numéro. Je vais mettre ces valeurs dans Class Properties Frame X qui gérera la navigation horizontale par sprites Le cadre Y sera destiné à la navigation verticale avec des sprites. Encore une fois, lorsque le cadre X et le cadre Y ont la valeur 00, nous affichons le cadre en haut à gauche. Je peux modifier ces valeurs pour parcourir la feuille de calcul. Maintenant que nous avons compris comment ces arguments ont été transmis à la méthode du dessin pour recadrer des cadres individuels, nous pouvons réellement animer notre feuille de calcul et donner vie à ce puissant hibou Commençons par simplement animer une seule ligne pour chaque image d'animation. Si l'image X est inférieure au nombre maximum d'images, dans ce cas, le nombre d'images maximum sera le nombre d' images par ligne, 30. Si l'image X est inférieure à 30, continuez à augmenter l' image X d'un L, ce qui signifie qu'elle est égale ou supérieure à 30, remettez l'image X à zéro pour qu'elle puisse recommencer à tourner. Bien, nous animons cette ligne, car ici nous réglons l' image Y sur trois Si je le mets à zéro, nous animons cette ligne Si je change ce numéro, nous animons différentes lignes Nous voulons échanger ces lignes d'animation en fonction de deux choses. Dans quelle direction marche le joueur Marche-t-il ou se tient-il simplement debout ? Si nous avions un personnage complexe doté de multiples attaques , etc., je suggère de créer un schéma de conception d'états comme je l'ai fait dans la classe des coureurs infinis. Dans ce cas, la logique du mouvement et de l'animation est suffisamment simple pour être gérée ici dans la méthode de mise à jour. Nous pourrons toujours l'étendre à un modèle de design d'état plus tard si nous décidons d'ajouter d'autres mouvements de joueurs. Laissez-moi vous montrer que nous définissons ici la vitesse du joueur en fonction des quatre touches fléchées qui ont été enfoncées vers la gauche, la droite, le haut ou le bas. Copions ce bloc de code. Faites très attention aux crochets, il est facile d'en manquer un et de déchiffrer votre code. Si vous vous souvenez, ici, nous gardons trace des touches qui ont été enfoncées et relâchées. Les touches enfoncées commencent par un P majuscule, les touches relâchées commencent par une majuscule R. Comment faire ? Je pense que cela devrait fonctionner. Lorsque nous appuyons sur la touche flèche gauche, nous voulons animer cette ligne Ce cadre de points y est égal à trois lignes d' animation qui marchent vers la gauche. Lorsque nous relâchons la flèche gauche comme ceci, nous définissons le cadre y22 Nous voulons simplement rester les bras croisés vers la gauche. Nous allons le tester. Je dois régler la vitesse sur 00 lorsque nous publierons ici. C'est mieux quand on appuie sur la flèche, non ? Je veux animer la marche, c'est vrai . Cette ligne, ce cadre à points, compte cinq Je copie ce LF, en faisant attention aux crochets. Nous passons à R ici lorsque nous relâchons la flèche, touche droite. Nous avons réglé la vitesse sur 00. Et nous avons réglé le cadre Y24, Idle, à droite. Animation. Parfait. Nous avons un personnage qui peut marcher à gauche et à droite, et la logique que nous venons d'écrire naviguer correctement dans la feuille de calcul Nous marchons et nous sommes debout. Le joueur est animé et réagit correctement aux entrées du clavier. Bon travail. Faisons-le également pour les mouvements verticaux, de haut en bas. Lorsque nous appuyons sur la flèche vers le haut, nous voulons que le joueur s'éloigne du cadre de la caméra par sept. Je copie ce bloc de code. Lorsque nous relâchons la flèche vers le haut, nous animons l'image par six et nous réglons la vitesse sur 00 Nous pouvons marcher à gauche, juste en haut. Lorsque nous appuyons sur la flèche vers le bas, nous voulons animer le cadre Y un. Je copie ce bloc de code. Lorsque nous relâchons la flèche vers le bas, nous animons l'image Y zéro et nous réglons la vitesse sur zéro Nous marchons et animons dans quatre directions. Nous alternons correctement entre l'animation debout et animation de marche pour chacune de ces directions travail incroyable pour créer une idée de profondeur donnant l' impression que le joueur s' éloigne et se dirige vers la caméra. En montant et en descendant, je le fais bouger un peu plus lentement sur cet axe. Regarde à quel point ça fait une différence. On a l'impression qu'il y a plus de profondeur, comme si l'arrière-plan était plus éloigné de la caméra que le premier plan Nous marchons à une vitesse normale, à gauche, non ? Mais de haut en bas, nous marchons un peu plus lentement. Changeons la vitesse maximale à cinq. C'est une grosse et lourde créature. Il devrait se déplacer plus lentement. Je commente le rectangle noir, nous n'en avons pas besoin pour le moment. J'aime vraiment ça. Nous avons une base pour de nombreux jeux différents. Tout ce dont vous avez besoin maintenant, ce sont vos idées créatives. On peut faire tellement de choses différentes avec ça. Au fur et à mesure que vous en apprendrez davantage sur Java Script Canvas et le développement de jeux, il deviendra de plus en plus facile de transformer ces idées en une base de code fonctionnelle. Laisse-moi t'en montrer plus. J'espère que tu en retires de la valeur aujourd'hui. Faites-moi savoir dans les commentaires si vous apprenez quelque chose nouveau, car nous n' utilisons que la dernière touche enfoncée ou relâchée pour contrôler le personnage du joueur. Il existe un problème courant lorsque nous marchons dans une direction, disons que je marche à droite, j'appuie sur la flèche gauche. Le joueur tourne à gauche et ce n' est qu'alors que je relâche la flèche droite. La dernière touche est relâchée vers la droite, ce qui obligera le joueur à s'arrêter brièvement avant que le joueur ne continue à marcher à gauche en maintenant enfoncé la touche gauche. Vous pouvez essayer et vous constaterez que nous aurons ce problème dans n'importe quelle direction, marchez quelque part. Et lorsque vous appuyez sur une touche de direction différente avant de relâcher la précédente, le joueur s'arrête un moment avant continuer à se déplacer dans cette nouvelle direction. Résoudre ce problème est facile. Lorsque nous relâchons la flèche vers la gauche. Nous voulons que ce code ne s'exécute que si la vitesse des joueurs est inférieure à zéro. Arrêtez le joueur et faites-le tourner au ralenti vers la gauche uniquement si la vitesse du joueur actuel est inférieure à zéro, si le joueur se déplace actuellement vers la gauche De cette façon, nous ne pouvons passer au ralenti à gauche qu'en marchant à gauche. Lorsque nous relâchons la flèche droite, nous voulons uniquement arrêter la vitesse de déplacement et animer le ralenti, n'est-ce pas ? Si le joueur se déplace actuellement vers la droite, si sa vitesse x est supérieure à zéro. Je dois également supprimer cette déclaration L ici. Et maintenant, nous résolvons le problème pour les mouvements à gauche et à droite. Faisons la même chose pour les mouvements de haut en bas. N'exécutez ce code que lorsque nous relâchons la flèche vers le haut et en même temps, la vitesse de déplacement des joueurs y est inférieure à zéro lorsque nous relâchons la flèche vers le bas. N'exécutez ce code que si en même temps la vitesse Y est supérieure à zéro. Uniquement lorsque le joueur descend vers la caméra. Maintenant, nous nous déplaçons et le pépin a disparu. Bravo. 44. Comment commander FPS: Si je règle la vitesse maximale sur deux joueurs, les mouvements sont lents, mais l' animation du sprite diffuse des images si vite que le joueur marche sur la lune Les pieds s'animent d' une manière qui ne correspond pas à la vitesse de déplacement et cela donne une très mauvaise apparence Pour résoudre ce problème, vous pouvez contrôler manuellement la vitesse d'animation de la feuille de sprites heure actuelle, nous ne diffusons une nouvelle image d'animation par boucle. Chaque fois qu'une image d'animation de demande est appelée. Créons une fonctionnalité qui nous permettra de définir manuellement images par seconde par seconde pour la vitesse d'animation de notre feuille de sprites Cela peut être fait globalement et nous pouvons définir des FPS pour l'ensemble du jeu. Ou comme je vais vous le montrer maintenant, vous pouvez définir le FPS individuellement pour l'objet du joueur. Peut-être aurons-nous des ennemis plus tard qui auront des feuilles de sprites différentes Et nous souhaiterions peut-être que ces feuilles de sprites soient animées à une vitesse différente Par défaut, le cadre d'animation de la demande s'ajuste automatiquement au rafraîchissement de l'écran. Tarif. Notre jeu fonctionnera plus rapidement pour des écrans à taux de rafraîchissement élevé Comme ces nouveaux écrans de jeu, nous pouvons contrôler que si nous voulons demander une image d'animation, elle possède une fonctionnalité spéciale générer un horodatage à chaque fois qu'elle appelle une fonction d'animation et de transmettre cet horodatage comme argument à la fonction d' animation qu'elle Utilisons-le pour compter les millisecondes entre les images afin de pouvoir définir nos propres images FBS J'ai créé une variable que j'ai appelée la dernière fois, elle se trouvera en dehors de la boucle d'animation comme celle-ci. Au départ, je l'ai mis à zéro. Il contiendra la valeur de horodatage de la boucle d'animation précédente Ainsi, nous pouvons comparer les horodatages actuels et anciens et déterminer le nombre de millisecondes écoulées La valeur est appelée temps delta. temps delta est le nombre de millisecondes qui se sont écoulées entre l'horodatage de cette boucle d'animation et l'horodatage de la boucle d'animation précédente Pour calculer le temps delta, nous savons que nous devons comparer ces horodatages horodatage de la boucle précédente sera conservé dans la dernière variable horaire ici Dans un premier temps, nous l'avons mis à zéro avant de commencer à générer des horodatages Comme je l'ai dit, le cadre d'animation de la demande transmet argument d' horodatage généré automatiquement à la fonction Si vous êtes débutant, imaginez qu'il est généré et transmis ici comme ça. Au moment où l'image d'animation de la demande déclenche cette fonction, nous attribuons un nom de variable à cet horodatage généré automatiquement Ici, je vais simplement l'appeler timestamp orthographié avec une majuscule S. Commentons cela et consoloquons l' Juste pour que je puisse voir quel format nous obtenons, vous pouvez voir que c'est en millisecondes La première valeur est littéralement le nombre de secondes écoulées depuis le début de la boucle, 45678 C'est l'horodatage que je supprime. L'heure delta de la console est l'horodatage de cette boucle d'animation moins la dernière fois indiquée sur la ligne 113, qui contiendra de cette boucle d'animation moins la dernière fois indiquée sur la ligne 113, toujours une valeur pour horodatage de la boucle d'animation précédente Une fois que nous avons calculé le temps delta, nous avons défini la dernière heure sur l'horodatage. Ainsi, ce nouvel horodatage issu de cette boucle peut être utilisé comme ancienne valeur d'horodatage dans la prochaine boucle d'animation suivante Nous avons maintenant l'heure delta. Il nous indique le nombre de millisecondes nécessaires à notre ordinateur pour diffuser une image d'animation Mon écran se rafraîchit à environ 60 images par seconde. Mon temps delta est d'environ 16,6 millisecondes. C'est parfait. Obtenez-vous le même delta ou obtenez-vous une valeur complètement différente ? Faites-le moi savoir dans un commentaire. Cela dépendra du taux de rafraîchissement de votre écran et en partie également de la puissance de votre machine. Les machines les plus faibles auront un temps delta plus élevé. Vous pouvez voir qu'ici les premières valeurs de temps delta ne sont aucune, pas un nombre. Comme nous exécutons animate pour la première fois ici dans la première boucle, cet horodatage n'est pas défini Aucun appel d'image d'animation de demande n'a été généré automatiquement auparavant . Pour que nous puissions résoudre ce problème, je dois m'assurer de passer le premier horodatage ici, juste pour éviter un non, pas une valeur numérique dans la boucle initiale. Sinon, cela pourrait nous poser des problèmes ultérieurement en fonction de la manière dont vous souhaitez utiliser vos valeurs de temps delta. L'horodatage initial sera égal à zéro. Vous pouvez voir que les valeurs sont omniprésentes au début, mais elles se stabilisent ensuite rapidement aux alentours de 16,6 au fur et à mesure que notre boucle d'animation se répète C'est l'idéal. Je supprime la console, je transmets cette valeur de temps delta à la méthode de rendu sur la classe de jeu Je m'assure que cette valeur est attendue ici et je peux la transmettre n' importe où dans notre jeu. Maintenant, partout où nous en avons besoin. Je le passe à la méthode de mise à jour sur classe Alber car nous voulons utiliser temps delta pour contrôler les images FPS par seconde d'animation de sprites Là, je passe le temps delta pour mettre à jour méthode et je dois m' assurer que c'est prévu. Ici, à la ligne 44, nous sommes maintenant dans la classe Alber et nous pouvons utiliser la valeur du temps delta ici pour tellement de choses différentes Pour contrôler le nombre d'images par seconde de l'animation des sprites, je vais créer trois variables auxiliaires, les propriétés de classe, le FPS sera Essayons d'animer 30 images par seconde et voyons à quoi cela ressemble L'intervalle entre les images sera de 1 000 millisecondes divisé par 30. Cela déterminera le nombre de millisecondes qui doivent s'écouler avant de passer à l' image suivante de la feuille de sprites Le Frame Timer sera le compteur. Il accumulera le temps delta encore et encore au fur et à mesure que notre boucle d'animation se déroulera Lorsqu'il atteint la valeur et l'intervalle d'images, lorsque suffisamment de millisecondes se sont accumulées, nous déclenchons certaines actions périodiques Dans ce cas, nous diffuserons la prochaine image d'animation. La même technique peut également être utilisée pour ajouter un nouvel ennemi au jeu ou pour un autre événement que vous souhaitez voir se produire dans un intervalle spécifique. Il s'agit d'une technique importante à comprendre. Écrivons la logique et expliquons-la lorsque nous verrons le code. Ce ne sont que quelques lignes. Je veux uniquement exécuter ce code qui échange entre les images de sprites lorsque suffisamment de millisecondes Si le délai d'images est supérieur à l'intervalle d'images, animez uniquement la feuille de sprites Sinon, continuez à augmenter le délai d'image par delta. Ce code animera la feuille de calcul à partir d'ici. Lorsque cela se déclenche, nous remettons également chronomètre à zéro afin qu'il puisse être à nouveau pris en compte pour le prochain événement périodique dans la boucle d'animation. Nous calculons le temps delta, Nous calculons le temps delta la différence entre l'horodatage de la actuelle et celle de la boucle d'animation précédente. temps delta est le nombre de millisecondes nécessaires notre ordinateur pour traiter une image d'animation Le temporisateur d'images commence à zéro et ajoute plus de temps delta au fur et à mesure que la boucle d'animation s'exécute jusqu'à ce qu'il soit supérieur à l'intervalle d'images. L'intervalle d'images est le point d'arrêt qui, lorsqu' il est atteint, déclenche notre événement périodique Lorsque nous l'atteignons, nous gérons animation des sprites et nous remettons le chronomètre à zéro afin qu'il puisse être compté à nouveau pour la prochaine image d'animation diffusée périodiquement Je sais que c'était beaucoup, mais cette technique est très importante. Il deviendra facile à comprendre lorsque vous l'utiliserez plus souvent. Croyez-moi maintenant, le personnage s'anime plus lentement, juste à cause de l'échange de sprites et non de la vitesse de déplacement réelle sur la Vous pouvez vraiment voir que lorsque je règle le FPS à deux images par seconde, il glisse toujours facilement sur le canevas à 60 images par seconde. Mais nous limitons la rapidité avec laquelle les images suivantes sont diffusées dans des feuilles de sprites J'espère que cela fait clairement la différence. Je peux essayer d'autres valeurs comme FPS. Je dois expérimenter un peu et trouver la bonne valeur qui permettra au lex se déplacer à la vitesse naturelle lorsque le joueur se déplace sur le terrain gazonné. 50, c'est encore un peu dérapant. 60, nous ne prenons pas en compte les valeurs restantes du temps delta chaque fois que nous déclenchons notre événement périodique Même si j'ai dit 60 FPS, le FPS réel serait inférieur à cela. Pour les besoins d'un projet comme celui-ci, c'est parfaitement bien. Nous avons une valeur que nous pouvons augmenter ou diminuer pour contrôler l'animation des sprites Il remplit bien son objectif. Je peux simplifier cette ligne de code et utiliser opérateur ternaire pour écrire tout cela sur une seule ligne Laissez-moi vous montrer que c'est facile. L'opérateur ternaire est le seul opérateur Java Script à trois opérandes Nous l'utiliserons comme une simple instruction d'une ligne si nous avons une condition à évaluer. Nous vérifions si l'image X est inférieure à la trame maximale. S'il s'agit d'un point d'interrogation, augmentez le cadre X d'un, L remettez le cadre X à zéro. Maintenant, cette seule ligne de code fait la même chose que cette instruction L if multiligne. Vous pouvez utiliser l'une ou l'autre des syntaxes. Je voulais juste te montrer. 45. Objets de jeu positionnés aléatoirement: Créons des objets et distribuons-les au hasard dans le monde du jeu. Je crée une classe, je l'appelle objet. Comme d'habitude, il s'attend une référence à l'objet principal du jeu à partir de la ligne 111 comme argument indiquant que nous avons accès à toutes les propriétés importantes. À partir de là, nous convertissons cette référence en propriété de classe. Comme nous l'avons fait avant. Méthode Draw, nous attendrons le contexte comme argument. À l'intérieur, nous appelons la méthode de dessin d'image intégrée. Je veux vous montrer comment étendre les classes et tirer parti de l'héritage, qui est l'un des grands principes de la programmation orientée objet. Comment pouvons-nous l'utiliser pour réduire la répétition du code. Je crée une classe appelée Busch qui étend la classe d'objets à partir de la ligne 102 Il aura également un constructeur. Je crée une autre classe. J'appelle plante encore une plante, j'appelle herbe. Nous avons la classe d'objet principale. Nous avons trois classes, Bush, plant et Grass, qui étendent cette classe d'objets. L'objet est appelé classe parent, également appelée superclasse Bush, Plant et Grass sont des cours pour enfants, également appelés sous-classes. Si j'utilise une propriété ou une méthode dans l'une de ces classes enfants, cette propriété n'est pas définie dans cette sous-classe Le script Java va le rechercher automatiquement sa classe parent, sur l'objet. De cette façon, je ne peux définir cette méthode de dessin qu'en une seule fois. Et toutes les classes enfants qui étendent cette classe parent y auront automatiquement accès, elles héritent de cette méthode Nous pouvons faire quelque chose de similaire avec les propriétés du constructeur en utilisant le super mot-clé que je vais vous montrer dans une minute. classe Object contiendra toutes les propriétés et méthodes partagées entre toutes les classes enfants. Busch, Plant et Grass contiendront des propriétés spécifiques uniquement à cette sous-classe particulière Par exemple, chaque sous-classe aura une image différente, mais toutes passeront cette image différente à la même méthode de dessin à partir de 907. Faisons-le. Avant de pouvoir utiliser ce mot clé dans le constructeur de la classe enfant, je dois déclencher le constructeur sur sa classe parent Quand je dis super comme ça ici, cela signifie que je veux exécuter un constructeur du parent de cette classe La classe parent est également appelée superclasse. À la ligne cent trois, je peux voir que le constructeur de classe d'objets attend le jeu comme argument Je transmets cette référence en même temps que je la convertit également en propriété de classe sur la classe Bush. Comme cela, dans la méthode de dessin d'image partagée que je lui ai transmise l'image didot x et dis.yi peuvent également lui donner la largeur dist et Si je veux redimensionner les images comme vous pouvez le voir, aucune d'entre elles n'est présente dans ce cours. Je veux que chaque sous-classe ait une image différente, et nous devons connaître la taille de cette image pour calculer sa position aléatoire Je vais devoir mettre toutes ces propriétés sur chaque sous-classe séparément. Commençons par Bush. Cette image à points sera un document obtenu par élément par identifiant. Ici, dans l'index HTML, je dois créer cet élément d' image comme d'habitude, vous pouvez télécharger les images dans la section des ressources du projet ci-dessous. Je l'ai mis ici, l'identifiant sera Bush, un autre avec un identifiant de plante comme celui-ci. Le dernier sera du grass dans le style CSS. J'utilise leurs identifiants pour masquer ces images. Nous voulons les dessiner sur une toile, et non comme de véritables éléments d'image sur la page Web. L'identifiant est Bush. Je duplique ce code d'identification. Ici, ce sera prévu et ici, de l'herbe. J'essaie de garder le nom simple et propre. Je ne veux pas vraiment redimensionner les images, mais si nous voulons laisser l' option de mise à l'échelle ouverte, il vaut peut-être mieux que je définisse propriétés de largeur et de masquage d'image séparément. Même si, à ce stade, ils auront la même valeur. Je redimensionne déjà les images pour qu'elles soient de la même taille que celles que nous allons dessiner sur Canvas, ce qui est une bonne pratique. L'image de Bush est de 216 à 100 pixels. Je pourrais également définir ces propriétés sur une ligne comme celle-ci. C'est à vous de décider. position horizontale sera une valeur aléatoire comprise entre zéro et la largeur de la zone de jeu moins la largeur de l'image elle-même. Cela nécessitera probablement quelques ajustements. Voyons voir, la position verticale en y ne partira pas de zéro, elle partira de la marge supérieure. Et à partir de là, une valeur aléatoire comprise entre zéro et la hauteur de la zone de jeu moins la hauteur de l' image moins la marge supérieure. Je pense que lorsque nous commencerons à les dessiner, nous verrons si je dois apporter des ajustements ici. Nous allons le tester. Dans la classe de jeu principale, je crée une propriété appelée Number of Plants. Créons dix objets végétaux positionnés de manière aléatoire. Je crée une méthode initialisée qui ne s'exécutera qu'une seule fois lors du chargement de la première page et qui positionnera aléatoirement les objets à l'intérieur Je crée une boucle à quatre boucles. Il sera exécuté dix fois. Chaque fois qu'il fonctionne, nous créons une plante. Je crée ici un tableau vide qui contiendra tous les objets de la plante. Chaque fois que les quatre boucles s'exécutent, je prends ce tableau de plantes, moi, nouvel objet Bush à l'intérieur de la ligne 111, je peux voir que le constructeur de classe Bush attend le jeu comme argument Je lui passe ce mot clé parce que nous sommes dans cette classe de jeu ici. Après avoir créé une instance de la classe de jeu 160, je peux appeler cette méthode d'initialisation Il fonctionnera et remplira le tableau des plantes avec dix instances aléatoires de la classe Bush Si je veux les afficher sur le canevas, je dois appeler leur méthode de dessin. Je vais le faire depuis le rendu interne. Je prends des plantes et pour chaque objet végétal du tableau, j'appelle leur méthode de dessin associée à partir de la ligne 106. Cette méthode s'attend à un contexte. Je transmets cette référence contextuelle. Super, je dessine dix buissons positionnés au hasard. Je vais ici, je vais copier toutes ces propriétés spécifiques à la classe Bush, et je les copie ici dans la classe plant. Je vérifie que la largeur de l'image est de 212 pixels, la hauteur de 118. Je le copie à nouveau, et la largeur de l'herbe sera 103 et la hauteur de 183 pixels. Bien, nous avons défini une classe d'objet parent dans laquelle nous pouvons placer toutes les propriétés et méthodes partagées, ainsi que trois sous-classes appelées Bush Plant et Grass qui étendent la classe parent Pour vérifier rapidement si ces classes fonctionnent, je peux simplement échanger le nom de la classe ici à la ligne 168. L'herbe fonctionne, l' usine fonctionne. Comment les répartir aléatoirement et contrôler quelle partie de ces dix plantes générées aléatoirement sera constituée de buissons, herbes ou d'objets végétaux Un moyen simple de le faire est de créer une variable. Ici, j'appelle par exemple randomiser. Il sera égal à mathodtrandom. Nous savons qu'un code aléatoire méthot comme celui-ci renvoie à lui seul une valeur aléatoire 0 à 1. Disons que je veux environ 30 % de ces objets soient des instances de la classe plant Je dis que si random Ize est inférieur à 0,3 L, si randomize est inférieur à 0,6 lorsque les mathématiques sont aléatoires entre 0,3 et 0,6, nous créons une instance de la classe Bush L, ce qui signifie que lorsque Maat lance aléatoirement entre 0,6 et un, nous créons Cela ne fonctionne pas parce que cela doit se trouver à l'intérieur de la boucle à quatre, car nous voulons lancer chaque fois que nous créons un nouvel objet, non une seule fois pour les dix objets. 46. Superposition et ordre de dessin dans des jeux 2D: Parfait. Nous étendons une classe pour créer trois objets de jeu différents positionnés aléatoirement. Bon travail. Comme vous pouvez le constater, la façon dont ces objets sont positionnés et la façon dont le jeu se superpose n'ont pas vraiment de sens visuel hibou est dessiné d'abord sur la ligne 162, puis toutes les plantes sont dessinées, après les plantes soient toujours au-dessus d'un ours Si je l'échange, les plantes sont toujours derrière l'ours. Puisque nous dessinons tout sur le même élément du canevas, ce qui est dessiné en premier est derrière, et ce qui a été dessiné après se trouve en haut devant. Je souhaite dessiner des objets dans un ordre précis en fonction de leur position verticale. Plus précisément, en fonction de la position verticale de leur bord inférieur. Parce que chaque objet a une hauteur différente, il faut s'assurer qu'ils sont alignés d'une manière logique et visuelle. Et pour que notre personnage puisse les contourner et être devant et derrière les objets. cas échéant, nous essayons de simuler un monde virtuel dans lequel les plantes poussent depuis le sol. Et où ce hibou marche sur un sol solide en tout temps, même lorsqu'il marche de haut en bas. La superposition doit correspondre visuellement à cela. C'est en fait très facile à réaliser. Je dois juste m'assurer que tous ces objets, donc tous les ours et tous les objets végétaux, sont dans le même ensemble. Pour que je puisse les trier en fonction de leur position verticale. Je crée un autre tableau appelé objets de jeu. Chaque fois que la méthode de rendu s'exécute, je mets un objet Alber à l'intérieur J'ai réparti tous les objets des plantes en bas âge dans cet opérateur de propagation en réseau. telle utilisation nous permet d' étendre un tableau à un autre. Dans ce cas, cela n'a pas beaucoup de sens de le faire chaque fois que la méthode de rendu est activée pour chaque image d'animation. Comme nous n'avons qu'Alber et dix plantes statiques, nous aurions pu utiliser cette méthode d' initialisation interne Il serait logique de le faire périodiquement pour construire ce tableau encore et encore. Si d'autres objets sont ajoutés et supprimés à maintes reprises, par exemple des ennemis ou des bonus qui vont et viennent. Nous avons maintenant Alber, les dix plantes au même niveau dans le même tableau Je peux prendre ce tableau pour chaque objet du tableau d'objets du jeu. J'appelle leur méthode de dessin. Lorsque nous faisons cela et que nous combinons différents types d'objets dans un seul tableau, nous devons nous assurer que tous ces objets ont réellement des méthodes de dessin définies dans leurs classes. Attention aux crochets Ici, je peux supprimer ce code. Je vais devoir appeler la méthode de mise à jour et lui transmettre le delta time. Sinon, je vais supporter, je ne bougerai pas et je n' animerai pas. Quand j'appelle Update comme ça, nous dessinons et mettons à jour tous les ours. Lorsque j'essaie de dessiner et de mettre à jour la première plante sur dix, elle est dessinée, mais il n'y a aucune méthode de mise à jour à exécuter, nous obtenons donc une erreur. Je dois ajouter une méthode de mise à jour sur la classe d' objet pour que ce code s'exécute. Nous ne mettons pas vraiment à jour les objets, mais ici nous pouvons avoir quelques animations. Par exemple, les buissons et l'herbe peuvent bouger lorsque le joueur les touche, ce code sera géré dans cette méthode de mise à jour. Je vais laisser ce champ vide pour le moment. Nous avons maintenant la même chose qu'avant, mais tous les éléments qui doivent être superposés dynamiquement sont dessinés et mis à jour depuis le tableau d'objets du jeu. Tous les ours sont les premiers du tableau. C'est pourquoi il est dessiné avant les plantes. Des plantes sont dessinées dessus. Si je les échange, les plantes sont derrière et l'aulber est dessiné en dernier sur le dessus Parce que c'est l' ordre dans lequel chaque méthode parcourt le tableau d'objets du jeu. Pour définir leurs méthodes de dessin, nous voulons trier Alber et les dix plantes de ce tableau en fonction de leur coordonnée verticale y, mais pas en fonction de leur limite supérieure mais de leur limite inférieure Comme nous avons des objets de hauteurs différentes, nous pouvons le faire en utilisant la méthode de tri par tableau intégrée . La méthode de tri trie les éléments d'un tableau place et renvoie la référence au même tableau. Maintenant trié, il prend un argument optionnel. Nous appelons une fonction de comparaison, dans laquelle nous pouvons définir une logique décrivant l'ordre de tri. Si nous ne définissons pas de condition de tri, par défaut, tous les éléments du tableau sont simplement convertis en chaînes et triés en fonction des caractères, des valeurs Unicode. A est le premier élément de comparaison, B représente le deuxième élément. Pour la comparaison, méthode de tri comparera automatiquement chaque élément du tableau à tous les autres éléments. Pour les trier en fonction de nos besoins. Nous voulons que la condition de tri compare la limite inférieure de chaque élément dessiné sur le canevas. C'est donc la position verticale y plus sa hauteur. Comme ça. Je dis de trier tous les éléments par ordre croissant en fonction leur position verticale et de leur hauteur Une fois le tableau trié, nous dessinons des plantes et un hibou dans cet ordre sur toile Et maintenant, tout a un sens visuel. Nous pouvons contourner les obstacles et nous pouvons constater que le personnage du joueur et les plantes sont désormais toujours correctement dessinés devant ou derrière. Vous pouvez étendre ce jeu de différentes manières, créer des champignons qui poussent dans zone jouable pour faire grandir le hibou pendant qu'il les mange Vous pouvez également lui faire éviter dangereux ennemis ou contourner des obstacles épineux Je vous suggère de créer une copie de cette base de code et l' utiliser comme base pour différentes expériences de jeu.