Skip to content
Roll for a...
retour

Löve2D - Afficher une grille en 3d Isométrique

Une méthode simple pour afficher une grille 2D en 3D isométrique, avec le moteur de jeu Löve 2D. Le but est de passer d’une grille au format tableau à ce type de rendu :

rendue isométrique

La logique

Quand nous dessinons une grille en vu du dessus, les cellules sont affichées côte à côte, comme Advance wars ou Fire emblem. Sur une vue en 3D isométrique, FF Tactics ou Tactics Ogre, les cellules sont affichées avec un léger décalage de leur axe X et Y. Les tiles au format 3D isométrique sont des cases carrées classiques, avec des zones en transparence permettant leur superposition.

Superposition des tiles

Les cases sont décalées de la moitié de leur taille sur l’axe X (de gauche à droite) et d’un quart de leur taille sur l’axe Y (vers le bas).

alignement.png

L’implémentation

Pré-requis

La fonction fromImageToQuads dans le fichier utils.ts est une implémentation simple d’un système de tileset. Le tutoriel n’abordant ce sujet, je ne décrirais pas son fonctionnement.

├── assets
│ └── sprite.png
├── conf.lua
├── main.lua
└── utils.luaArborescence
function love.conf(t)
    t.version = "11.5"                  -- The LÖVE version this game was made for (string)
    t.window.title = "iso tutoriel"         -- The window title (string)
    t.window.icon = nil                 -- Filepath to an image to use as the window's icon (string)
    t.window.width = 260              -- The window width (number)
    t.window.height = 260               -- The window height (number)
endconfig.ts
function fromImageToQuads(tilesheet, tileWidth, tileHeight)
  local tiles = {}
  local imageWidth = tilesheet:getWidth()
  local imageHeight = tilesheet:getHeight()
  for i = 0, imageHeight - 1, tileHeight do
    for j = 0, imageWidth - 1, tileWidth do
      table.insert(
        tiles,
        love.graphics.newQuad(
          j, i, tileWidth, tileHeight, imageWidth, imageHeight
        )
      )
    end
  end
  return tiles
endutils.ts

sprite.png sprite

Le code

function love.load()
    require "utils"

    love.graphics.setDefaultFilter("nearest") -- no bluring on tiles

    WINDOWWIDTH, WINDOWHEIGHT = love.window.getMode()
    TILESIZE = 32

    Tilesheet = love.graphics.newImage('assets/sprite.png')
    Tiles = fromImageToQuads(Tilesheet, 32, 32)
end

function love.update(dt)
end

function love.draw()
    love.graphics.scale(2, 2) -- zoom x2
    love.graphics.translate(WINDOWWIDTH/4-16,WINDOWHEIGHT/4-32) -- Center map
endmain.lua

On commence par écrire notre template de base avec tout ce qu’il nous faut pour commencer :

Ensuite, nous allons initialiser notre grille dans un tableau suivant notre tilesheet :

tilesheet numérotée

Pour rappel, l’index des tableaux en Lua commence par 1 et non 0. La premiere tile a donc l’index 1.

function love.load()

  ...

  GRID = {
    { 2, 2, 2 },
    { 2, 2, 7 },
    { 2, 2, 1 }
  }

endmain.lua

Maintenant nous allons devoir parcourir le tableau pour afficher une par une les cellules de notre grille. Habituellement, nous définirions l’axe X et Y de nos cases par ce genre de formule : x = X_index * 32, y = Y_index * 32. Ainsi, la cellule {1,1} serait affichée aux coordonnées x=32,y=32, la {0,2} a x=0,y=64, etc…

Dans notre cas, nous allons devoir prendre en compte le décalage sur les axes X et Y (voir commentaire du code).

function love.draw()

  ...

  for x, table in ipairs(GRID) do
    for y, cell in ipairs(table) do
      local isox = 0
        - (x * (TILESIZE / 2)) -- On décale la coordonnées X vers la gauche suivant l'index X de la case dans le tableau
        + (y * (TILESIZE / 2)) -- On décale la coordonnées X vers la droite suivant l'index Y de la case dans le tableau
      local isoy = 0
        + (x * (TILESIZE / 4)) -- On décale la coordonnées Y vers le bas suivant l'index X de la case dans le tableau
        + (y * (TILESIZE / 4)) -- On décale la coordonnées Y vers le bas suivant l'index Y de la case dans le tableau
      local tileNumber = cell
      love.graphics.draw(Tilesheet, Tiles[tileNumber], isox, isoy)
    end
  end
endmain.lua

A ce stade, nous devrions avoir ce genre de rendu :

premier rendu

Maintenant nous avons besoin de rajouter la notion de niveau, l’équivalent d’un axe Z en 3D. Nous allons modifier notre grille en conséquence, en ajoutant un troisième niveau servant de calque.

function love.load()

  ...

  GRID = {
    {
        { 2, 2, 2 },
        { 2, 2, 7 },
        { 2, 2, 1 }
    },
    {
        { 5, 4, 4 },
        { 3, 1, 1 },
        { 3, 8, 1 }
    }
  }
endmain.lua

Pour afficher notre second calque, nous allons décaler l’axe de chaque case. Cette fois l’axe Y, de moitié vers le haut, selon la position de son calque.

function love.draw()

  ...

  for index, layer in ipairs(GRID) do
    for x, table in ipairs(layer) do
      for y, cell in ipairs(table) do
        local isox = 0
          - (x * (TILESIZE / 2))
          + (y * (TILESIZE / 2))
        local isoy = 0
          + (x * (TILESIZE / 4))
          + (y * (TILESIZE / 4))
        local tileNumber = cell
        love.graphics.draw(Tilesheet, Tiles[tileNumber], isox, isoy - ((index - 1) * (TILESIZE / 2)))
      end
    end
  end
endmain.ts

Et voici le rendu final :

rendu final

Sources et outils


Partager sur: