【游戏开发】在Lua中实现面向对象特性——模拟类、继承、多态

 

一、简介

  Lua是一门非常强大、非常灵活的脚本语言,自它从发明以来,无数的游戏使用了Lua作为开发语言。但是作为一款脚本语言,Lua也有着自己的不足,那就是它本身并没有提供面向对象的特性,而游戏开发是一项庞大复杂的工程,如果没有面向对象功能势必会为开发带来一定的不便。不过幸好Lua中有table这样强大的数据结构,利用它再结合元表(metatable),我们便可以很方便地在Lua中模拟出类、继承和多态等面向对象编程具有的特性。

二、前提知识

  按照惯例,我们还是先来熟悉一下必要的前提知识,以便方便我们理解后续的代码。

1.表(table)

  (1)table 是 Lua 的一种数据结构,用于帮助我们创建不同的数据类型,如:数组、字典等;

  (2)table 是一个关联型数组,你可以用任意类型的值来作数组的索引,但这个值不能是 nil,所有索引值都需要用 "["和"]" 括起来;如果是字符串,还可以去掉引号和中括号; 即如果没有[]括起,则认为是字符串索引,Lua table 是不固定大小的,你可以根据自己需要进行扩容;

  (3)table 的默认初始索引一般以 1 开始,如果不写索引,则索引就会被认为是数字,并按顺序自动从1往后编;

  (4)table 的变量只是一个地址引用,对 table 的操作不会产生数据影响;

  (5)table 不会固定长度大小,有新数据插入时长度会自动增长;

  (6)table 里保存数据可以是任何类型,包括function和table;

  (7)table所有元素之间,总是用逗号 "," 隔开;

2.元表(metatable)

  关于元表的概念以及它的要点,我们已经在《【游戏开发】小白学Lua——从Lua查找表元素的过程看元表、元方法》这篇博客中做了深入地探讨,在此就不再赘述了,忘记了或者不熟悉的小伙伴可以去看一下。

三、Lua中实现类、继承、多态

1.利用Lua实现类

  在面向对象的特性中,类一般都有类名,构造方法,成员方法,属性等。下面我们就用Lua中的table和元表实现一下模拟类中的这些特性,Class.lua 代码如下:

 1 --类的声明,这里声明了类名还有属性,并且给出了属性的初始值
2 Class = {x=0,y=0}
3 --设置元表的索引,想模拟类的话,这步操作很关键
4 Class.__index = Class
5 --构造方法,构造方法的名字是随便起的,习惯性命名为new()
6 function Class:new(x,y)
7 local self = {} --初始化self,如果没有这句,那么类所建立的对象如果有一个改变,其他对象都会改变
8 setmetatable(self, Class) --将self的元表设定为Class
9 self.x = x --属性值初始化
10 self.y = y
11 return self --返回自身
12 end
13
14 --这里定义类的其他方法
15 function Class:test()
16 print(self.x,self.y)
17 end
18
19 function Class:plus()
20 self.x = self.x + 1
21 self.y = self.y + 1
22 end

  简单解释一下,在Lua中的类,其实都是table,因为table既可以存储普通变量又可以存储函数或者另一个table,利用这个特性,我们实现了面向对象的类中的方法、属性(字段)和构造方法。而设置元表和__index元方法这一步也是必不可少的,我们需要借助它的查找机制来实现类的继承和多态等。

2.利用Lua实现继承

  在上面我们实现了Lua中的类,那么实现继承也就不是什么难事了,SubClass.lua 代码如下:

 1 require 'Class'
