Log In  

Hi, I find myself doing lots of OOP in pico-8 just as I find it a bit more manageable in my head even if it isn't token efficient. I used to create objects with the following method. As a slightly aside point what does cls in the setmetatable call stand for or do? I never worked it out.

setmetatable(actors, {
  __call = function (cls, ...)
    local self = setmetatable({}, cls)
    self:_init(...)
    return self
  end,
})

function actors:_init(type,x,y,xoffset,yoffset,xoffset2,yoffset2,health)
    --actors initilization function sets all of it's parameters
    return self
end
add(actorTable,actors(--parameters))

Recently however I have been creating them with the following method.

function createenemy(x,y,path)
    local enem = {}
        --Enemy variables and methods are initialized
    enem.update = function(this)
    end
    enem.hit = function(this)
    end
    enem.draw = function(this)
        spr(this.sprite,this.x,this.y)
    end
    add(enemy,enem)
    add(objects,enem)
end

Is one of these better than the other? The latter feels simpler at least to me but are there any performance differences or style issues?

P#45195 2017-10-14 02:47 ( Edited 2017-10-15 10:11)

1

I only just started programming in Lua/Pico-8 but also use OOP a lot. Although OOP in Lua is a bit expensive token-wise, I exploit inheritance a lot in my current game, and I feel that with the re-use this enables, the ratio "functionality realized"/"tokens used" is good enough. Either way, I find it most natural way to program as well.

I use (variants of) both approaches. A drawback of the second approach is that it requires more memory. Class method implementations are not shared between instances of the same class. The code looks more natural though and is less verbose. Furthermore, private members can be defined as locals in the create function, which makes them really private and saves tokens (no need to prefix them with "this.")

As far as I know, you cannot implement inheritance using the second approach, so if you want to use that, you have to resort to the first approach.

So, I tend to use the second approach for classes that have only one/a few instances at a time, where I do not need inheritance (e.g. Game, Level) and the second for all other in-game objects (Enemy, Mover, Object, Tile, etc)

Btw, "cls" is a shorthand for class.

P#45201 2017-10-14 06:49 ( Edited 2017-10-14 10:49)
2

LUA OOP really shines for large projects...where token will hit you hard!
Suggest an hybrid approach, using the object:method call to support method inheritance:

— base constructor
function make_object(x,y)
 local c={
  x=x,y=y,
  update=update_object
 }
 return c
end
function make_plane(x,y)
 local c=make_object(x,y)
 c.update=update_plane
 return c
end
function update_object(self)
 self.x+=1
 self.y+=2
end
function update_plane(self)
 — call super function
 update_object(self)
 — do smthg plane specific...
end

— create a plane
local p=make_plane(5,7)
p:update() — same as p.update(p) but prettier!
P#45202 2017-10-14 10:41 ( Edited 2017-10-14 14:41)
1

Okay cool. As a note you can also do inheritance in the second approach by returning the object you create and then having classes that inherit from that parent class call the parents initialization function and set their local obj to that before doing the changes necessary.

function createBullet(x,y,owner)
    local obj = {}
        --initialize variables
    obj.x = x
    obj.y = y

    obj.destroy = function(this)
        createexplosion(this.x,this.y)
        del(objects,this)
    end

    -- The body of the update function that all types of bullet will execute
    -- If other objects inherit from this class they can overwrite the update method
    -- but still call the common bullet behaviour from commonUpdate()
    obj.commonUpdate = function(this)
        --code
    end

    obj.update = function(this)
        this.commonUpdate(this)
    end

    add(objects,obj)--Optional, if you add here then ones inheriting shouldn't add it
    return obj
end
function createEnemyTrackBullet(x,y)
    local obj =createbullet(x,y,false)
    --Changes variables as necessary

    obj.update = function(this)
        --Calls the inherited common behaviour
        this.commonUpdate(this)
        --Then unique behavior for the child
        if (this.timer == 30*4) this.destroy(this)
    end

    obj.draw = function(this)
    end
end
P#45222 2017-10-15 06:11 ( Edited 2017-10-15 10:11)

[Please log in to post a comment]

Follow Lexaloffle:          
Generated 2024-04-19 20:58:57 | 0.011s | Q:17