Lunar Lander – Devlog #1

12 réflexions au sujet de “Lunar Lander – Devlog #1”

  1. C’est avec beaucoup de plaisir que je découvre et lis ce nouveau devlog, merci beaucoup de nous partager ton avancée et tes connaissances. Je vais suivre avec intérêt !

  2. Tout comme Lost… super devlog très instructif ! Merci beaucoup. 🙂

    Je ne veux pas te dire de bêtise, mais pour additionner 2 vecteurs, en fait tu peux résumer le souci à ça : comment additionner 2 tables (tout est tables en lua). Pour ça il y a une métaméthodes __add qui te permet de faire ton table1 + table2 (transposable aux vecteurs donc) via les métatables donc.

    Tu trouveras plus d’infos dans les ateliers maths, notamment celui dédié aux vecteurs justement. 🙂
    Je ne sais pas si ça t’aidera ou si tu cherchais une autre façon !

    Hâte de voir tes prochains devlogs en tout cas.

  3. Merci à toi aussi :D, c’est vraiment encourageant.
    J’ai pas hyper l’habitude de faire ce genre d’exercice à la base (les devlog). Du coup, si ça intéresse les gens c’est d’autant plus motivant à continuer.

    Effectivement, c’est bien ce que j’avais trouvé. Il en existe également d’autre pour la multiplication, la division, la conversion en string etc..
    Mais quand j’ai essayé, ça plantait. Je suis donc revenu en arrière. Du coup, j’ai envie de jeter un oeil à l’atelier math. Je dois pas être loin d’y arriver mais avec la « pression » de l’enregistrement j’ai préféré passer à autre chose.

  4. Salut ! On reconnait de suite les pros du code ^^

    Quand j’ai cherché à apprendre les métatables je suis tombé là dessus :
    http://wxlua.free.fr/Tutoriel_Lua/Tuto/Metatables/metatables2.php
    avec la fonction :
    maMetaTable.__index(la_table, la_key)

    et ils m’ont perdu avec cette phrase du coup :
    « la_table » est l’argument de la table qui a été indexé et « la_key » est la clé qui va essayer de lire la table.
    C’est probablement à cause de mon manque d’expérience et je ne comprends pas ce qu’ils veulent dire par « table indexée », ni ce que c’est la « clé qui va lire ». C’est pas très débutant friendly
    Du coup j’avais pas du tout compris à quoi servait __index. Maintenant que tu dis que c’est comme le prototype en JS ça me parle déjà un peu plus…

    Mais en fait je ne comprends toujours pas à quoi ça sert ^^’ : Account.__index = Account
    Si la propriété à laquelle on souhaite accéder n’existe pas, on remonte dans __index, mais qu’est-ce qui se passe ensuite du coup ? On peut mettre des propriétés dans __index ?
    Mais pareil du coup en quoi __index sert à faire de la POO ?
    Sur le tutoriel Lua c’est juste écrit: « utilisée lorsqu’on tente d’accéder à un élément de la variable inexistant. Sera exploité pour la création d’une classe dans la partie POO »

    Oui désolé pour moi c’est loin d’être clair 🙁
    En fait il me manque beaucoup d’informations, même dans les explications du Tutoriel Lua. Sûrement un manque d’expérience en POO

  5. Salut !

    Ouais en effet, c’est pas évident à comprendre au départ. Perso, j’y arrive parce que j’arrive à faire le lien avec des choses que je connais (et c’est surement pour pouvoir faire ce genre de lien plus facilement que David enseigne plusieurs langage, framework et outil).
    De ce que je comprends, en Lua on parle de table, mais on pourrait changer le terme table par le terme « objet » en Lua, le résultat serait le même.
    Ce que je veux dire c’est que la programmation orientée objet en Lua utilise ce qu’ils appellent des tables.

    Pour être honnête, la phrase que tu cite, il faut savoir comment ça marche avant de pouvoir la comprendre (ce qui n’est pas très utile pour une explication).

    Je vais essayer d’être plus explicite avec un example (attention j’ai pas testé le code, la plupart sont des illustrations de mes propos).

    Si je prend un bout de mon code, j’ai :


    local hero = {
    position = Vector:new(),
    angle = 0,
    origin = Vector:new(),
    velocity = Vector:new(),
    angularSpeed = 3,
    thrustPower = 5,
    state = "flying",
    sprite = love.graphics.newImage("assets/images/ship.png"),
    flameSprite = love.graphics.newImage("assets/images/engine.png"),
    maxSpeed = 5
    }

    D’un point de vue POO, j’ai un objet avec des propriété (« position », « angle » etc). D’un point de vue Lua, on dira que j’ai une table indexée. ça veut simplement dire que c’est une table et qu’elle fonctionne avec des index (ici les index sont « position », « angle » etc).

    En lua si je fait ensuite :


    print(hero.angle)

    J’aurai un affichage de l’angle du vaisseau.

    Si je fait :


    print(hero.blabla)

    On s’attend à avoir un affichage « nil » étant que la propriété n’existe pas.
    Cependant, avant de voir si Lua doit afficher « nil », Lua va vérifier s’il n’existe pas une « solution de secours » dans la metatable. Avec le bout de code en l’étant, il n’y a pas de metatable, donc j’aurai un nil.

    Si maintenant on considère le code suivant :


    Spacecraft = {
    blabla = "trop cool"
    }

    function Spacecraft:new()
    local hero = {
    position = Vector:new(),
    angle = 0,
    origin = Vector:new(),
    velocity = Vector:new(),
    angularSpeed = 3,
    thrustPower = 5,
    state = "flying",
    sprite = love.graphics.newImage("assets/images/ship.png"),
    flameSprite = love.graphics.newImage("assets/images/engine.png"),
    maxSpeed = 5
    }

    setmetatable(hero, self);
    self.__index = self;

    print(hero.blabla)

    return hero;
    end

    Le résultat du print(hero.blable) ne sera pas « nil ». La raison est que à hero j’ai défini comme metatable « Spacecraft ». Ce qu’il va se passer lors du print, c’est que Lua va chercher dans hero si l’index (ou la clé, c’est un synonyme ici) existe dans hero. Elle n’existe toujours pas dans hero, mais il y a une metatable! Donc Lua va fouiller dans la metatable s’il n’y a pas un « __index » qui traine et en fonction de ce qu’est __index va l’utiliser pour savoir comment trouver la propriété « blabla ».
    Si __index est une table, il va surement regarder si cette table possède « blabla ». C’est justement le rôle de « self.__index = self; » (self fait référence à Spacecraft ici).

    En gros si j’affiche mon objet/table héro au complet j’aurai quelque chose comme (après la ligne avec le setmetatable):

    hero = {
    position = Vector:new(),
    angle = 0,
    origin = Vector:new(),
    velocity = Vector:new(),
    angularSpeed = 3,
    thrustPower = 5,
    state = "flying",
    sprite = love.graphics.newImage("assets/images/ship.png"),
    flameSprite = love.graphics.newImage("assets/images/engine.png"),
    maxSpeed = 5,
    [[metatable]] = {
    __index = {
    blabla = "trop cool"
    }
    }
    }

    (C’est juste une vision mentale ici, je sais pas si [[metatable]] est un index de la table hero, mais c’est pour illustrer que hero possède une metatable maintenant).

    Donc Lua trouvera dans hero, une metatable qui possède un __index et __index possède la propriété recherchée.

    ///BEBIN WARNING///

    __index étant une table, __index peut lui même posséder une metatable

    et cette metatable peut elle même posséder un __index

    Je pourrai avoir un truc du genre

    hero = {
    [[metatable]] = {
    __index = {
    blabla = "trop cool",
    [[metatable]] = {
    __index = {
    blabla = "trop cool"
    mega_blabla = "trop cool plus fort"
    }
    }
    }
    }
    }
    print(hero.blabla) -- affichera "trop cool"
    print(hero.mega_blabla) -- affichera "trop cool plus fort"
    print(hero.blabla_pas_top) -- affichera "nil"

    ///END WARNING///

    Et Lua va (ce que j’appelle) « remonter » dans les __index jusqu’à trouver ce qu’il cherche et donner le résultat; ou bien jusqu’à ce qu’il n’y ait plus d’__index et renvoyer « nil ».

    Par contre on est en Lua, et on est un peu libre de faire « kesskon veu ». __index pourrait tout à fait être une fonction et Lua le permet.
    De la même manière qu’avant, si Lua ne trouve pas un index dans la table, il va chercher dans la metatable et voir que __index existe mais il s’agit d’une fonction cette fois.
    Dans ce cas là, il va appeller la fonction en passant en paramètre la table (ici ce serait donc hero) et le nom de la propriété (ou index, ou clé, tu l’appelles comme tu préfères).
    Donc là, Lua appelerait la fonction un peu de la manière suivante (c’est encore une expérience de pensée):


    hero.metatable.__index(hero, "blabla") -- là index peut être appeler comme une fonction car c'est une fonction

    Ensuite c’est à la fonction qui a été placé dans __index de savoir comment traiter le problème.

    Pour avoir le même résultat que print blabla de tout à l’heure mais en utilisant une fonction:


    Spacecraft = {}
    Spacecraft.__index = function(table, index) {
    if (index == "blabla") then
    return "trop cool"
    end

    return nil
    }

    function Spacecraft:new()
    local hero = {
    position = Vector:new(),
    angle = 0,
    origin = Vector:new(),
    velocity = Vector:new(),
    angularSpeed = 3,
    thrustPower = 5,
    state = "flying",
    sprite = love.graphics.newImage("assets/images/ship.png"),
    flameSprite = love.graphics.newImage("assets/images/engine.png"),
    maxSpeed = 5
    }

    setmetatable(hero, self);
    self.__index = self;

    print(hero.blabla)

    return hero;
    end

    Je sais pas si je suis hyper clair. En tout cas, c’est comme ça que je comprends les choses à l’heure actuelle.

  6. Pour ta question du « Account.__index = Account ». ça n’a d’interêt que lorsque t’utilises « Account » en tant que metatable via « setmetatable ».
    Comme ça, __index possédera toutes les propriétés de Account et donc Lua pourra les trouver en « remontant » les __index.

    Pour répondre à la question de comment faire de la POO avec ça:

    La POO par définition est le fait d’avoir des objets (des tables ici) qu’on fait interagir entre eux. C’est pas une solution qui est meilleure que les autres, c’est juste une façon de penser. On peut faire de la programmation sans penser POO, ça marche aussi et les débuts de l’informatique on commencer sans POO (de ce que je sais).

    Mais ici, je dirai que si on a différents « concept » comme un héro, ennemi et pnj. On pourrait créer un nouveau concept « Personnage » qui possède toutes les propriétés communes (et même des fonctions pourquoi pas) aux concepts héro, ennemi et pnj.
    Par exemple, ils ont tous une position. Ben « position » pourrait être une propriété dans Personnage mais pas dans héro, ni de ennemi ni de pnj.
    Mais héro, ennemi et pnj pourrait avoir dans metatable.__index une table Personnage. Comme ça on pourrait faire

    print(hero.position)
    print(ennemi.position)
    print(pnj.position)

    Et Lua trouvera la propriété position qui vient du concept « Personnage ». Le but ici est d’éviter de dupliquer du code (mais ça a certains désavantages aussi attention comme avoir des metatable dans des metatables dans des metatables dans des metatables … et on peut s’y perdre).

    Pour aller plus loin, admettons que le héro et l’ennemi ont des points de vies. On pourrait définir un concept « PersonnageTuable » (le nom est pourri désole je suis pas inspiré).
    Ce concept « PersonnageTuable » pourrait avoir en tant qu’__index une table Personnage (et donc une position) et les concept héro et ennemi pourrait avoir en tant qu’__index une table « PersonnageTuable ».
    Du coup, héro et ennemi ont des points de vie ainsi qu’une position. Le pnj lui aura une position mais pas de point de vie (car il n’est pas un « PersonnageTuable »).

    Encore une fois, c’est une façon de penser, on peut faire autrement.

  7. Je me permets de te répondre JaDona, mais peut-être que Gamabunta pourra être plus précis que moi.

    On est d’accord, c’est pas du tout débutant-friendly les métatables de toute façon…on comprend bien pourquoi David fait l’impasse de cette fonctionnalité de Lua dans les cours.

    Quand tu demandes à Lua d’utiliser le contenu d’une table, si ce contenu n’existe pas il ne te renvoie pas immédiatement nil, il va voir s’il y a une métatable reliée à cette table, avec la métaméthode __index associée.

    Basiquement, la métaméthode __index fonctionne comme une fonction qui prend 2 paramètres, la table de base et le contenu introuvable dans celle-ci (la clé), puis qui renvoie la valeur recherchée dans une autre table (que tu auras indiqué dans la fonction). Exemple :

    entrepot = {pomme = 3, poire = 3, orange = 4}
    panier = {pomme = 1, poire = 2}

    mt = {}
    mt.__index = function(table, key)
    return entrepot[key] end

    setmetatable(panier, mt)

    print(panier.orange)

    Le résultat du print sera : 4
    NB : L’argument table doit rester « table », lua y met « panier » lorsque tu fais le print.

    Lua permet aussi un raccourci plutôt que de créer une fonction, c’est de faire pointer directement le __index vers une autre table (la table indexée), dans laquel il ira piocher ce que tu cherches.

    entrepot = {pomme = 3, poire = 3, orange = 4}
    panier = {pomme = 1, poire = 2}

    mt = {}
    mt.__index = entrepot

    setmetatable(panier, mt)

    print(panier.orange)

    Ca renvoie exactement le même résultat sans créer de fonction (plus optimisé donc).

    En fait c’est une façon de faire de l’héritage en lua, et je n’ai jamais testé, mais le fait de passer par la fonction permet de faire de l’héritage multiple si j’ai bien compris, entre autre.

    J’espère ne pas avoir empiré ton incompréhension. :p

  8. Merci pour vos réponses Gamabunta et Lysenti !

    Donc du coup en quelque sorte __index permet de désigner le « parent » de l’objet ?

    En fait j’ai été pas mal perturbé par l’atelier Shoot’em up parce que ce qu’il fait « ressemble » à de la poo. Avec les fonctions CreateEnemy() par exemple, où chaque ennemi aura des propriétés distinctes etc..
    Du coup j’ai du mal à différencier la pseudo-poo qu’on a vu à de la vraie poo. Ça se situerait dans l’héritage ? Ou peut être aussi dans le fait que ce ne sont peut être pas de vraies instances ?

  9. Oui, perso ça m’a semblé super naturel parce que je ne connaissais rien à la poo justement.
    Avec les fonctions d’usinage de type CreateSprite() etc, c’est une façon de faire des « classes » en lua en fait, et les instances sont les objets qui sortent de ces « usines ».

    Je ne sais pas si on peut parler de parent en lua… en tout cas c’est une façon de ne pas dupliquer du code ça c’est sûr (sans toutefois passer par des fonctions). Ce qui est, il me semble, le but premier de la poo.

    Après pour les différences entre la pseudo-poo en lua et la vraie poo, il faudrait demander à quelqu’un de plus expérimenté que moi… je crois par exemple qu’il y a la notion d’attribut privé ou public lorsque tu crées les constructeurs (les fonctions usines en lua), c’est-à-dire que tu peux modifier certaines variables héritées et pas d’autres. Et encore, il me semble avoir lu que la métaméthode __newindex permet d’empêcher la modification d’une variable…

    En fait on dit que lua peut simuler de la poo, parce qu’il faut passer par certains artifices propres au langage pour en faire, là où le C# l’intègre naturellement par exemple. En définitive ça permet d’avoir une compréhension plus claire de ce qu’est un objet en passant par le lua… enfin de mon point de vue !

  10. Effectivement Il y a des notions de « private », « protected » etc.. selon les langages pour gérer qui a accès à quoi.

    En tout cas c’est beaucoup plus clair maintenant. Merci à vous 🙂

Laisser un commentaire

Dialoguez avec les autres membres de la gamecodeur school.

Accédez maintenant à notre serveur Discord privé : Entraide, Game Jams, Partage de projets, etc.

Vous devez être membre de la Gamecodeur School Premium pour être autorisé à accéder au serveur.