2
3 --声明了新的属性Z
4 SubClass = {z = 0}
5 --设置元表为Class
6 setmetatable(SubClass, Class)
7 --还是和类定义一样,表索引设定为自身
8 SubClass.__index = SubClass
9 --这里是构造方法
10 function SubClass:new(x,y,z)
11 local self = {} --初始化对象自身
12 self = Class:new(x,y) --将对象自身设定为父类,这个语句相当于其他语言的super ,可以理解为调用父类的构造函数
13 setmetatable(self, SubClass) --将对象自身元表设定为SubClass类
14 self.z= z --新的属性初始化,如果没有将会按照声明=0
15 return self
16 end
17
18 --定义一个新的方法
19 function SubClass:go()
20 self.x = self.x + 10
21 end
22
23 --重定义父类的方法,相当于override
24 function SubClass:test()
25 print(self.x,self.y,self.z)
26 end

  代码里面的注释已经很全了,关键点是通过设置SubClass的元表为它的父类Class,从而很方便地实现了继承,这还是要归功于table的查找机制。在子类SubClass中,我们可以自由地新增字段和子类独有的新方法。而且还可以重定义或者说覆盖/重写父类的方法,类似于Java中的override,子类覆盖父类的虚方法。有了这些我们就可以模拟面向对象中的多态了。

3.利用Lua实现多态

  这里我们新建一个 Main.lua 将它作为我们程序的入口,在里面测试一下我们上面的代码是否如我们所期待的那样,Main.lua 代码如下:

 1 require 'Class'
2 require 'SubClass'
3
4 local a = Class:new() -- 首先实例化父类的对象,并调用父类中的方法
5 a:plus()
6 a:test()
7
8 a = SubClass:new() -- 然后实例化子类对象
9 a:plus() -- 子类对象可以访问到父类中的成员和方法
10 a:go() -- 子类对象调用子类中的新增方法
11 a:test() -- 子类对象调用重写的方法

  程序运行的输出结果如下:

1       1
11 1 0

  首先我们实例化父类对象并调用父类中的方法,结果输出了1 1,符合预期。接着我们再实例化了子类的对象,然后成功地访问到了父类中的成员变量和方法,并且还可以访问子类中的新增方法,最后我们再执行了重写过父类中虚函数的方法,结果输出 11 1 0,也是正确的。

四、总结

  通过简单地几步,我们就在Lua中成功地模拟了类、继承和多态的特性,这可以给我们程序开发带来了不少的方便。以Unity游戏开发举例,tolua/ulua是Unity游戏开发热更新方案中的一种,他们功能很强大,但是美中不足的一点就是它们没有提供面向对象的特性,所以在开发的时候,很多直接就是全局函数、全局变量和过程式的开发流程,影响了开发的效率,更对之后的维护带来诸多不便。因此我们就可以通过与本篇中类似的方法,改进tolua/ulua,让它们也可以实现面向对象开发。当然本篇中的代码只是作为抛砖引玉,它其实是十分简陋的,想用在商业项目中还需要做很多的改良与完善。至于如何改进tolua/ulua,让他们支持面向对象特性,我们将在以后的篇章中继续探讨。

  本篇博客中的代码已经同步到Github:https://github.com/XINCGer/Unity3DTraining/tree/master/SomeTest/Lua_Class   欢迎fork!

作者:马三小伙儿
出处:http://www.cnblogs.com/msxh/p/8469340.html 
请尊重别人的劳动成果,让分享成为一种美德,欢迎转载。另外,文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!

