Les listes (ipairs / pairs) ce que j'ai compris... c'est que je n'ai rien compris.
Bonjour/ Bonsoir.
Voilà quelques jours que je suis en train de programmer un "pong" pour assimiler les concepts de base. (oui je prend mon temps 😓 )
Après avoir fini de coder les reactions de la balle et des pad, etc... j'essaye de m'attaquer à faire "pop" plusieures balles après un certain temps en jeu.
ayant déjà coder tout sur la balle. j'essaye de reproduire le système d'ajout de listes dans une autre liste ( comme dans l'exemple du "dlc" de david sur la trainée de balle dans pong). Mais ça ne marche pas....
je vous met la page de code avant d'essayer de mettre le systeme de pop de balle.
local balle = {} balle.x = 188 balle.y = 100 balle.image = {} balle.timer = 1 balle.shadow = 0 balle.vx = 1 balle.vy = 1 balle.speed = 1 scoreJ1 = 0 scoreJ2 = 0 listeTrail = {} function balle.load() balle.image[1] = love.graphics.newImage("pongInGame/ball/ball1.png") balle.image[2] = love.graphics.newImage("pongInGame/ball/ball2.png") balle.image[3] = love.graphics.newImage("pongInGame/ball/ball3.png") balle.image[4] = love.graphics.newImage("pongInGame/ball/ball4.png") balle.image[5] = love.graphics.newImage("pongInGame/ball/ball5.png") end function balle.update(dt) balle.timer = balle.timer + 0.4*60*dt if balle.timer >= #balle.image +1 then balle.timer = 1 end balle.shadow = balle.y + 3 -------mouvement de la balle ----------- balle.x = balle.x + balle.vx*balle.speed*60*dt balle.y = balle.y + balle.vy*balle.speed*60*dt ---balle sur les bords---------------- if balle.y <= 8 then balle.vy = -balle.vy balle.y = 8 end if balle.y >= 220 - 8 then balle.vy = -balle.vy balle.y = 220 - 8 end ----------point marqué------------------- if balle.x <= 0 then scoreJ2 = scoreJ2 +1 balle.x = 188 balle.y = 100 end if balle.x >= pad[2].x +20 then scoreJ1 = scoreJ1 +1 balle.x = 188 balle.y = 100 end ---- reaction sur pad --------------- if balle.x - 8 <= pad[1].x + 12 and balle.x -8 >= pad[1].x then if balle.y + 8 >= pad[1].y and balle.y - 8 <= pad[1].y + 34 then balle.vx = -balle.vx balle.x = pad[1].x + 13 + 8 balle.speed = balle.speed +0.2 end end if balle.x + 8 >= pad[2].x - 12 and balle.x +8 <= pad[2].x then if balle.y + 8 >= pad[2].y - 34 and balle.y -8 <= pad[2].y then balle.vx = -balle.vx balle.x = pad[2].x - 13 - 8 balle.speed = balle.speed +0.2 end end ---------- trainée de balle----------------------------- for n=#listeTrail,1,-1 do local t = listeTrail[n] t.vie = t.vie - dt t.taille = t.taille - 3*dt if t.vie <= 0 then table.remove(listeTrail, n) end end local maTrainee = {} maTrainee.x = balle.x maTrainee.y = balle.y maTrainee.vie = 0.5 maTrainee.taille = 6 table.insert(listeTrail,maTrainee) end function balle.draw() local frameBalle = math.floor(balle.timer) --------------ombrage-------------- love.graphics.setColor(0,0,0,0.4) love.graphics.draw(balle.image[1], balle.x, balle.shadow, 0, 1,1, balle.image[1]:getWidth()/2, balle.image[1]:getHeight()/2) love.graphics.setColor(1,1,1,1) --------- dessin trainée--------------------------------------- for n=1,#listeTrail do local t = listeTrail[n] love.graphics.setColor(1,1,0, t.vie/2) love.graphics.circle("fill", t.x, t.y, t.taille) love.graphics.setColor(1,1,1,1) end ----------balle--------- love.graphics.draw(balle.image[frameBalle], balle.x, balle.y, 0, 1,1, balle.image[1]:getWidth()/2, balle.image[1]:getHeight()/2) love.graphics.print("scoreJ1 : "..scoreJ1, 50, 20) love.graphics.print("scoreJ2 : "..scoreJ2, 50, 40) end return balle
local balle = {} balle.maBalle = {} balle.maBalle.x = 188 balle.maBalle.y = 100 balle.maBalle.image = {} balle.maBalle.timer = 1 balle.maBalle.shadow = 0 balle.maBalle.vx = 1 balle.maBalle.vy = 1 balle.maBalle.speed = 1 scoreJ1 = 0 scoreJ2 = 0 listeTrail = {} function balle.load() balle.maBalle.image[1] = love.graphics.newImage("pongInGame/ball/ball1.png") balle.maBalle.image[2] = love.graphics.newImage("pongInGame/ball/ball2.png") balle.maBalle.image[3] = love.graphics.newImage("pongInGame/ball/ball3.png") balle.maBalle.image[4] = love.graphics.newImage("pongInGame/ball/ball4.png") balle.maBalle.image[5] = love.graphics.newImage("pongInGame/ball/ball5.png") end function balle.update(dt) balle.maBalle.timer = balle.maBalle.timer + 0.4*60*dt if balle.maBalle.timer >= #balle.maBalle.image +1 then balle.maBalle.timer = 1 end balle.maBalle.shadow = balle.maBalle.y + 3 -------mouvement de la balle ----------- balle.maBalle.x = balle.maBalle.x + balle.maBalle.vx*balle.maBalle.speed*60*dt balle.maBalle.y = balle.maBalle.y + balle.maBalle.vy*balle.maBalle.speed*60*dt ---balle sur les bords---------------- if balle.maBalle.y <= 8 then balle.maBalle.vy = -balle.maBalle.vy balle.maBalle.y = 8 end if balle.maBalle.y >= 220 - 8 then balle.maBalle.vy = -balle.maBalle.vy balle.maBalle.y = 220 - 8 end ----------point marqué------------------- if balle.maBalle.x <= 0 then scoreJ2 = scoreJ2 +1 balle.maBalle.x = 188 balle.maBalle.y = 100 end if balle.maBalle.x >= pad[2].x +20 then scoreJ1 = scoreJ1 +1 balle.maBalle.x = 188 balle.maBalle.y = 100 end ---- reaction sur pad --------------- if balle.maBalle.x - 8 <= pad[1].x + 12 and balle.maBalle.x -8 >= pad[1].x then if balle.maBalle.y + 8 >= pad[1].y and balle.maBalle.y - 8 <= pad[1].y + 34 then balle.maBalle.vx = -balle.maBalle.vx balle.maBalle.x = pad[1].x + 13 + 8 balle.maBalle.speed = balle.maBalle.speed +0.2 end end if balle.maBalle.x + 8 >= pad[2].x - 12 and balle.maBalle.x +8 <= pad[2].x then if balle.maBalle.y + 8 >= pad[2].y - 34 and balle.maBalle.y -8 <= pad[2].y then balle.maBalle.vx = -balle.maBalle.vx balle.maBalle.x = pad[2].x - 13 - 8 balle.maBalle.speed = balle.maBalle.speed +0.2 end end ---------- trainée de balle----------------------------- for n=#listeTrail,1,-1 do local t = listeTrail[n] t.vie = t.vie - dt t.taille = t.taille - 3*dt if t.vie <= 0 then table.remove(listeTrail, n) end end local maTrainee = {} maTrainee.x = balle.maBalle.x maTrainee.y = balle.maBalle.y maTrainee.vie = 0.5 maTrainee.taille = 6 table.insert(listeTrail,maTrainee) --------pop de balle------------ local popTimer = 0 popTimer = popTimer + 1 if popTimer >= 70 then table.insert(balle, maBalle) popTimer = 0 end end function balle.draw() local frameBalle = math.floor(balle.maBalle.timer) --------------ombrage-------------- love.graphics.setColor(0,0,0,0.4) love.graphics.draw(balle.maBalle.image[1], balle.maBalle.x, balle.maBalle.shadow, 0, 1,1, balle.maBalle.image[1]:getWidth()/2, balle.maBalle.image[1]:getHeight()/2) love.graphics.setColor(1,1,1,1) --------- dessin trainée--------------------------------------- for n=1,#listeTrail do local t = listeTrail[n] love.graphics.setColor(1,1,0, t.vie/2) love.graphics.circle("fill", t.x, t.y, t.taille) love.graphics.setColor(1,1,1,1) end ----------balle--------- love.graphics.draw(balle.maBalle.image[frameBalle], balle.maBalle.x, balle.maBalle.y, 0, 1,1, balle.maBalle.image[1]:getWidth()/2, balle.maBalle.image[1]:getHeight()/2) love.graphics.print("scoreJ1 : "..scoreJ1, 50, 20) love.graphics.print("scoreJ2 : "..scoreJ2, 50, 40) end return balle
après avoir fait ce changement. le programme ne plante pas mais pas de nouvelles balles. j'ai aussi essayer avec des love.graphics.print pour regarder ce qu'il se passe mais aucune nouvelle balle n'est créer.
Je pensais avoir compris... mais il n'en ai rien... 😣
merci. de m'avoir lu. En esperant qu'une personne pourra me donner un conseil. ( je précise que j'ai bien lu et relu le cours sur les listes et sur l'inventaire...)
bonne journée/soirée à vous.
Le problème vient d'une mauvaise compréhension et utilisation des listes.
Tu as ta balle qui est déclarée de la sorte :
local balle = {} balle.maBalle = {} balle.maBalle.x = 188 -- [...]
suite à quoi, lorsque tu veux rajouter une nouvelle balle, tu fais :
local popTimer = 0 popTimer = popTimer + 1 if popTimer >= 70 then table.insert(balle, maBalle) popTimer = 0 end
Plusieurs problèmes à ce niveau là.
Tout d'abord, tu initialise une variable popTimer à 0 juste avant de l'incrémenter, ce qui fait qu'à chaque tour de boucle il sera égal à 0 et donc jamais ne sera >= à 70 pour rentrer dans la condition.
Ensuite, quand tu fais un table.insert, tu rajoute un élément à une liste. Cette liste devient une table numérative, c'est à dire qu'elle est indexée via un numéro (qui commence par 1).
Exemple avec valeurs simples :
local tableTest = {} table.insert(tableTest, 10) table.insert(tableTest, 15) table.insert(tableTest, 32) print(tableTest[1]) --> 10 print(tableTest[2]) --> 15 print(tableTest[3]) --> 32
Exemples avec listes dans listes :
local tableTest2 = {} local test = { x = 10, y = 20 } local test2 = { x = 30, y = 40 } table.insert(tableTest2, test) table.insert(tableTest2, test2) print(tableTest2[1].x) --> 10 print(tableTest2[2].y) --> 40
Si on reprend ton code, ta liste balle devrait ressembler à ceci :
-- Représentation de la table balle -> {} balle.maBalle -> {} balle.maBalle.x -> 188 balle.maBalle.y -> 100 balle.maBalle.[...] -> [...] balle[1] -> balle.maBalle balle[2] -> balle.maBalle [...]
Donc, dans la structure de ta table, ça n'est pas correct. D'autant plus qu'en Lua, quand tu passe une liste en paramètre de fonction, ça ne copie pas les valeurs de la liste, mais ça passe la liste en référence, ce qui permet par exemple d'en modifier les valeurs. Donc chaque nouvelle balle sera une référence de la balle principale, et non une nouvelle balle à part entière.
Dans ton draw tu n'affiche que la balle principale :
love.graphics.draw(balle.maBalle.image[frameBalle], balle.maBalle.x, balle.maBalle.y, 0, 1,1, balle.maBalle.image[1]:getWidth()/2, balle.maBalle.image[1]:getHeight()/2)
Il faudrait draw les autres balles de la liste pour les voir s'afficher.
Je pense aussi que mélanger le module qui gère la balle avec la liste qui contient la balle est une mauvaise idée.
Voici ce que je te propose comme solution :
Il faut revoir la logique de tes listes. Fais une fonction qui permet d'ajouter de nouvelles balles comme ceci :
-- Table qui contiendra toutes les balles local balles = {} -- Table qui contiendra les images de ta balle local imagesBalles = {} -- Initialisation du timer de spawn de balles local timeSpawnBall = 0 -- Fonction pour créer de nouvelles balles function newBall(pX, pY) local ball = {} ball.x = pX ball.y = pY ball.timer = 1 ball.shadow = 0 ball.vx = 1 ball.vy = 1 ball.speed = 1 ball.frame = 1 -- Variable pour connaitre la frame actuelle de la balle table.insert(balles, ball) end -- Création de la première balle newBall(188, 100)
Dans ton update :
for i=1, #balles do local b = balles[i] -- Création d'un raccourci pour éviter d'avoir à écrire balles[i] à chaque fois b.timer = b.timer + 0.4*60*dt if b.timer >= #imagesBalles +1 then b.timer = 1 end b.shadow = b.y + 3 -------mouvement de la balle ----------- b.x = b.x + b.vx*b.speed*60*dt b.y = b.y + b.vy*b.speed*60*dt -- [...] suite du code à adapter -- Spawn de nouvelles balles timerSpawnBall = timerSpawnBall + 1 * dt if timerSpawnBall >= 5 then -- grâce à 1 * dt, ça compte en seconde, donc 5 = 5 secondes local x = love.math.random(0, 200) -- Défini un nombre entre 0 et 200 local y = love.math.random(0, 100) -- Défini un nombre entre 0 et 100 newBall(x, y) timerSpawnBall = 0 end end
Pour le spawn de nouvelle balles, je lui ai fait avoir une position aléatoire sur l'écran, mais c'est pour l'exemple. Tu adapteras par la suite en fonction de tes besoins.
Dans ton draw :
for i=1, #balles do local b = balles[i] love.graphics.draw(imagesBalles[b.frame], b.x, b.y, 0, 1,1, imagesBalles[1]:getWidth()/2, imagesBalles[1]:getHeight()/2) end
Ce sera déjà plus simple pour la compréhension, et ça permet de traiter autant de balles que les tableaux puissent en accueillir.
J'ai donné mon exemple avec une boucle for classique étant donné que tu es au début de l'apprentissage, mais tu pourrais également utiliser un for in pairs (exemple avec le draw, k = key, soit l'index du tableau, et v = value, soit la valeur de la clé actuelle) :
for k, v in pairs(balles) do love.graphics.draw(imagesBalles[v.frame], v.x, v.y, 0, 1,1, imagesBalles[1]:getWidth()/2, imagesBalles[1]:getHeight()/2) end
J'espère que ma réponse t'aidera. Si tu as des soucis de compréhension, n'hésite pas à le dire que je détaille les parties sur lesquelles tu as du mal =)
Merci à vous pour ce long message d'explication! 😀
Je comprend beaucoup mieux maintenant.
J'ai réussi à mettre en application ce code. Et les balles spawn!! youpi! 😆
Bon, après, viens de nouveaux problèmes ( que je vais pouvoir régler tout seul.) les balles spawns de plus en plus vite. et dès qu'une balle tape un pad, le dessin de la trainée passe au dessus de la balle. puis ça se met à planter (à cause de la trainée). haha
mis à part ça j'ai quelques points que j'aimerai éclaircir si tu veux bien. 🤔
1) Dans ton exemple j'ai vu que tu n'utilisais pas de function ****.load() , Quelle est la différence entrer écrire en dehors du .load() et à l'intèrieur?
2) le [i] à une signification particulière?
3) et autre question bonus qui n'a rien avoir avec ce code: Si je fait un scale (5/5) par combien dois-je diviser getWidht() et getHeight() pour tomber au milieu de l'ecran?
Je n'arrive pas à trouver la formule... ça doit être un nombre à virgule, mais je ne comprend pas pourquoi... 😓
Posté par: @vikanimBon, après, viens de nouveaux problèmes ( que je vais pouvoir régler tout seul.) les balles spawns de plus en plus vite. et dès qu'une balle tape un pad, le dessin de la trainée passe au dessus de la balle. puis ça se met à planter (à cause de la trainée). haha
En effet ça risque de corser la difficulté ^^
Le code que je t'ai noté est bien entendu à adapter, et non à copier tel quel.
Posté par: @vikanim1) Dans ton exemple j'ai vu que tu n'utilisais pas de function ****.load() , Quelle est la différence entrer écrire en dehors du .load() et à l'intèrieur?
Tout dépend du contexte, là en l'occurrence je n'ai pas voulu complexifier trop les choses en rajoutant de la structure sachant que ce n'était pas le sujet.
Comme tu utilises un module, ton load est appelé quand tu le décide. Si tu écris en dehors de cette fonction (en l'occurrence avant pour plus de visibilité), le code sera appliqué au chargement du fichier, et uniquement à ce moment. C'est pourquoi généralement dans mon code j'ai 2 fonctions de démarrage : init et load.
L'init ne s'appelle qu'une seule fois au démarrage, et contient des éléments qui n'ont besoin d'être initialisés qu'une seule fois, par exemple la création de boutons, cadres, textes etc...
Le load quand à lui est appelé à chaque fois qu'on vient sur la scène. Il contient donc des éléments qu'on a besoin de remettre à chaque fois qu'on vient sur cette scène. Ça peut être par exemple le fait de mettre des valeurs spécifiques à des variables.
Posté par: @vikanim2) le [i] à une signification particulière?
Si tu parles du [i] dans balles[i], alors oui c'est une signification particulière que tu dois connaitre sur le bout des doigts, sinon tu vas avoir des difficultés quand à l'utilisation des tables. Je te conseille de revoir les cours de base concernant les listes pour revoir tout cela, car il s'agit d'un fondamental indispensable.
Posté par: @vikanim3) et autre question bonus qui n'a rien avoir avec ce code: Si je fait un scale (5/5) par combien dois-je diviser getWidht() et getHeight() pour tomber au milieu de l'ecran?
Question piège ou erreur d'écriture. Dans scale(5/5) je lis : scale de 5 divisé par 5, soit scale(1) : pas de changement quand à l'affichage classique.
Mais j'imagine que tu voulais dire 5 en sx et 5 en sy, auquel cas tout l'écran est grossi 5 fois.
Si tu souhaites avoir le milieu du contenu après avoir multiplié le scale par 5, dans ce cas il faut multiplier ton affichage par 5 également, puis diviser le tout par 2 afin d'avoir le milieu :
scale = 5 milieuX = love.graphics.getWidth() * scale / 2 milieuY = love.graphics.getHeight() * scale / 2
Attention car comme l'écran aura été grossi, le milieu n'apparaitra pas dans la fenêtre.
Il ne faut pas utiliser de scale pour tes sprites, c'est une très mauvaise pratique, courante chez les débutant.
Pourquoi ?
- Parce que tu ne sauras plus calculer tes collisions, car ce que le joueur voit et la vraie taille de l'image est différente, donc faut faire plein de calculs inutiles
- C'est très laid
- Ca prend du temps à la carte graphique, elle a autre chose à faire
Pourquoi cela existe alors ?
- Pour faire des effets visuels, zoom, etc.
- Pour des cas exceptionnels, ou pour les débutants qui font l'erreur de l'utiliser 🙂
A toi d'adapter tes graphismes avec un logiciel de dessin afin qu'ils aient exactement la taille dont tu as besoin, et que tu puisses les afficher SANS toucher les paramètres de scale.
super. merci pour toutes ces réponses. j'y vois plus clair. et désolé du temps extrêmement long de réponse. ça fait un moment que je n'était plus par ici.
et bonne année. 😀
- 6 Forums
- 262 Sujets
- 906 Posts
- 1 En ligne
- 45.6 {numéro}K Membres