Enclosed module state for each instance

What is the best way to enclose module for each instance of the game object with a script that uses that module?
For example, I have a module for animation and I want to use it for every game object, but with its own state for each instance, for example, each instance should have its actual anim or flip state.

I tried following these rules but probably need some more explanation on what is happening with module’s variables when the instance is created. Is it a good practice to assign a module to some self.variable?

You can write your module functions in the same way that you would a script function—with a self argument. You can pass in the same self from the script, or another table if you feel like keeping it separate. Any state data you want can be stored there.

I don’t know that it’s possible to have multiple instances of a module (it probably is with some rigmarole). When you require something it checks if that module has already been loaded, so all scripts will be using the same one. So it doesn’t make any difference if you save it in a self.variable or a normal local variable. The module is just a table of stuff, and the value of your variable is just a reference to the module table.

Can you give an example of some code that you have so far? Or describe what exactly you want to do?

2 Likes

try doing this in your module

local M = {}

function M.create(self , args) 
        local instance = {}
        instance.value = 5
        function instance.abc(args)
                return instance.value
       end
      return instance
end

return M

The create function here creates an instance of the variable “instance”, so all the functions and variables you put inside it will be local to the script calling it. For eg:

--assuming you have already required the module as my_module
function init(self)
  local a = my_module.create(args)
  a.value = 100
  print(a.abc())
end

will print 100, but if I change it in some other script, it will show the value assigned in that script.

BTW: see lowrezadventure by @britzl to understand more about it.

2 Likes

I think I got the understanding now more :smiley: I do tried to check how it works in lowrezadventure and some other project, but tried to do it in my way and it wasn’t working (requiring module to self, e.g. self.anim = require “utils.anim”). What is working for me is that I indeed create an instance containing the variables that I want to be owned by each instance and return metatable of the module with those variables instead. What I wanted to know is, what approach is the best to enclose values, but from now I see there are many ways and each have its advantages and disadvantages. I will add here code, but later today :wink:

I have a module with following functions:

function ANIM.create(id, initial_anim, initial_flip)
    local instance = {
	    id = id or go.get_id(),
	    my_flip = initial_flip or true,
	    anim = initial_anim or hash("idle")
    }
    return setmetatable(instance, { __index = ANIM })
end

function ANIM:get()
	print("FFF", self.anim, self.my_flip)
end

function ANIM:play(anim)
	assert(anim, "You must provide initial anim for animator")
	if (not self.anim) or (self.anim ~= anim) then
		msg.post("#sprite", "play_animation", { id = anim })
		self.anim = anim
	end
end

And then I instantiate an animator’s instance and implicitly pass self object to each function called on the instance, like this:

local animator = require "utils.animator"
function init(self)
      self.sprite = animator.create()
      self.sprite:play(hash("run"))

And now it seems like I can play different animation for each of instances of different game objects, I hope it is a good solution.

Earlier, when I wasn’t returning self from a module I tried to just:

 self.sprite = require "utils.animator"

But there were some unexpected bugs so I gave up (strange, because I thought it could work)

1 Like