【转载】【游戏开发】在Lua中实现面向对象特性——模拟类、继承、多态的更多相关文章

  1. 【游戏开发】在Lua中实现面向对象特性——模拟类、继承、多态

    一.简介 Lua是一门非常强大.非常灵活的脚本语言,自它从发明以来,无数的游戏使用了Lua作为开发语言.但是作为一款脚本语言,Lua也有着自己的不足,那就是它本身并没有提供面向对象的特性,而游戏开发是 ...

  2. 【Unity游戏开发】Lua中的os.date和os.time函数

    一.简介 最近马三在工作中经常使用到了lua 中的 os.date( ) 和 os.time( )函数,不过使用的时候都是不得其解,一般都是看项目里面怎么用,然后我就模仿写一下.今天正好稍微有点空闲时 ...

  3. python中的面向对象学习以及类的多态

    接下来类的第三个重要的特性:多态(一种接口,多种实现) 多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特 ...

  4. Lua和C++交互 学习记录之九:在Lua中以面向对象的方式使用C++注册的类

    主要内容转载自:子龙山人博客(强烈建议去子龙山人博客完全学习一遍) 部分内容查阅自:<Lua 5.3  参考手册>中文版 译者 云风 制作 Kavcc vs2013+lua-5.3.3 在 ...

  5. lua 中的面向对象

    lua 是一种脚步语言,语言本身并不具备面向对象的特性. 但是我们依然可以利用语言的特性,模拟出面向对象的特性. 面向对象的特性通常会具备:封装,继承,多态的特性,如何在lua中实现这些特性,最主要的 ...

  6. Cocos2d-x 脚本语言Lua中的面向对象

    Cocos2d-x 脚本语言Lua中的面向对象 面向对象不是针对某一门语言,而是一种思想.在面向过程的语言也能够使用面向对象的思想来进行编程. 在Lua中,并没有面向对象的概念存在,没有类的定义和子类 ...

  7. lua中的面向对象编程

    简单说说Lua中的面向对象 Lua中的table就是一种对象,看以下一段简单的代码: 上述代码会输出tb1 ~= tb2.说明两个具有相同值得对象是两个不同的对象,同时在Lua中table是引用类型的 ...

  8. Lua中的面向对象编程详解

    简单说说Lua中的面向对象 Lua中的table就是一种对象,看以下一段简单的代码: 复制代码代码如下: local tb1 = {a = 1, b = 2}local tb2 = {a = 1, b ...

  9. Java语言中的面向对象特性总结

    Java语言中的面向对象特性 (总结得不错) [课前思考]  1. 什么是对象?什么是类?什么是包?什么是接口?什么是内部类?  2. 面向对象编程的特性有哪三个?它们各自又有哪些特性?  3. 你知 ...

随机推荐

  1. Luogu P4198 楼房重建 (李超线段树)

    题目 传送门 题解 首先转化成到(0,0)(0,0)(0,0)的斜率. 那么就是求多少个点是前缀最大值. 做法是线段树,用gao(i,x)gao(i,x)gao(i,x)表示在iii区间内,之前最大值 ...

  2. Longest Continuous Increasing Subsequence

    Description Give an integer array,find the longest increasing continuous subsequence in this array. ...

  3. Bootstap学习的实用网站

    基本CSS样式 http://v2.bootcss.com/base-css.html 93 Twitter Bootstrap HTML Templates https://shapebootstr ...

  4. bzoj 1396/2865: 识别子串 后缀自动机+线段树

    水水的字符串题 ~ #include <map> #include <cstdio> #include <cstring> #include <algorit ...

  5. Python的模块,模块的使用、安装,别名,模块作用域

    模块和包 所谓的模块就是将不同功能的函数分别放到不同的文件中,这样不仅有利于函数的维护,也方便了函数的调用.在Python中,一个.py文件就是一个模块(Module). 在模块的上层有一个叫做包(P ...

  6. tornado解析post数据的问题

    解析tornado查询参数: self.request.query_arguments self.get_query_argument[s](参数名称) 解析tornado的post参数: self. ...

  7. sql 分组后每组查询10个

    SELECT ID,Name,Class ROW_NUMBER() OVER(PARTITION BY Class ORDER BY ID) as NUM 主要是用到 rownum 里面的 PARTI ...

  8. DES算法实现

    概述(团队项目) DES是一个分组加密算法,它以64位为分组对数据加密.同时DES也是一个对称算法:加密和解密用的是同一个算法.DES是一个包含16个阶段的"替换–置换"的分组加密 ...

  9. MySQL数据库可以用任意ip连接访问的方法

    > use mysql; > update user set host='%' where host='localhost'; > flush privileges;

  10. vue-resource在vuecli3中请求headers修改

    this.$resource.delete({ user_code: Cookie.get("empid"), date: date, file_name: file_name } ...