Log In  
Follow
merwok

people often ask about object orientation (OOP) and inheritance, but can get confusing or incomplete guides. I want to help everyone understand how prototypes work!

lua does support object-oriented programming (but does not require it), based on prototype inheritance — not classes.
metatables are part of this but also often misunderstood. this is a complete explainer that I wrote on discord and keep not putting here in a clean way. so I am putting it here as it is!

so what is a prototype?

goblin={
 sp=42,
}

function goblin:new(x,y)
 local obj={x=x, y=y}
 return setmetatable(obj, {__index=self})
end

function goblin:draw()
 spr(self.sp,self.x,self.y)
end

gob1=goblin:new(40,40)
gob2=goblin:new(60,70)

alright so this is like 6 different things working together.

1) table with methods: goblin is a table with property sp and methods new and draw (a method is a function attached to an object)

calling goblin:new(40,40) is the same as goblin.new(self,40,40); self is «the object we are working on»; defining function goblin:draw() is the same as function goblin.draw(self) and the same as goblin={sp=42, draw=function(self) spr(...) end, somethingelse=true}

there is a difference between the two methods in my example: when we call goblin:new, the self param inside it will be the goblin table itself (the prototype), but when we have gob1:draw() then self inside draw will refer to gob1.

2) metatables. there are special methods that lua uses to implement operators (+, /, .., etc). the method for addition for example is __add (we call these metamethods). if I want to be able to do vector1 + vector2for my custom vector tables for example, I need to define a method named __add but I can’t do it in the vector prototype table, lua will not look it there; it is required to define these metamethods in a table’s metatable. (the metatable is similar to a class in other object-oriented languages: it is the template, or the definition, or the model for many tables.) so that’s what happens in goblin:new: I define a metatable with one metamethod and set it on my goblin object.

3) prototype. these are great! if I have 50 goblins on screen and they have different health and coordinates but the same properties for sprite, width, height, etc, and the same methods for update, attack, draw, etc, I would like to define all the shared things in one place, then have custom things in each goblin table. that’s what a prototype is for! here in goblin example we have sp and draw shared, and in a specific goblin table (it starts as obj on line 6, then it’s gob1 or gob2 in my example) we have specific data like x and y.
much more info on this really useful site: https://gameprogrammingpatterns.com/prototype.html

alright so how do I say «gob1 and gob2 should delegate to goblin prototype for some properties»? I define a metatable with an __index property. it is called by lua when I do gob1.sp and sp is not found inside gob1. it can be a function (can be useful to have a dynamic property that’s computed from other properties) or another table: the prototype!
more: https://www.lua.org/pil/13.4.1.html

now this is the cool thing with prototype-based object-oriented language that you don’t have in such a nice way with class-based OO languages
what if I want 40 goblins on screen and 10 archer goblins? these should have a different sprite and different attack method.

archer=goblin:new()

archer.sp=52

function archer:attack(target)
 --use the bow
end

arcgob1=archer:new(20,50)
arcgob2=archer:new(40,70)

look at this from bottom to top:

  • arcgob1.x will be 20, y 50
  • arcgob1’s and arcgob2’s prototype is archer, because when we call archer:new, self on line 6 of my first code block points to archer
  • arcgob1.sp is 52 (the value comes from the prototype)
  • arcgob1:attack(hero) will use our archer:attack method.
  • arcgob1:draw() will use goblin:draw! archer itself is a table that has goblin for prototype
    draw is not found in arcgob1, look at its prototype archer, not found, look at its prototype goblin, found! call it with self pointing to arcgob1.

result:

[ Continue Reading.. ]

24
5 comments



Looking at lucky draw and the game with bbs thread title "Fit" Santa (https://www.lexaloffle.com/bbs/?pid=fit_santa_00-1) was displayed with & quot ; (can’t type it here even in backticks!)

1
1 comment



In game code, calling ls() only returns names of cart files.

To make it possible to write local game launchers and other mini-splores, it would be nice to have a way to get directories too (some of us are hoarders and have to organize carts).

Ideas:

ls()     -- same as now
ls(0x2)  -- get directories only
ls(0x3)  -- (maybe) get other kinds of files
         -- (for art tools and such, to build dialogs instead of -i / stdin / drag n drop)

-- or
ls()     -- unchanged
lsdir()  -- new

-- will also need `cd(path)` to go there and list carts, or `ls(path)`

Thanks for considering this!

4
18 comments



Would be useful to have an export option (in the console and in the command-line interface) to get the label image as a PNG, to print labels for physical carts or for emulation frontend metadata for example. Could be 'export game.label.png', using the same resolution as GIFs.

9
9 comments



To ease the workflow of developing with p8 file, then saving as PNG for sharing, it would be really useful to have a command-line switch to save as PNG (combined with the positional parameter that loads a cart), for example: pico8 game.p8 -save game.png

This would behave like 'SAVE game.png' in the console, adding the .p8 string in the middle, but not prompting for overwrite confirmation (goal is headless/automatic conversion, like -export — of course errors are possible if the cart doesn’t respect limits).

Rationale: I find myself working with both P8 and PNG carts for the same game/project, using the P8 file as authoritative version (limits don’t prevent saving + compatible with all text tools) and also saving as PNG to see what the label looks like and share it when desired. It is cumbersome to work with the P8, save, save as png, confirm overwrite, then have to remember to load the P8 to avoid that the next save saves PNG then have to overwrite the P8. I would prefer to consider the PNG form a compiled form that I don’t edit, and avoid human mistakes by saving it using a command line or makefile.

Another use case from Sam Hocevar on discord: he wanted to convert P8 to PNG to study the compression algo, and had to resort to export to JS, extract cart data, serialise it, save in blank cart, which is quite convoluted.

5
3 comments



Hi! It would be convenient to have an option in the cart submenu to save a file from BSS to local carts, for systems that are not always connected.

For the carts that only have numerical IDs or generated names, it would be great to have a new RENAME command in the console :)

10
18 comments



In the code editor, add a new tab with the first line being a comment line containing only puny caps and spaces, then add a second comment line with regular text. Hover over the tab, the title preview shows the second comment instead of the first. Bug doesn’t happen if the title mixes cases ("--UI helpers" is ok).

2 comments



I wondered why I was not logged in when opening some links, but I was logged in in other tabs.
Found out that the website answers to both lexaloffle.com and www.lexaloffe.com, but logged in status is not shared.

Possible solutions:

  • change cookies to be valid for both variants
  • pick one variant as canonical and redirect transparently

Thanks!

5 comments



Hello! On the Carts category page https://www.lexaloffle.com/bbs/?cat=7&sub=2 , the three featured carts at the top are not real links (a elements), but divs with a custom JavaScript handler. This does not work with all the tools that know about links: ctrl+click to open in a new tab, middle click, long press on mobile, bookmark link, contextual menu, search links in page, etc. Please consider changing this!

4 comments