Guide d'introduction mis à jour pour la création de mondes isométriques, deuxième partie

Ce que vous allez créer

Dans cette dernière partie de la série de didacticiels, nous allons construire sur le premier didacticiel et apprendre à mettre en œuvre des micros, déclencheurs, permutation de niveau, cheminement, suivi de chemin, défilement de niveau, hauteur isométrique et projectiles isométriques..

1. Micros

Les collectes sont des objets qui peuvent être collectés dans le niveau, normalement en marchant dessus, par exemple, des pièces de monnaie, des gemmes, de l'argent, des munitions, etc..

Les données de collecte peuvent être intégrées directement dans nos données de niveau comme ci-dessous:

[[1,1,1,1,1,1], [1,0,0,0,0,1], [1,0,8,0,0,1], [1,0,0, 8,0,1], [1,0,0,0,0,1], [1,1,1,1,1,1]]

Dans ce niveau de données, nous utilisons 8 dénoter une collecte sur une dalle de gazon (1 et 0 les murs et les dalles piétonnières comme précédemment). Cela pourrait être une image de mosaïque unique avec une mosaïque d'herbe superposée à l'image de ramassage. En suivant cette logique, nous aurons besoin de deux états de tuile différents pour chaque tuile qui possède un enlèvement, c’est-à-dire un avec enlèvement et un sans avoir à être montré après que l’enlèvement soit récupéré..

L’art isométrique typique comportera plusieurs mosaïques marchantes - supposons que nous en ayons 30. L’approche ci-dessus signifie que si nous avons N micros, nous aurons besoin de N x 30 mosaïques en plus des 30 mosaïques originales, chaque mosaïque devant avoir une version avec micros et un sans. Ce n'est pas très efficace. au lieu de cela, nous devrions essayer de créer dynamiquement ces combinaisons. 

Pour résoudre ce problème, nous pourrions utiliser la même méthode que celle utilisée pour placer le héros dans le premier tutoriel. Chaque fois que nous rencontrons une tuile de ramassage, nous allons d'abord placer une tuile d'herbe, puis placer la collecte au-dessus de la tuile d'herbe. De cette façon, nous avons simplement besoin de tuiles de lecture N en plus de 30 tuiles accessibles à la marche, mais nous aurions besoin de valeurs numériques pour représenter chaque combinaison dans les données de niveau. Pour résoudre le besoin de N x 30 valeurs de représentation, nous pouvons conserver un pickupArray pour stocker exclusivement les données de collecte en dehors de la levelData. Le niveau terminé avec le ramassage est indiqué ci-dessous:

Pour notre exemple, je garde les choses simples et n’utilise pas de tableau supplémentaire pour les collectes..

Ramasser les micros

La détection des micros s'effectue de la même manière que la détection des mosaïques de collision, mais après déplacer le personnage.

if (onPickupTile ()) pickupItem ();  function onPickupTile () // vérifie s’il existe une reprise dans le retour de la tuile du héros (levelData [heroMapTile.y] [heroMapTile.x] == 8);  

Dans la fonction onPickupTile (), nous vérifions si le levelData valeur de tableau à la heroMapTile coordonnée est une tuile de ramassage ou non. Le nombre dans le levelData tableau à cette coordonnée de tuile indique le type de ramassage. Nous vérifions les collisions avant de déplacer le personnage, mais nous devons vérifier les ramassages après, car dans le cas de collisions, le personnage ne doit pas occuper la place s'il est déjà occupé par la tuile de collision, mais dans le cas de ramassages, le personnage est libre de se déplacer. par-dessus.

Une autre chose à noter est que les données de collision ne changent généralement jamais, mais les données de collecte changent chaque fois que nous récupérons un élément. (Cela implique généralement de changer la valeur dans le levelData tableau de, disons, 8 à 0.)

