Fichiers multiples et portée des variables avec LÖVE2D

Fichiers multiples

Avec plusieurs fichiers, notre code sera mieux organisé et plus facile à lire. Créons un nouveau fichier et appelons-le example.lua. Assurez-vous qu’il soit dans le même répertoire que main.lua.

Dans ce fichier, créons une variable. Nous mettrons –! file: nom du fichier tout en haut pour préciser dans quel fichier le code doit être placé :

1
2
--! file: example.lua
test = 20

Maintenant dans main.lua, ajoutons print(test). Quand vous exécuterez le jeu, vous verrez que test vaut nil. C’est parce que nous n’avons pas encore chargé le fichier example.lua. Nous devons le faire avec la fonction require en passant le nom du fichier (sans l’extension) comme argument :

1
2
3
--! file: main.lua
require("example")
print(test)

Nous n’avons pas besoin d’ajouter l’extension “.lua” au nom du fichier car Lua le fait automatiquement pour nous.

Nous pouvons également placer le fichier dans un sous-répertoire, mais dans ce cas, assurez-vous d’utiliser le chemin complet avec des points comme séparateurs :

1
2
-- Utilisez . au lieu de /
require("dossier.sousdossier.example")

Maintenant, quand vous affichez la variable test après avoir chargé example.lua, elle devrait avoir la valeur 20.

Dans cet exemple, test est ce que nous appelons une variable globale. C’est une variable que nous pouvons utiliser partout dans notre projet. À l’opposé d’une variable globale, nous avons la variable locale. Vous pouvez en créer une en écrivant le mot-clé local devant son nom :

1
2
--! file: example.lua
local test = 20

Exécutez le jeu pour constater que l’affichage de la variable test donne une nouvelle fois nil. C’est dû à la portée des variables.

Portée des variables

Les variables locales ont une portée limitée. Dans le cas de notre variable test, la portée est limitée au fichier example.lua. Cela signifie que test peut être utilisée partout dans ce fichier, mais pas dans d’autres fichiers.

Si nous souhaitons créer une variable locale dans un bloc comme une fonction, une condition if ou une boucle for, alors sa portée sera limitée à ce bloc :

1
2
3
4
5
6
7
--! file: example.lua
if true then
  local test = 20
end

print(test)
-- Sortie: nil

test vaut nil car l’instruction print se trouve en dehors de la portée de la variable.

Les paramètres d’une fonction sont traités comme des variables locales. Ils n’existent que dans la fonction.

Pour vraiment comprendre comment la portée (scope) fonctionne, examinons le code suivant :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
--! file: main.lua
test = 10
require("example")
print(test)
-- Sortie: 10

--! file: example.lua
local test = 20

function some_function(test)
  if true then
    local test = 40
    print(test)
    -- Sortie: 40
  end

  print(test)
  -- Sortie: 30
end

some_function(30)

print(test)
-- Sortie: 20

Si vous exécutez le jeu, il devrait afficher successivement 40, 30, 20, 10. Analysons ce code étape par étape :

  1. Le premier affichage à l’intérieur de la condition if est 40.
  2. Ensuite, nous affichons test une nouvelle fois et sa valeur est 30, qui est la valeur passée en argument à la fonction. Le paramètre test n’est pas affecté par la variable test définie à l’intérieur du bloc if. Dans ce bloc, la variable locale test masque temporairement le paramètre test.
  3. En dehors de la fonction, nous affichons test. Cette fois, il vaut 20. La variable test créée au début du fichier example.lua n’est pas affectée par les variables homonymes à l’intérieur de la fonction.
  4. Enfin, nous affichons la variable test dans le fichier main.lua et elle vaut 10. La variable globale n’est pas affectée par la variable locale dans le fichier example.lua.

Voici une représentation graphique de la portée de chaque variable test pour clarifier :

Représentation de la portée de chaque variable
Représentation de la portée de chaque variable

Lorsque vous déclarez une variable locale, vous n’êtes pas obligé de lui donner une valeur immédiatement :

1
2
local test
test = 20

Les valeurs de retour

Comme les fonctions, les fichiers peuvent également renvoyer une valeur. Si nous ajoutons return 10 à la fin du fichier example.lua et que dans le fichier main.lua nous écrivons print(require("example")), cela affichera 10.

Un cas d’utilisation courant est de retourner une table contenant des fonctions ou des variables que vous souhaitez rendre accessibles depuis d’autres fichiers :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
--! file: example.lua
local myModule = {}

myModule.value = 42

function myModule.doSomething()
  print("Action effectuée !")
end

return myModule

--! file: main.lua
local module = require("example")
print(module.value)       -- Affiche: 42
module.doSomething()      -- Affiche: Action effectuée !

Résumé

Avec require, nous pouvons charger d’autres fichiers Lua dans notre projet. Les variables globales peuvent être utilisées partout, tandis que les variables locales sont limitées à leur portée (scope). Les variables locales n’affectent pas les variables ayant le même nom en dehors de leur portée. Cette organisation en fichiers multiples et l’utilisation judicieuse des portées nous permettent de structurer efficacement notre code et d’éviter les conflits de noms de variables.