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 sur sa position.
1
2
3
4
5
6
7
8
9
10
11
functionlove.draw()--ipairs recap--ipairs is a special function that allows you to loop through a table--Every iteration i becomes what iteration the loop is at, so 1, 2, 3, 4, etc)--Every iteration v becomes the value on position i, so in our case 1, 0, 0, 1, 1, 0, etc.fori,vinipairs(tilemap)doifv==1thenlove.graphics.rectangle("line",i*25,100,25,25)endendend
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.
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 comme une petite ville
Chaque rangée de maisons est une table, et plusieurs rangées font 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.
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()--Let's do it without ipairs first.--For i=1 till the number of values in tilemapfori=1,#tilemapdo--For j till the number of values in this rowforj=1,#tilemap[i]do--If the value on row i, column j equals 1iftilemap[i][j]==1then--Draw the rectangle.--Use i and j to position the rectangle.-- j for x, i for 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 y. N’oubliez pas que ce ne sont que des noms de variables et peuvent être nommés, 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 le tilemap de la table 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 carreaux, et utiliser ces numéros pour donner aux carreaux 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--First check if the tile is not zeroiftile~=0then--Set the color based on the tile numberiftile==1then--setColor uses RGB, A is optional--Red, Green, Blue, 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--Draw the tilelove.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}}--Create a table named colorscolors={--Fill it with tables filled with RGB numbers{1,1,1},{1,0,0},{1,0,1},{0,0,1},{0,1,1}}endfunctionlove.draw()fori,rowinipairs(tilemap)doforj,tileinipairs(row)do--First check if the tile is not zeroiftile~=0then--Set the color. .setColor() also accepts a table with 3 numbers.--We pass the table with as position the value of tile.--So if tile equals 3 then we pass colors[3] which is {1, 0, 1}love.graphics.setColor(colors[tile])--Draw the tilelove.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()--Load the imageimage=love.graphics.newImage("tile.png")--Get the width and heightwidth=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={--Fill it with tables filled with RGB numbers{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])--Draw the 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 l’utiliser pour les carreaux.
functionlove.load()--Load the imageimage=love.graphics.newImage("tileset.png")--We need the full image width and height for creating the quadslocalimage_width=image:getWidth()localimage_height=image:getHeight()--The width and height of each tile is 32, 32--So we could do:width=32height=32--But let's say we don't know the width and height of a tile--We can also use the number of rows and columns in the tileset--Our tileset has 2 rows and 3 columns--But we need to subtract 2 to make up for the empty pixels we included to prevent bleedingwidth=(image_width/3)-2height=(image_height/2)-2--Create the quadsquads={}fori=0,1doforj=0,2do--The only reason this code is split up in multiple lines--is so that it fits the 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 nombre 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 sur 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--Draw the image with the correct quadlove.graphics.draw(image,quads[tile],j*width,i*height)endendendend
Donc sur (1,1) nous dessinons le quad en position 1. Sur (1,2) nous dessinons le quad sur 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 pas traverser les murs.
Le tile_x et tile_y est la position du joueur sur notre tilemap. Ce nombre sera multiplié par la largeur et la hauteur des carreaux lorsqu’ils seront dessinés. Mais d’abord, faisons bouger les choses. Au lieu d’un mouvement en douceur, 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 sont enfoncées. Pour cela, nous utilisons l’événement love.keypressed.
Nous créons d’abord la variable locale 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--Draw the image with the correct quadlove.graphics.draw(image,quads[tile],j*width,i*height)endendend--Draw the player and multiple its tile position with the tile width and heightlove.graphics.draw(player.image,player.tile_x*width,player.tile_y*height)end
Lorsque vous exécutez le jeu, vous devriez pouvoir vous promener 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 sur les coordonné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 endroit 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 touchez une touche. Chercher 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.