Faire un scrolling 2D dans un jeu JavaScript

Dans un jeu 2D, le niveau dépasse souvent largement la taille de l’écran. Le joueur doit pouvoir avancer dans cet espace sans que toute la carte soit visible en permanence. Le scrolling consiste à déplacer le point de vue pour révéler progressivement le décor, tout en conservant des coordonnées stables pour le personnage, les plateformes et les objets du niveau.

Scrolling 2D

Déplacez le personnage et observez la caméra, la zone morte et le parallaxe.

Flèches gauche/droite ou Q/D
Joueur : 0 px Caméra : 0 px Niveau : 0 px

Télécharger la ressource

Le besoin : afficher un niveau plus grand que la zone visible

Une première scène peut tenir entièrement dans un élément canvas. Le personnage se déplace alors directement entre les bords de l’écran et tous les objets restent visibles. Cette approche devient insuffisante dès que le niveau doit être plus large que la fenêtre de jeu. Réduire toute la carte pour la faire entrer dans le canvas rendrait les éléments trop petits et supprimerait toute sensation d’exploration. Il faut donc distinguer la taille réelle du niveau de la partie actuellement affichée.

Le niveau possède ses propres dimensions et ses propres coordonnées. Le canvas représente seulement une fenêtre ouverte sur ce monde. Le personnage peut ainsi se trouver à plusieurs milliers de pixels du début du niveau alors que sa position à l’écran reste proche du centre. Le scrolling ne déplace pas réellement le niveau : il change la portion du monde convertie en pixels visibles. Cette séparation constitue la base d’une caméra 2D.

Le principe : séparer les coordonnées du monde des coordonnées de l’écran

Chaque élément du jeu conserve une position dans le monde. Une plateforme placée à 1 800 pixels du début du niveau reste toujours à cette position, quelle que soit la caméra. Pour l’afficher, on soustrait simplement la position de la caméra à celle de l’objet. Une plateforme située à 1 800 pixels apparaît donc à 300 pixels de l’écran lorsque la caméra est placée à 1 500 pixels. Cette conversion permet de dessiner tous les objets avec une règle unique.

La caméra ne contient ici qu’une coordonnée horizontale. Sa position représente le bord gauche de la zone visible dans le niveau. Lors du rendu, la formule position écran = position monde − position caméra est appliquée au décor, au joueur et aux objets. Les calculs de déplacement et de collision continuent pourtant d’utiliser les coordonnées du monde. L’affichage peut ainsi évoluer sans modifier la logique du jeu.

Le suivi : laisser le joueur bouger dans une zone morte

Une caméra strictement centrée sur le personnage réagit au moindre déplacement. Le joueur reste alors immobile à l’écran tandis que tout le décor glisse continuellement derrière lui. Ce comportement fonctionne, mais il peut rendre la caméra nerveuse et rendre les petits ajustements difficiles à lire. Une zone morte permet de conserver une partie stable autour du personnage. La caméra ne commence à avancer que lorsque celui-ci dépasse une limite définie dans l’écran.

Dans la démonstration, deux repères définissent cette zone. Le personnage peut se déplacer librement entre eux sans modifier la caméra. Lorsqu’il franchit le repère droit, la caméra avance juste assez pour le replacer sur cette limite. Lorsqu’il revient vers la gauche, le même principe est appliqué dans l’autre sens. Le scrolling devient ainsi plus lisible et laisse au joueur une marge de mouvement naturelle.

Les limites : empêcher la caméra de sortir du niveau

Le suivi du personnage ne suffit pas. Au début du niveau, la caméra ne doit pas afficher une zone vide située avant la carte. À l’autre extrémité, elle ne doit pas dépasser la largeur du monde. Sa position est donc limitée entre zéro et la largeur du niveau moins celle du canvas. Ce calcul garantit que le bord droit de la caméra coïncide au maximum avec le bord droit du niveau.

