Log In  

I never used LUA before (I come from JS and Ruby), today a saw a bit about OOP here and since pico doesn't support metatables i'd like to know if this is the right way to OOP:

local player = {}

function Player.new()
    local self = {}

    self.x = 64
    self.y = 100
    self.width = 20
    self.height = 5
    self.color = 7

    self.get_x = function() --one way for method
        return self.x
    end

    function self.set_x(new_value) --another way for method
        self.x = new_value
    end

    function self.draw()
        rectfill(self.x, self.y, self.x + self.width, self.y + self.height, self.color)
    end

    return self
end

function redraw()
    rectfill(0,0,128,128,0)
end

function _init()
    player1 = Player.new()
end

function _update()
    local x = player1.get_x()
    player1.set_x(x + 1)
end

function _draw()
    redraw()
    player1.draw()
end

So... If there is anything wrong* there please tell me :), i know i could make a player.move method but i wanted to see getters and setters visually.

*I do consider anti-patterns as wrong.

P#13153 2015-08-26 01:01 ( Edited 2015-08-26 11:16)

Generally I'd say you want to avoid OOP on a platform like this if you can since it incurs a lot of overhead, but, this seems like the right way to do it for sure.

You should call member functions with a : though, such as

player1:set_x(x+1)

Which isn't totally necessary the way you've written it, because the local self is being captured in your function definitions. The ":" captured the caller table and registers it as the "self" token for within the function. If you don't do that there won't be anything to reference the caller, since it'll just treat it like a typical agnostic function call.

It would be more efficient to write the member functions outside the new function, and then just assign them to the newly created table within it.

P#13154 2015-08-26 01:17 ( Edited 2015-08-26 05:17)

yeah, doing OOP type stuff in pico8 will really kill your token space. definitely wouldn't recommend using getters or setters.

Without metatables it's really quite a pain.

P#13156 2015-08-26 03:56 ( Edited 2015-08-26 07:56)

@lulublululu

What's the difference between adding them directly or outside the constructor? I did this way because I think it's visually nice, but if it really makes a difference I'll chnge it (if you could edit this example to show me your way it would be awesome)

@impbox

Could you elaborate more about this "token space"? I tried to google it but i can't figure out what you mean by that.

*edit

~Added: Token-based code limiting (8192 tokens, 32k ascii text)~

Do you mean this? Am i limited to 8k total chars in my games? Can use load() to expand this?

*another edit

from what i tested, a token is either a command or a char out of a command, and its limited on the cartridge itself so i guess i can use load() to bypass the limit :D

P#13159 2015-08-26 07:01 ( Edited 2015-08-26 11:15)

Regarding tokens, pico-8 has two limits on how much code you can include in a cartridge. The first is a simple limit on how much text you can have in your code section (32k characters is the limit). The second is a slightly less obvious limit on the number of tokens in your code (8192 tokens is the limit).

If you load up a cartridge and then in the console type 'info', you'll see how many characters and tokens it is using. And yeah, going full OOP will eat up a lot of extra tokens, which for many people is the limiting factor for how much stuff they can fit (it's harder to hit the text limit, though I have done it).

P#13160 2015-08-26 07:08 ( Edited 2015-08-26 11:08)
1

pico-8 cartridges have a limited capacity(and as such, a limited capacity for code), which is measured as tokens. You can see how much space you've used at the bottom-right of the code editor. I could try and explain how much a token is but it'd be easy to get a feel for it if you take note of when the counter goes up as you write code.

Function separation:

player = {}

function player:draw()
 rectfill(self.x, self.y, self.x + self.width, self.y + self.height, self.color)
end

function player.new()
 local p = {}

 -- functions(and tables, jsyk) are not copied, but referenced, so it is more efficient in an OOP context where the idea is to create many copies of the same thing
 p.draw = player.draw

 --etc
end

Each time you define a function, Lua is compiling that function into bytecode and storing it in memory(at least temporarily due to garbage collection, which in a sense can be even more of a waste). So if you're defining that function each time you create an object, you're storing it in memory that many times. The pico is a pretty performance-critical platform, and redefining a function n times comes at a large and unnecessary CPU and memory cost, both are precious. By referencing the function defined at program start, it can exist in one place only--the Player table--and everything else just hooks onto that.

I hope that helps you out :) good luck

P#13161 2015-08-26 07:15 ( Edited 2015-08-26 11:17)

@scottb

Yep, I hope this limit get raised, but load() workaround can probably help for now :)

@lulublululu

Thanks for the explanation, low-level and memory management is something i'm really bad at (I blame the high-level langs for that)

P#13162 2015-08-26 07:16 ( Edited 2015-08-26 11:20)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-04-18 22:18:26 | 0.014s | Q:21