Cela pose un problème: que se passe-t-il lorsque nous devons redémarrer le niveau et réinitialiser ainsi tous les micros à leur position d'origine? Nous n'avons pas les informations pour le faire, car le levelData Le tableau a été modifié lorsque le joueur a ramassé des objets. La solution consiste à utiliser un tableau en double pour le niveau en cours de lecture et à conserver le tableau d'origine. levelData tableau intact. Par exemple, nous utilisons levelData et levelDataLive [], cloner le dernier de l'ancien au début du niveau et ne changer que levelDataLive [] pendant le jeu.

Par exemple, je crée une collecte aléatoire sur une tuile d’herbe vide après chaque collecte et j'augmente la pickupCount. le pickupItem la fonction ressemble à ceci.

function pickupItem () pickupCount ++; levelData [heroMapTile.y] [heroMapTile.x] = 0; // engendre le prochain ramassage spawnNewPickup (); 

Vous devriez remarquer que nous vérifions la présence de micros chaque fois que le personnage est sur cette tuile. Cela peut se produire plusieurs fois par seconde (nous ne vérifions que lorsque l'utilisateur bouge, mais nous pouvons tourner en rond dans une tuile), mais la logique ci-dessus n'échouera pas; depuis que nous avons mis la levelData données de tableau à 0 la première fois que nous détectons un ramassage, tous les suivants onPickupTile () les chèques vont retourner faux pour cette tuile. Découvrez l'exemple interactif ci-dessous:

2. Tuiles de déclenchement

Comme son nom l'indique, les tuiles de déclenchement entraînent des incidents lorsque le joueur les appuie ou appuie sur une touche. Ils peuvent téléporter le joueur dans un endroit différent, ouvrir une porte ou engendrer un ennemi, pour donner quelques exemples. En un sens, les pick-up ne sont qu'une forme spéciale de tuiles à déclenchement: lorsque le joueur marche sur une tuile contenant une pièce de monnaie, celle-ci disparaît et son compteur de pièces augmente..

Voyons comment mettre en place une porte qui amène le joueur à un autre niveau. La tuile à côté de la porte sera une tuile à déclenchement; quand le joueur appuie sur le X clé, ils vont passer au niveau suivant.

Pour changer de niveau, il suffit d’échanger la version actuelle. levelData tableau avec celui du nouveau niveau, et définissez le nouveau heroMapTile position et direction pour le personnage du héros. Supposons qu'il y ait deux niveaux avec des portes pour permettre le passage entre eux. Comme la tuile au sol à côté de la porte sera la tuile de déclenchement dans les deux niveaux, nous pouvons l'utiliser comme nouvelle position du personnage quand ils apparaissent dans le niveau..

La logique de mise en œuvre est la même que pour les capteurs, et nous utilisons à nouveau le levelData tableau pour stocker les valeurs de déclenchement. Pour notre exemple, 2 désigne une tuile de porte et la valeur à côté est le déclencheur. j'ai utilisé 101 et 102 avec la convention de base que toute tuile avec une valeur supérieure à 100 est une tuile de déclenchement et que la valeur moins 100 peut être le niveau auquel elle conduit:

var level1Data = [[1,1,1,1,1,1], [1,1,0,0,0,1], [1,0,0,0,0,1], [2,102,0 , 0,0,1], [1,0,0,0,1,1], [1,1,1,1,1,1]]; var level2Data = [[1,1,1,1,1,1], [1,0,0,0,0,1], [1,0,8,0,0,1], [1,0 , 0,0101,2], [1,0,1,0,0,1], [1,1,1,1,1,1]];

Le code permettant de rechercher un événement déclencheur est présenté ci-dessous:

var xKey = game.input.keyboard.addKey (Phaser.Keyboard.X); xKey.onUp.add (triggerListener); // ajoute un écouteur de signal pour la fonction d'événement up triggerListener () var trigger = levelData [heroMapTile.y] [heroMapTile.x]; if (trigger> 100) // trigger trigger valide trigger- = 100; if (trigger == 1) // basculer au niveau 1 levelData = level1Data;  else // passage au niveau 2 levelData = level2Data;  pour (var i = 0; i < levelData.length; i++)  for (var j = 0; j < levelData[0].length; j++)  trigger=levelData[i][j]; if(trigger>100) // trouve la nouvelle tuile déclencheur et place le héros là heroMapTile.y = j; heroMapTile.x = i; heroMapPos = new Phaser.Point (heroMapTile.y * tileWidth, heroMapTile.x * tileWidth); heroMapPos.x + = (tileWidth / 2); heroMapPos.y + = (tileWidth / 2); 

La fonction triggerListener () vérifie si la valeur du tableau de données de déclenchement à la coordonnée donnée est supérieure à 100. Si c'est le cas, nous déterminons le niveau auquel nous devons passer en soustrayant 100 de la valeur de mosaïque. La fonction trouve la tuile de déclenchement dans la nouvelle levelData, qui sera la position de spawn pour notre héros. J'ai fait le déclencheur pour être activé quand X est libéré; si nous écoutons seulement si la touche est enfoncée, nous nous retrouvons dans une boucle où nous basculons entre les niveaux tant que la touche est maintenue enfoncée, car le personnage apparaît toujours dans le nouveau niveau au-dessus d'une tuile de déclencheur..

Voici une démo de travail. Essayez de ramasser des objets en marchant dessus et en échangeant les niveaux en vous tenant à côté des portes et en frappant X.

3. projectiles

UNE projectile est quelque chose qui se déplace dans une direction donnée avec une vitesse particulière, comme une balle, un sortilège, une balle, etc. Tout ce qui concerne le projectile est identique au personnage du héros, à l'exception de l'altitude: plutôt que de rouler sur le sol, les projectiles flottent souvent au-dessus de lui à une certaine hauteur. Une balle va voyager au-dessus du niveau de la taille du personnage, et même une balle peut avoir besoin de rebondir.

Une chose intéressante à noter est que la hauteur isométrique est identique à la hauteur dans une vue latérale 2D, bien que sa valeur soit inférieure. Il n'y a pas de conversions compliquées impliquées. Si une balle est à 10 pixels du sol en coordonnées cartésiennes, elle pourrait être de 10 ou 6 pixels au dessus du sol en coordonnées isométriques. (Dans notre cas, l'axe pertinent est l'axe des ordonnées.)

Essayons de mettre en place une balle qui rebondit dans nos prairies fortifiées. Par réalisme, nous ajouterons une ombre au ballon. Tout ce que nous avons à faire est d’ajouter la valeur de la hauteur de rebond à la valeur isométrique Y de notre balle. La valeur de la hauteur du saut changera d'une image à l'autre en fonction de la gravité, et une fois que la balle touchera le sol, nous inverserons la vitesse actuelle le long de l'axe des ordonnées..

Avant d'aborder les rebonds dans un système isométrique, nous verrons comment l'implémenter dans un système cartésien 2D. Représentons la puissance de saut de la balle avec une variable zValue. Imaginez que, pour commencer, le ballon ait une puissance de saut de 100, donc zValue = 100

Nous allons utiliser deux autres variables: incrementValue, qui commence à 0, et la gravité, qui a une valeur de -1. Chaque image, nous soustrayons incrementValue de zValue, et soustraire la gravité de incrementValue afin de créer un effet d'amortissement. Quand zValue atteint 0, cela signifie que la balle a atteint le sol; à ce stade, nous retournons le signe de incrementValue en le multipliant par -1, en le transformant en un nombre positif. Cela signifie que la balle se déplacera vers le haut à partir de la trame suivante, rebondissant ainsi.

Voici à quoi ça ressemble dans le code:

if (game.input.keyboard.isDown (Phaser.Keyboard.X)) zValue = 100;  incrementValue- = gravité; zValue- = incrementValue; si (zValue<=0) zValue=0; incrementValue*=-1; 

Le code reste le même pour la vue isométrique, avec la légère différence que vous pouvez utiliser une valeur inférieure pour zValue commencer avec. Voir ci-dessous comment le zValue est ajouté à l'isométrique y valeur de la balle lors du rendu.

function drawBallIso () var isoPt = new Phaser.Point (); // Il n'est pas conseillé de créer des points dans la boucle de mise à jour. var ballCornerPt = new Phaser.Point (ballMapPos.x-ball2DVolume.x / 2, ballMapPos.y-ball2DVolume .y / 2); isoPt = cartesianToIsometric (ballCornerPt); // trouve une nouvelle position isométrique pour le héros à partir de la position de carte 2D gameScene.renderXY (ballShadowSprite, isoPt.x + borderOffset.x + shadowOffset.x, isoPt.y + borderOffset.y, shadowOffset.y, shadow ); // dessine une ombre pour restituer la texture gameScene.renderXY (ballSprite, isoPt.x + borderOffset.x + ballOffset.x, isoPt.y + borderOffset.y-ballOffset.y-zValue, false); // dessine le héros à rendre texture

Découvrez l'exemple interactif ci-dessous:

Comprenez bien que le rôle joué par l’ombre est un rôle très important qui ajoute au réalisme de cette illusion. Notez également que nous utilisons maintenant les deux coordonnées d'écran (x et y) pour représenter trois dimensions en coordonnées isométriques. L'axe des ordonnées en coordonnées d'écran est également l'axe z en coordonnées isométriques. Cela peut être déroutant!

4. Trouver et suivre un chemin

La recherche de chemin et le suivi de chemin sont des processus assez compliqués. Il existe différentes approches utilisant différents algorithmes pour trouver le chemin entre deux points, mais comme notre levelData est un tableau 2D, les choses sont plus faciles qu’elles ne pourraient l’être autrement. Nous avons des nœuds uniques et bien définis que le joueur peut occuper, et nous pouvons facilement vérifier s’ils sont accessibles à la marche..

Articles Similaires

  • A * Pathfinding pour les débutants
  • Recherche de champ de vecteur basée sur des objectifs
  • Accélérer A * Pathfinding avec l'algorithme de recherche de point de saut
  • Le comportement de la direction "suivant le chemin"

Un aperçu détaillé des algorithmes de recherche de cheminement sort du cadre de cet article, mais je vais essayer d'expliquer la façon la plus courante de son fonctionnement: l'algorithme du plus court chemin, dont les algorithmes de A * et Dijkstra sont des implémentations célèbres..

Notre objectif est de trouver des nœuds reliant un nœud de départ et un nœud de fin. À partir du nœud de départ, nous visitons les huit nœuds voisins et les marquons tous comme étant visités; ce processus principal est répété de manière récurrente pour chaque nœud nouvellement visité. 

Chaque fil suit les nœuds visités. Lors du saut aux nœuds voisins, les nœuds déjà visités sont ignorés (la récursivité s'arrête); sinon, le processus se poursuit jusqu'à ce que nous atteignions le nœud final, où la récursivité se termine et le chemin complet suivi est renvoyé sous forme de tableau de nœuds. Parfois, le noeud final n'est jamais atteint, auquel cas la recherche de chemin échoue. Nous finissons généralement par trouver plusieurs chemins entre les deux nœuds, auquel cas nous prenons celui avec le plus petit nombre de nœuds..

Trouver son chemin

Il est déconseillé de réinventer la roue lorsqu'il s'agit d'algorithmes bien définis. Nous utiliserions donc les solutions existantes à des fins de repérage. Pour utiliser Phaser, nous avons besoin d’une solution JavaScript, et celle que j’ai choisie est EasyStarJS. Nous initialisons le moteur de recherche de chemin comme ci-dessous.

easystar = new EasyStar.js (); easystar.setGrid (levelData); easystar.setAcceptableTiles ([0]); easystar.enableDiagonals (); // nous voulons que le chemin ait des diagonales easystar.disableCornerCutting (); // pas de chemin en diagonale pour marcher aux coins des murs

Comme notre levelData a seulement 0 et 1, nous pouvons directement le transmettre en tant que tableau de noeuds. Nous fixons la valeur de 0 en tant que noeud praticable. Nous activons la capacité de marche en diagonale mais nous la désactivons lorsque nous marchons près des coins de dalles non piétonnables. 

En effet, si cette option est activée, le héros peut découper la tuile non praticable lors d’une marche en diagonale. Dans un tel cas, notre détection de collision ne permettra pas au héros de passer. De plus, veuillez noter que, dans l'exemple, j'ai complètement supprimé la détection de collision car elle n'est plus nécessaire pour un exemple de parcours basé sur l'IA.. 

Nous allons détecter le tap sur n'importe quelle tuile libre à l'intérieur du niveau et calculer le chemin à l'aide de la findPath une fonction. La méthode de rappel plotAndMove reçoit le tableau de noeuds du chemin résultant. Nous marquons le mini-carte avec le chemin nouvellement trouvé.

game.input.activePointer.leftButton.onUp.add (findPath) fonction findPath () if (isFindingPath || isWalking) return; var pos = game.input.activePointer.position; var isoPt = new Phaser.Point (pos.x-borderOffset.x, pos.y-borderOffset.y); tapPos = isometricToCartesian (isoPt); tapPos.x- = tileWidth / 2; // ajustement pour trouver la bonne mosaïque d'erreur due à l'arrondi de tapPos.y + = tileWidth / 2; tapPos = getTileCoordinates (tapPos, tileWidth); if (tapPos.x> -1 && tapPos.y> -1 && tapPos.x<7&&tapPos.y<7)//tapped within grid if(levelData[tapPos.y][tapPos.x]!=1)//not wall tile isFindingPath=true; //let the algorithm do the magic easystar.findPath(heroMapTile.x, heroMapTile.y, tapPos.x, tapPos.y, plotAndMove); easystar.calculate();    function plotAndMove(newPath) destination=heroMapTile; path=newPath; isFindingPath=false; repaintMinimap(); if (path === null)  console.log("No Path was found."); else path.push(tapPos); path.reverse(); path.pop(); for (var i = 0; i < path.length; i++)  var tmpSpr=minimap.getByName("tile"+path[i].y+"_"+path[i].x); tmpSpr.tint=0x0000ff; //console.log("p "+path[i].x+":"+path[i].y);   

Chemin suivi

Une fois que nous avons le chemin d'accès sous forme de tableau de noeuds, nous devons faire en sorte que le caractère le suive.

Disons que nous voulons faire marcher le personnage sur une tuile sur laquelle nous cliquons. Nous devons d’abord rechercher un chemin entre le nœud que le personnage occupe actuellement et le nœud sur lequel nous avons cliqué. Si un chemin réussi est trouvé, nous devons déplacer le caractère vers le premier nœud du tableau de nœuds en le définissant comme destination. Une fois que nous arrivons au nœud de destination, nous vérifions s'il y a plus de nœuds dans le tableau de nœuds et, si tel est le cas, définissons le nœud suivant comme destination, et ainsi de suite jusqu'à atteindre le nœud final..

Nous allons également changer la direction du joueur en fonction du nœud actuel et du nouveau nœud de destination chaque fois que nous atteignons un nœud. Entre les nœuds, il suffit de marcher dans la direction requise jusqu'à atteindre le nœud de destination. Ceci est une IA très simple, et dans l'exemple cela est fait dans la méthode aiWalk montré partiellement ci-dessous.

function aiWalk () if (path.length == 0) // le chemin est terminé if (heroMapTile.x == destination.x && heroMapTile.y == destination.y) dX = 0; dY = 0; isWalking = false; revenir;  isWalking = true; if (heroMapTile.x == destination.x && heroMapTile.y == destination.y) // a atteint la destination actuelle, définissez une nouvelle, changez de direction // attendez que nous soyons quelques étapes dans la mosaïque avant de procéder à stepsTaken ++; si (étapes prisesdestination.x) dX = -1;  else dX = 0;  si (heroMapTile.ydestination.y) dY = -1;  else dY = 0;  if (heroMapTile.x == destination.x) dX = 0;  else if (heroMapTile.y == destination.y) dY = 0;  //…

nous faire besoin de filtrer les points de clic valides en déterminant si nous avons cliqué dans la zone piétonnable, plutôt que dans un carreau mural ou dans un autre carreau non piétonnier.

Un autre point intéressant pour le codage de l'IA: nous ne voulons pas que le personnage se retourne face à la prochaine tuile du tableau de noeuds dès qu'il est arrivé dans la rangée actuelle, car un tel virage immédiat fait en sorte que notre personnage marche sur les frontières de carrelage. Au lieu de cela, nous devrions attendre que le personnage ait fait quelques pas à l'intérieur de la tuile avant de chercher la prochaine destination. Il est également préférable de placer manuellement le héros au milieu de la tuile actuelle juste avant de tourner, pour que tout soit parfait..

Découvrez la démo de travail ci-dessous:

5. Défilement isométrique

Lorsque la zone de niveau est beaucoup plus grande que la zone d’écran disponible, vous devez la définir. faire défiler.

La zone d'écran visible peut être considérée comme un rectangle plus petit dans le rectangle plus grand de la zone de niveau complète. Faire défiler, c'est essentiellement déplacer le rectangle intérieur à l'intérieur du plus grand. Habituellement, lorsqu'un tel défilement se produit, la position du héros reste la même par rapport au rectangle d'écran, généralement au centre de l'écran. Fait intéressant, tout ce dont nous avons besoin pour implémenter le défilement est de suivre le coin du rectangle intérieur..

Ce point d'angle, que nous représentons en coordonnées cartésiennes, fera partie d'une tuile dans les données de niveau. Pour le défilement, nous incrémentons les positions x et y du point d’angle en coordonnées cartésiennes. Maintenant, nous pouvons convertir ce point en coordonnées isométriques et l'utiliser pour dessiner l'écran. 

Les valeurs nouvellement converties, dans l’espace isométrique, doivent également constituer le coin de notre écran, ce qui signifie qu’elles sont les nouvelles. (0, 0). Ainsi, lors de l'analyse et du dessin des données de niveau, nous soustrayons cette valeur de la position isométrique de chaque mosaïque et pouvons déterminer si la nouvelle position de la mosaïque se situe dans l'écran.. 

Alternativement, nous pouvons décider que nous allons tirer seulement un X x Y grille de mosaïque isométrique à l'écran pour rendre la boucle de dessin efficace pour des niveaux plus importants. 

Nous pouvons exprimer cela par étapes de la manière suivante:

  • Mettre à jour les coordonnées x et y du point d'angle cartésien.
  • Convertir cela en espace isométrique.
  • Soustrayez cette valeur de la position de tracé isométrique de chaque mosaïque.
  • Dessinez seulement un nombre prédéfini limité de tuiles à l'écran à partir de ce nouveau coin.
  • Facultatif: Dessinez la mosaïque uniquement si la nouvelle position de tracé isométrique se situe dans l'écran..
var cornerMapPos = new Phaser.Point (0,0); var cornerMapTile = new Phaser.Point (0,0); var visibleTiles = new Phaser.Point (6,6); //… function update () //… if (isWalkable ()) heroMapPos.x + = heroSpeed ​​* dX; heroMapPos.y + = heroSpeed ​​* dY; // déplace le coin dans le sens opposé cornerMapPos.x - = heroSpeed ​​* dX; cornerMapPos.y - = heroSpeed ​​* dY; cornerMapTile = getTileCoordinates (cornerMapPos, tileWidth); // récupère la nouvelle tuile de carte de héros heroMapTile = getTileCoordinates (heroMapPos, tileWidth); // depthsort & dessine une nouvelle scène renderScene ();  function renderScene () gameScene.clear (); // efface l'image précédente puis dessine à nouveau var tileType = 0; // limitons les boucles dans la zone visible var startTileX = Math.max (0,0-cornerMapTile.x); var startTileY = Math.max (0,0-cornerMapTile.y); var endTileX = Math.min (levelData [0] .length, startTileX + visibleTiles.x); var endTileY = Math.min (levelData.length, startTileY + visibleTiles.y); startTileX = Math.max (0, endTileX-visibleTiles.x); startTileY = Math.max (0, endTileY-visibleTiles.y); // vérifie la condition de bordure pour (var i = startTileY; i < endTileY; i++)  for (var j = startTileX; j < endTileX; j++)  tileType=levelData[i][j]; drawTileIso(tileType,i,j); if(i==heroMapTile.y&&j==heroMapTile.x) drawHeroIso();     function drawHeroIso() var isoPt= new Phaser.Point();//It is not advisable to create points in update loop var heroCornerPt=new Phaser.Point(heroMapPos.x-hero2DVolume.x/2+cornerMapPos.x,heroMapPos.y-hero2DVolume.y/2+cornerMapPos.y); isoPt=cartesianToIsometric(heroCornerPt);//find new isometric position for hero from 2D map position gameScene.renderXY(sorcererShadow,isoPt.x+borderOffset.x+shadowOffset.x, isoPt.y+borderOffset.y+shadowOffset.y, false);//draw shadow to render texture gameScene.renderXY(sorcerer,isoPt.x+borderOffset.x+heroWidth, isoPt.y+borderOffset.y-heroHeight, false);//draw hero to render texture  function drawTileIso(tileType,i,j)//place isometric level tiles var isoPt= new Phaser.Point();//It is not advisable to create point in update loop var cartPt=new Phaser.Point();//This is here for better code readability. cartPt.x=j*tileWidth+cornerMapPos.x; cartPt.y=i*tileWidth+cornerMapPos.y; isoPt=cartesianToIsometric(cartPt); //we could further optimise by not drawing if tile is outside screen. if(tileType==1) gameScene.renderXY(wallSprite, isoPt.x+borderOffset.x, isoPt.y+borderOffset.y-wallHeight, false); else gameScene.renderXY(floorSprite, isoPt.x+borderOffset.x, isoPt.y+borderOffset.y, false);  

Veuillez noter que le coin est incrémenté dans le contraire direction à la position du héros mise à jour comme il se déplace. Cela garantit que le héros reste où il est par rapport à l'écran. Découvrez cet exemple (utilisez les flèches pour faire défiler, appuyez pour augmenter la grille visible).

Quelques notes:

  • Lors du défilement, nous pouvons avoir besoin de dessiner des tuiles supplémentaires aux bords de l’écran, ou alors nous pourrions voir des tuiles disparaître et apparaître aux extrémités de l’écran..
  • Si vous avez des tuiles qui occupent plus d’un espace, vous devrez dessiner plus de tuiles aux frontières. Par exemple, si la plus grande mosaïque de l'ensemble mesure X par Y, vous devrez alors dessiner X plus de mosaïques à gauche et à droite et Y plus de mosaïques en haut et en bas. Cela garantit que les coins de la plus grande vignette seront toujours visibles lors du défilement vers l'intérieur ou l'extérieur de l'écran..
  • Nous devons toujours nous assurer que nous n'avons pas de zones vides à l'écran pendant que nous nous approchons des limites du niveau..
  • Le niveau ne doit défiler que jusqu'à ce que la tuile la plus extrême soit dessinée à l'écran correspondant. Après cela, le personnage doit continuer à se déplacer dans l'écran. sans pour autant le niveau de défilement. Pour cela, nous devrons suivre les quatre coins du rectangle d’écran intérieur et limiter la logique de défilement et de déplacement du lecteur en conséquence. Êtes-vous prêt à relever le défi d'essayer de mettre cela en œuvre vous-même??

Conclusion

Cette série est particulièrement destinée aux débutants qui souhaitent explorer les mondes du jeu isométrique. Beaucoup de concepts expliqués ont des approches alternatives qui sont un peu plus compliquées, et j'ai délibérément choisi les plus faciles. 

Ils ne répondent peut-être pas à la plupart des scénarios que vous pouvez rencontrer, mais les connaissances acquises peuvent être utilisées pour développer ces concepts et créer des solutions plus complexes. Par exemple, le simple tri en profondeur mis en place va casser lorsque nous aurons des niveaux à plusieurs étages et des mosaïques de plateforme se déplaçant d'un étage à l'autre. 

Mais c'est un tutoriel pour une autre fois.