Le personnage reçoit lui aussi ses propres limites. Sa position ne peut pas devenir négative ni dépasser la largeur du monde. Ces contraintes sont indépendantes de l’affichage : le joueur est limité dans le niveau, puis la caméra est limitée autour de lui. Cette distinction évite de mélanger les règles du monde avec celles de la fenêtre visible. Elle facilite aussi l’ajout ultérieur de murs, de plateformes ou de zones bloquées.

Le rendu : ne dessiner que ce qui peut être visible à l’écran

Un petit niveau peut être entièrement parcouru à chaque image sans conséquence perceptible. Sur une carte plus grande, il devient inutile de dessiner des objets situés très loin de la caméra. La démonstration vérifie donc la position horizontale des plateformes et des éléments de décor avant de les afficher. Un objet est ignoré lorsque son bord droit se trouve avant la caméra ou lorsque son bord gauche se trouve après la zone visible.

Cette sélection réduit le travail de dessin et prépare le code à des niveaux plus importants. Le principe reste simple : les objets continuent d’exister dans le monde, mais seuls ceux qui croisent la caméra sont envoyés au canvas. Cette première optimisation peut ensuite être remplacée par une grille, des secteurs ou un système de tuiles. Pour une ressource pédagogique, le filtrage horizontal suffit à rendre le mécanisme immédiatement compréhensible.

La profondeur : ajouter un effet de parallaxe sans déplacer le monde

Le scrolling devient plus perceptible lorsque plusieurs plans ne se déplacent pas à la même vitesse. Les éléments proches suivent presque entièrement la caméra, tandis que les éléments lointains se déplacent plus lentement. Ce décalage crée une impression de profondeur sans utiliser de perspective réelle. Chaque plan reçoit simplement un coefficient appliqué à la position de la caméra.

Dans la démonstration, le ciel reste fixe, les collines lointaines suivent une petite partie du déplacement et les reliefs proches suivent une part plus importante. Les plateformes et le personnage utilisent le déplacement complet, car ils appartiennent au monde jouable. Le parallaxe ne modifie donc aucune coordonnée réelle. Il agit uniquement au moment du rendu et peut être ajusté ou supprimé sans toucher aux déplacements ni aux collisions.

La boucle : dissocier la mise à jour de l’affichage

Le jeu est organisé autour de deux étapes. La fonction de mise à jour lit les entrées, déplace le personnage et calcule la nouvelle position de la caméra. La fonction de rendu efface ensuite le canvas et dessine la scène à partir de cet état. Cette séparation empêche les calculs de dépendre de l’ordre dans lequel les éléments sont affichés. Elle rend aussi le code plus facile à interrompre, à réinitialiser ou à enrichir.

Le temps écoulé entre deux images est mesuré pour conserver une vitesse régulière. Le déplacement est exprimé en pixels par seconde plutôt qu’en pixels par image. Une baisse de fréquence d’affichage ne ralentit donc pas automatiquement le personnage. Le temps est plafonné pour éviter un déplacement brutal lorsque l’onglet a été masqué ou que l’exécution a été interrompue. La boucle reste volontairement compacte, mais elle reprend les bases nécessaires à un véritable jeu.

Le résultat : une caméra simple, stable et réutilisable

La ressource ne repose sur aucun moteur et n’utilise aucune bibliothèque. Le niveau, le personnage et la caméra sont représentés par quelques objets JavaScript. Le scrolling provient uniquement de la conversion entre coordonnées du monde et coordonnées de l’écran. La zone morte améliore le suivi, les limites empêchent les sorties de carte et le parallaxe renforce la lecture du déplacement.

Cette base peut ensuite accueillir un niveau vertical, une caméra sur deux axes, des plateformes, des collisions ou une carte construite avec des tuiles. La structure reste la même : le monde conserve ses coordonnées, la caméra choisit la zone visible et le rendu applique le décalage. En isolant ces responsabilités dès le départ, le scrolling cesse d’être un déplacement artificiel du décor. Il devient un véritable système de caméra 2D sur lequel le reste du jeu peut s’appuyer.

À lire également

Remonter en haut de page
Gérer les cookies