Hello there!
I have been exploring Pico8 for over 2 years now trying to understand coding with let's say "some" progress.
But I'm stuck with Tables. I mean, I get the concept but there's something I haven't got to fully understand therefore I get mixed results.
So I created actors (player, enemy) as tables but I can't make them spawn several instances on screen. So far I have got to draw 5 enemies on stage (at random position) but they keep appearing all the time (where they should appear once), any light about what I'm doing wrong? here's the code:
--init
function _init()
--globals
wave=5
w=112
h=112
--player
pyr={
spt=1,
x=w/3,
y=h/3,
life=10,
spd=2,
flp=false,
idle=true,
}
enms={} --enemies
enm={ --single enemy
spt=10,
life=5,
spd=1,
flp=false,
idle=true,
draw=function()
spr(enm.spt,flr(rnd(w)),flr(rnd(h)))
end,
}
for a=1,wave do
add(enms,enm)
end
end
--draw
function _draw()
cls()
print(#enms,20,20,7) --checking created instances from enms table
foreach(enm,enm:draw())
end
I have read tutorials, videos and everything available but still I haven't figured it out yet :( Any help is much appreciated.
When you assign a table to a variable, or add it to a list, you create a reference to the table in memory. In your code, enm={...} creates a table, then assigns a reference to that table to the enm variable. add(enms,enm) then takes the reference to the table stored in enm and adds it to the enms list. It does not make a copy of the table itself, it just makes a copy of the reference. So your enms table actually ends up with 5 references (from the 5 waves) to the same table.
If you want to create five separate enemy tables, one way is to create a function that makes and returns the enemy table, then call that function five times:
function make_enemy() return { spt=10, life=5, spd=1, flp=false, idle=true, draw=function() spr(self.spt,flr(rnd(w)),flr(rnd(h))) end, } end for a=1,wave do add(enms,make_enemy()) end |
One way to think of it is the {} braces are what create the table, and everything else just refers to the table. Because the function call evaluates a new pair of {} braces each time, it's actually creating a new table and returning it. In the previous version, the {} braces were only encountered once, so it only made one table.
Note that I had to make a change to the draw() function to use "self" to refer to the enemy being drawn. This is a special name that is set to the current enemy when you use the enm:draw() syntax. That's how draw() knows which table it belongs to.
This pattern can be improved so that it doesn't create a new copy of the draw() method for each enemy table, to save on memory. This involves a concept called prototypical inheritance, and uses a Lua feature called metatables. It's not that complicated but you can ignore this for now and come back to it if you find you need it.
P.S. With draw() as a method like this, your foreach() will need to be something like:
foreach(enms, function(enm) enm:draw() end) |
foreach() takes a table and a function, and the function needs to be a regular function that takes the element as its argument, not a method of the element. In this version, I create an anonymous function for this purpose.
You might prefer making draw_enemy(enm) a regular function instead of a method, then just do:
foreach(enms, draw_enemy) |
Awesome, thanks! I'll follow your explanation in detail and will come back :)
Hello again!
I got to finally handle the tables' nature (sort of speak) so I've doing a lot of progress, thanks for the help!
Now I have just a little question, I need to print the x position of one of the enemies that I created from the table/wave method but I only get the "NIL value" error message. My question is if it's possible to get such value? I'm using something like:
IF (BLT.X>ENM.X) THEN DEL (BLT,SELF) END
The overall goal is to compare the bullet's x position with enemy's x position to set a collision and destroy both.
Thanks in advance!
[Please log in to post a comment]