SoFunction
Updated on 2025-04-07

Lua object-oriented and inheritance

Finally here, I believe that most people who are learning Lua are developing mobile online games.

And they are basically focused on the hot update features of scripting languages, so full script development has become very popular.
For Lua, which is not very popular (relative to mainstream languages ​​such as C++ and Java), it requires a short time to develop games, which is not simple for novices.

That's why everyone is more accustomed to using object-oriented thinking to make trouble!

Okay, I won’t nag anymore, I don’t like nagging the most. (Xiaoruo: Yes, yes, you are not nagging at all, hurry up and start talking!)

1. Class objects

As for how to create a class, everyone already knows it is just a table.
So, how to implement it if you want to use this class to create multiple objects?
Just use meta tables and meta methods.
 
The following code:

Copy the codeThe code is as follows:

    TSprite = {
        x = 0,
        y = 0,
    }
    function TSprite:setPosition(x, y)
        = x;
        = y;
    end
  
    function TSprite:new()
        o = {}
        setmetatable(o, {__index = self});
        return o;
    end
  
    local who1 = TSprite:new();
    local who2 = TSprite:new();
    who1:setPosition(1, 2);
    who2:setPosition(44, 6);
print("who1 coordinate(" .. .. "," .. .. ")");
print("who2 coordinate(" .. .. "," .. .. ")");

Pay attention to the new function of TSprite. A new table is created in the function and a meta table is set for the new table. The __index meta method of this meta table is TSprite itself, and finally returns this new table.

Therefore, all new tables generated by new can use TSprite's function and various field properties (because the value of __index is TSprite).

Therefore, we use the new function to create who1 and who2 and call their setPosition function. Finally, the x and y values ​​of who1 and who2 are different.
This is the object of the class.

2. The __index of the class object is the same TSprite, why can the x and y values ​​be different?

I wonder if you have such a doubt, that is, why are the x and y of who1 and who2 different? Are they not calling the setPosition function in the end? Didn’t the x value of TSprite finally be called when calling?
It will be a little confused here, and it will be fine if you make sense:

1). When setPosition does not exist in who1, go back to search in the __index element method, and then the setPosition function of TSprite will be found.
2). In the setPosition function, = x is used, and the self at this time is who1. The x field does not exist in who1. Therefore, if we want to print the value, we actually printed the x value of TSprite.
3). But, note, but here it is. The __index meta method is used for calling, not for assignment. Therefore, the sentence = x actually just assigns the x field of the table who1. Who1 does not have an x ​​field, so it is assigned a value, so who1 has an x ​​field, and who1 will no longer search for x field in TSprite.
4). Therefore, when assigning the x and y fields of who1 and who2, it will not affect TSprite at all.

3. Save resources – use TSprite as metatable

Let’s take a closer look at the new function. When we set the metatable for the new table, we recreated a metatable: setmetatable(o, {__index = self});

If you do this, every time you call the new function to create a new object, a new meta table will be generated. Although this expense seems to be negligible, you who have obsessive-compulsive disorder must like the following code:

Copy the codeThe code is as follows:

    function TSprite:new()
        o = {}
        setmetatable(o, self);
        self.__index = self;
        return o;
    end

In this new new function, self is used as the meta table, and then self is used as the value of __index.

It looks like this and I can't get around it. I like that everyone can't get around it, so I can nag again:
1). When calling the new function, self is actually TSprite itself. TSprite can be used instead. However, in order to lay the foundation for the future, it is better to use self here.
2). self.__index = self. Don’t be scared by this code. In fact, the same thing is still the same. Setting the __index meta method of the meta table is equivalent to TSprite.__index = TSprite.
3). Is there no problem with TSprite itself as the value of __index? It's true that there is no problem. TSprite is also a table. The table can be used as a meta table. The meta table can have a __index meta method, which has no hero at all.
4). Therefore, through this little trick, we avoid creating an additional new meta table every time we call the new function.

4. I don’t like the rich second generation—Inheritance

We always joke about the rich second generation, but who doesn’t want to be a rich second generation in his heart?
There are not many people like me who are determined to become a rich generation by themselves~ (Xiao Ruo: Ah my bah~!)
 
So, how to achieve inheritance in Lua? It's very simple, but it needs to be thought about carefully, as follows:

Copy the codeThe code is as follows:

    TSprite = {
        x = 0,
        y = 0,
    }
    function TSprite:setPosition(x, y)
        = x;
        = y;
    end
  
    function TSprite:new()
        o = {}
        setmetatable(o, self);
        self.__index = self;
        return o;
    end
  
    local MoneySprite = TSprite:new();
    function MoneySprite:setPosition(x, y)
print("Haha, I am a rich second generation and there is no need to change at all.");
    end

TSprite still hasn't changed, but let's look at MoneySprite. According to previous understanding, it is an object of TSprite.
However, the term "object" is determined by ourselves, but in fact it is just a table.

At this time, we modified the setPosition function of MoneySprite, so when calling the setPosition function of MoneySprite, it has nothing to do with TSprite.

But, this is not the point, the point is the next code:

Copy the codeThe code is as follows:

    local who = MoneySprite:new();
    who:setPosition(44, 6);
  
print("who coordinate(" .. .. "," .. .. ")");

We call MoneySprite's new function again to create a new object.
What's going on? The key is the code in the new function. At this time, who is the self in the new function?
The new function is called by MoneySprite, so self is MoneySprite.
So the meta table of the new object is MoneySprite, and the __index of the meta table is also MoneySprite.

Therefore ~! It's amazing. When calling who setPosition function, it actually calls the setPosition function of MoneySprite.

So, who is the object of MoneySprite, and MoneySprite is a subclass of TSprite.

Let's take a look at the output results:

Copy the codeThe code is as follows:

[LUA-print] Haha, I am a rich second generation and I don’t need to change at all.
[LUA-print] who coordinates (0,0)

How about it? The implementation method of inheritance is also very simple, right?
If you are unfamiliar with meta tables, meta methods, and self, you may not be able to understand them for a while. It doesn’t matter. Think for a while, or think back the next day, and you will suddenly become enlightened.

5. End

Before I knew it, I had already written 20 articles in this series, which was really beyond my expectations.
I could actually stick with it, but the effect of writing articles is really good, and the efforts of more than one hour a night are also worth it.
At least, my understanding of Lua's basics has been further consolidated~
 
OK, keep sticking to it... (Xiaoruo: So it's ~! Why do you have to use ellipsis every time? Isn't using exclamation marks better expressing your determination...)