Communauté

Les listes (ipairs ...
 
Notifications
Retirer tout

Les listes (ipairs / pairs) ce que j'ai compris... c'est que je n'ai rien compris.

5 Posts
3 Utilisateurs
1 Likes
369 Vu
0
Début du sujet

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.

Spoiler
code avant systeme 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

 

Spoiler
après avoir faire les changements pour le pop de 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.

 

 

5 Réponses
1

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 =)

Ce message a été modifié Il y a 1 an 2 fois parRaphytator
0
Début du sujet

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... 😓

 

 

0
Posté par: @vikanim

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

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: @vikanim

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?

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: @vikanim

2) 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: @vikanim

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?

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.

Ce message a été modifié Il y a 1 an parRaphytator
0

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.

0
Début du sujet

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. 😀 

Répondre
Share:

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.