C’est notre niveau. Un 1 est une tuile et un 0 est vide. Maintenant, nous devons le dessiner. Nous parcourons la table, et chaque fois que nous rencontrons un 1, nous dessinons un rectangle à sa position.
1
2
3
4
5
6
7
8
9
10
11
functionlove.draw()--ipairs recap--ipairs est une fonction spéciale qui permet de parcourir une table--À chaque itération, i devient le numéro de l'itération, donc 1, 2, 3, 4, etc.--À chaque itération, v devient la valeur à la position i, donc dans notre cas 1, 0, 0, 1, 1, 0, etc.fori,vinipairs(tilemap)doifv==1thenlove.graphics.rectangle("line",i*25,100,25,25)endendend
Représentation des tuiles dessinées
D’accord, cela fonctionne, mais maintenant nous voulons aller verticalement. Pour ce faire, nous mettons des tables à l’intérieur d’une table, également connue sous le nom de table 2D.
Alors maintenant, nous avons un tableau rempli de tableaux. Voyez-le comme un tableau Excel.
Représentation du tableau sous Excel
1, 2, 3, etc. sont ce que nous appelons des lignes et A, B, C, etc. sont appelés des colonnes.
Une autre façon de voir les choses est comme une petite ville :
Une autre représentation mais avec des maisons
Chaque rangée de maisons est une table, et plusieurs rangées forment toute la ville, ou dans notre cas, notre niveau.
La maison verte est au 2ème rang sur la 5ème colonne.
La maison rouge est au 3ème rang de la 2ème colonne.
Avec les tableaux 2D, nous accédons aux valeurs comme ceci :
1
tilemap[4][3]
Cela signifie : La 3ème valeur de la 4ème table, ou la 3ème colonne de la 4ème ligne.
Comment le programme lit notre code
Dessinons notre niveau. Parce que nous avons une table 2D, nous devons utiliser une boucle for à l’intérieur d’une boucle for. Plus communément, on appelle ceci une boucle for imbriquée.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
functionlove.draw()--Faisons-le d'abord sans ipairs.--Pour i=1 jusqu'au nombre de valeurs dans tilemapfori=1,#tilemapdo--Pour j jusqu'au nombre de valeurs dans cette ligneforj=1,#tilemap[i]do--Si la valeur à la ligne i, colonne j est égale à 1iftilemap[i][j]==1then--Dessiner le rectangle.--Utiliser i et j pour positionner le rectangle.--j pour x, i pour y.love.graphics.rectangle("line",j*25,i*25,25,25)endendendend
Nous parcourons donc nos lignes et pour chaque ligne, nous parcourons nos colonnes.
Nous utilisons j, de notre boucle interne pour notre positionnement horizontal et i, de notre boucle externe pour le positionnement vertical. N’oubliez pas que ce ne sont que des noms de variables et qu’ils peuvent être nommés autrement, mais utiliser i et j comme ceci est courant.
Transformons les boucles for en une boucle ipairs.
Nous utilisons deux variables, row et tile, pour rendre plus clair ce qui se passe. Nous parcourons la table tilemap et chaque valeur est une ligne. Nous parcourons la ligne et chaque valeur est une tuile.
Nous pouvons également utiliser des numéros différents pour nos tuiles, et utiliser ces numéros pour donner aux tuiles des couleurs différentes.
functionlove.load()tilemap={{1,1,1,1,1,1,1,1,1,1},{1,2,2,2,2,2,2,2,2,1},{1,2,3,4,5,5,4,3,2,1},{1,2,2,2,2,2,2,2,2,1},{1,1,1,1,1,1,1,1,1,1}}endfunctionlove.draw()fori,rowinipairs(tilemap)doforj,tileinipairs(row)do--Vérifions d'abord si la tuile n'est pas zéroiftile~=0then--Définir la couleur en fonction du numéro de tuileiftile==1then--setColor utilise RGB, A est optionnel--Rouge, Vert, Bleu, Alphalove.graphics.setColor(1,1,1)elseiftile==2thenlove.graphics.setColor(1,0,0)elseiftile==3thenlove.graphics.setColor(1,0,1)elseiftile==4thenlove.graphics.setColor(0,0,1)elseiftile==5thenlove.graphics.setColor(0,1,1)end--Dessiner la tuilelove.graphics.rectangle("fill",j*25,i*25,25,25)endendendend
functionlove.load()tilemap={{1,1,1,1,1,1,1,1,1,1},{1,2,2,2,2,2,2,2,2,1},{1,2,3,4,5,5,4,3,2,1},{1,2,2,2,2,2,2,2,2,1},{1,1,1,1,1,1,1,1,1,1}}--Créer une table nommée colorscolors={--La remplir avec des tables contenant des nombres RGB{1,1,1},{1,0,0},{1,0,1},{0,0,1},{0,1,1}}endfunctionlove.draw()fori,rowinipairs(tilemap)doforj,tileinipairs(row)do--Vérifions d'abord si la tuile n'est pas zéroiftile~=0then--Définir la couleur. .setColor() accepte aussi une table avec 3 nombres.--Nous passons la table à la position correspondant à la valeur de tile.--Donc si tile vaut 3, alors nous passons colors[3] qui est {1, 0, 1}love.graphics.setColor(colors[tile])--Dessiner la tuilelove.graphics.rectangle("fill",j*25,i*25,25,25)endendendend
Images
Nous pouvons donc créer un niveau coloré, mais maintenant nous voulons utiliser des images. Eh bien, c’est facile, il suffit d’ajouter une image, d’obtenir la largeur et la hauteur et de dessiner l’image au lieu d’un rectangle.
functionlove.load()--Charger l'imageimage=love.graphics.newImage("tile.png")--Obtenir la largeur et la hauteurwidth=image:getWidth()height=image:getHeight()tilemap={{1,1,1,1,1,1,1,1,1,1},{1,2,2,2,2,2,2,2,2,1},{1,2,3,4,5,5,4,3,2,1},{1,2,2,2,2,2,2,2,2,1},{1,1,1,1,1,1,1,1,1,1}}colors={--Remplir avec des tables contenant des nombres RGB{1,1,1},{1,0,0},{1,0,1},{0,0,1},{0,1,1}}endfunctionlove.draw()fori,rowinipairs(tilemap)doforj,tileinipairs(row)doiftile~=0thenlove.graphics.setColor(colors[tile])--Dessiner l'imagelove.graphics.draw(image,j*width,i*height)endendendend
C’est donc simple. Mais que se passe-t-il si nous voulons dessiner des images différentes ? Eh bien, nous pourrions utiliser plusieurs images, mais dans le chapitre précédent, nous avons appris comment dessiner une partie d’une image avec des quads. Nous pouvons également les utiliser pour les tuiles.
functionlove.load()--Charger l'imageimage=love.graphics.newImage("tileset.png")--Nous avons besoin de la largeur et hauteur complètes de l'image pour créer les quadslocalimage_width=image:getWidth()localimage_height=image:getHeight()--La largeur et hauteur de chaque tuile est 32, 32--Nous pourrions donc faire :width=32height=32--Mais disons que nous ne connaissons pas la largeur et la hauteur d'une tuile--Nous pouvons aussi utiliser le nombre de lignes et colonnes dans le tileset--Notre tileset a 2 lignes et 3 colonnes--Mais nous devons soustraire 2 pour compenser les pixels vides inclus pour éviter le bleedingwidth=(image_width/3)-2height=(image_height/2)-2--Créer les quadsquads={}fori=0,1doforj=0,2do--La seule raison pour laquelle ce code est divisé en plusieurs lignes--est pour qu'il tienne sur la pagetable.insert(quads,love.graphics.newQuad(1+j*(width+2),1+i*(height+2),width,height,image_width,image_height))endendtilemap={{1,1,1,1,1,1,1,1,1,1},{1,2,2,2,2,2,2,2,2,1},{1,2,3,4,5,5,4,3,2,1},{1,2,2,2,2,2,2,2,2,1},{1,1,1,1,1,1,1,1,1,1}}end
Maintenant que nous avons une table avec des quads, nous mettons le numéro correspondant dans notre tilemap en fonction du quad que nous voulons. En fonction de l’ordre dans lequel nous avons créé nos quads, ils se trouvent à cette position dans notre tableau :
Si vous comparez le tilemap avec l’image et les nombres, vous pouvez voir comment chaque tuile est utilisée.
Maintenant, nous devons dessiner le bon quad.
1
2
3
4
5
6
7
8
9
10
functionlove.draw()fori,rowinipairs(tilemap)doforj,tileinipairs(row)doiftile~=0then--Dessiner l'image avec le quad correctlove.graphics.draw(image,quads[tile],j*width,i*height)endendendend
Donc à la position (1,1) nous dessinons le quad en position 1. À la position (1,2) nous dessinons le quad à la position 6, etc.
Si vous lancez le jeu, vous verrez que notre niveau ressemble maintenant à l’image ci-dessus.
Joueur
Maintenant que nous avons un niveau, créons un joueur qui peut se promener, mais qui ne peut pas traverser les murs.
Les propriétés tile_x et tile_y correspondent à la position du joueur sur notre tilemap. Ces nombres seront multipliés par la largeur et la hauteur des tuiles lorsqu’ils seront dessinés. Mais d’abord, faisons bouger le joueur. Au lieu d’un mouvement fluide, nous le ferons sauter à sa position suivante ; nous n’aurons donc pas besoin de dt pour le mouvement. Cela signifie également que nous ne voulons pas savoir si les touches de mouvement sont enfoncées, mais si elles viennent d’être pressées. Pour cela, nous utilisons l’événement love.keypressed.
Nous créons d’abord les variables locales x et y. Ensuite, nous ajoutons ou soustrayons 1 à cette variable en fonction de la touche qui a été enfoncée, et finalement nous attribuons cette valeur à la position du joueur.
functionlove.draw()fori,rowinipairs(tilemap)doforj,tileinipairs(row)doiftile~=0then--Dessiner l'image avec le quad correctlove.graphics.draw(image,quads[tile],j*width,i*height)endendend--Dessiner le joueur et multiplier sa position de tuile par la largeur et la hauteur des tuileslove.graphics.draw(player.image,player.tile_x*width,player.tile_y*height)end
Ce que permet de faire le code actuel
Lorsque vous exécutez le jeu, vous devriez pouvoir vous déplacer avec votre joueur. Mais le problème est qu’il peut traverser les murs. Corrigeons cela en vérifiant si la position où il veut aller est un mur.
Créez d’abord une fonction appelée isEmpty. À l’intérieur, nous retournons si la valeur aux coordonnées données est égale à 0.
1
2
3
functionisEmpty(x,y)returntilemap[y][x]==0end
Il peut sembler étrange que x et y soient inversés, mais c’est correct. Parce que la position y est la ligne et la position x est la colonne.
Maintenant que nous avons notre fonction, nous pouvons vérifier si l’endroit où nous voulons aller est un emplacement vide, et si c’est le cas, cela signifie que nous pouvons y aller.
Super, maintenant notre joueur est piégé à l’intérieur de nos murs. Essayez de voir si vous pouvez lui faire ramasser des objets ou lui faire ouvrir une porte lorsque vous appuyez sur une touche. Cherchez des idées et essayez de les appliquer. C’est comme ça que vous apprendrez.
Résumé
Nous pouvons utiliser des tuiles pour faire des niveaux. Un tilemap est constitué de lignes et de colonnes. Chaque ligne contient un certain nombre de colonnes. Les lignes sont alignées verticalement et les colonnes horizontalement. Nous pouvons utiliser un jeu de tuiles et des quads pour dessiner notre niveau.