尝试在 Lua 中实现面向对象的编程,但效果不佳
Trying to implement object-oriented programming in Lua, but it's not quite working
好的,所以我正在尝试按照此处的说明进行操作:https://www.lua.org/pil/16.1.html 在 Lua(以及 LOVE 游戏框架)中执行类似于 OO 编程的操作,但它不起作用。这是我的代码的核心。我有一个通用的 Object
class:
local Object = {}
function Object:load(arg)
end
function Object:update(dt)
end
function Object:draw()
end
function Object:new(arg)
o = {}
setmetatable(o, self)
self.__index = self
o:load(arg)
return o
end
return Object
和一个继承自它的Ship
class:
Object = require('objects.object')
local Ship = Object:new()
Ship.sprite = love.graphics.newImage('assets/sprites/ship.png')
Ship.sprite:setFilter('nearest', 'nearest', 0)
Ship.px = Ship.sprite:getWidth()/2
Ship.py = Ship.sprite:getHeight()/2
function Ship:load(arg)
self.x = arg.x or 0
self.y = arg.y or 0
self.sx = arg.sx or arg.s or 1
self.sy = arg.sy or arg.s or 1
self.rot = arg.rot or 0
self.tint = arg.tint or {255, 255, 255}
end
function Ship:draw()
love.graphics.setColor(self.tint)
love.graphics.draw(self.sprite, self.x, self.y, self.rot,
self.sx, self.sy, self.px, self.py)
love.graphics.setColor({255, 255, 255})
end
return Ship
现在的问题是,我使用以下代码将其中两个 Ships 创建为另一个对象的成员:
self.ship1 = Ship:new({x=50, y=self.y1, s=2, tint={0, 0.5, 1}})
self.ship2 = Ship:new({x=750, y=self.y2, s=-2, tint={1, 0.5, 0}})
但是当我画它们的时候,我只看到了一个——第二个。事实证明,就像上面的代码没有将 Ship
的新实例分配给 ship1
和 ship2
,而是 直接分配给 self
,出于我无法理解的原因。我是不是做错了什么或者这是解释器的一个奇怪的错误?
已解决!显然,需要的是这个小片段:
function Object:new(arg)
local o = {}
setmetatable(o, self)
self.__index = self
o:load(arg)
return o
end
在我所有的 new
方法中将 o
设置为本地解决了所有问题。我不知道它到底是如何工作的,但我假设在设置元表时将它放在全局变量 space 中会破坏某些东西。
这不是解释器的错误,而是语言的设计行为。 o={}
创建全局变量,这不是程序员在这里期望的。 "Why it is so?" 是语言创造者经常被问到的问题。有 many efforts 可以更简单地控制该行为。
没有 local
的 o = {}
创建全局变量 全局变量可以在程序中的所有函数之间访问和共享,除非您使用花哨的环境范围技术。在函数内部使用全局变量为各种副作用打开了大门,你应该小心副作用。
我删除了一些语法糖并添加了上面的代码可以等效地写成如下:
Object.new = function(table_before_colon,arg)
highlander = {} --global variable, there can be only one
setmetatable(highlander,table_before_colon);
table_before_colon.__index = table_before_colon;
highlander:load(arg) -- table_before_colon.__index.load(highlander,arg)
return highlander
end
local Ship = Object:new()
--global highlander == Ship
--Ship.new points to Object.new
function Ship:load(arg)--equivalent to: Ship.load=function(self,arg)
--code that sets fields of the `self` object and is called from within new
self.x = arg.x or 0 -- equivalently highlander.x=arg.x or 0
end
现在,如果在 new
开始到 new
returns 期间没有发生任何事情,那么全局变量的存在无关紧要。但是,显然,您的其他代码与此类似:
local OtherObject = Object:new()
--otherObject == highlander
OtherObject.load = function(new_other_obj,arg)
--highlander == new_other_obj
new_other_obj.ship1 = Ship:new({x=50, y=self.y1, s=2, tint={0, 0.5, 1}})
--highlander == new_other_obj.ship1
new_other_obj.ship2 = Ship:new({x=750, y=self.y2, s=-2, tint={1, 0.5, 0}})
--highlander == new_other_obj.ship2
end
因此,OtherObject.load
调用其他函数,这些函数也访问和修改同一个全局变量。
local some_object = OtherObject:new()
returns 调用结束时的全局变量,在 [=18=20=] 调用中最后设置为 ship2
=] 内部调用 OtherObject:new
.
好的,所以我正在尝试按照此处的说明进行操作:https://www.lua.org/pil/16.1.html 在 Lua(以及 LOVE 游戏框架)中执行类似于 OO 编程的操作,但它不起作用。这是我的代码的核心。我有一个通用的 Object
class:
local Object = {}
function Object:load(arg)
end
function Object:update(dt)
end
function Object:draw()
end
function Object:new(arg)
o = {}
setmetatable(o, self)
self.__index = self
o:load(arg)
return o
end
return Object
和一个继承自它的Ship
class:
Object = require('objects.object')
local Ship = Object:new()
Ship.sprite = love.graphics.newImage('assets/sprites/ship.png')
Ship.sprite:setFilter('nearest', 'nearest', 0)
Ship.px = Ship.sprite:getWidth()/2
Ship.py = Ship.sprite:getHeight()/2
function Ship:load(arg)
self.x = arg.x or 0
self.y = arg.y or 0
self.sx = arg.sx or arg.s or 1
self.sy = arg.sy or arg.s or 1
self.rot = arg.rot or 0
self.tint = arg.tint or {255, 255, 255}
end
function Ship:draw()
love.graphics.setColor(self.tint)
love.graphics.draw(self.sprite, self.x, self.y, self.rot,
self.sx, self.sy, self.px, self.py)
love.graphics.setColor({255, 255, 255})
end
return Ship
现在的问题是,我使用以下代码将其中两个 Ships 创建为另一个对象的成员:
self.ship1 = Ship:new({x=50, y=self.y1, s=2, tint={0, 0.5, 1}})
self.ship2 = Ship:new({x=750, y=self.y2, s=-2, tint={1, 0.5, 0}})
但是当我画它们的时候,我只看到了一个——第二个。事实证明,就像上面的代码没有将 Ship
的新实例分配给 ship1
和 ship2
,而是 直接分配给 self
,出于我无法理解的原因。我是不是做错了什么或者这是解释器的一个奇怪的错误?
已解决!显然,需要的是这个小片段:
function Object:new(arg)
local o = {}
setmetatable(o, self)
self.__index = self
o:load(arg)
return o
end
在我所有的 new
方法中将 o
设置为本地解决了所有问题。我不知道它到底是如何工作的,但我假设在设置元表时将它放在全局变量 space 中会破坏某些东西。
这不是解释器的错误,而是语言的设计行为。 o={}
创建全局变量,这不是程序员在这里期望的。 "Why it is so?" 是语言创造者经常被问到的问题。有 many efforts 可以更简单地控制该行为。
local
的 o = {}
创建全局变量 全局变量可以在程序中的所有函数之间访问和共享,除非您使用花哨的环境范围技术。在函数内部使用全局变量为各种副作用打开了大门,你应该小心副作用。
我删除了一些语法糖并添加了上面的代码可以等效地写成如下:
Object.new = function(table_before_colon,arg)
highlander = {} --global variable, there can be only one
setmetatable(highlander,table_before_colon);
table_before_colon.__index = table_before_colon;
highlander:load(arg) -- table_before_colon.__index.load(highlander,arg)
return highlander
end
local Ship = Object:new()
--global highlander == Ship
--Ship.new points to Object.new
function Ship:load(arg)--equivalent to: Ship.load=function(self,arg)
--code that sets fields of the `self` object and is called from within new
self.x = arg.x or 0 -- equivalently highlander.x=arg.x or 0
end
现在,如果在 new
开始到 new
returns 期间没有发生任何事情,那么全局变量的存在无关紧要。但是,显然,您的其他代码与此类似:
local OtherObject = Object:new()
--otherObject == highlander
OtherObject.load = function(new_other_obj,arg)
--highlander == new_other_obj
new_other_obj.ship1 = Ship:new({x=50, y=self.y1, s=2, tint={0, 0.5, 1}})
--highlander == new_other_obj.ship1
new_other_obj.ship2 = Ship:new({x=750, y=self.y2, s=-2, tint={1, 0.5, 0}})
--highlander == new_other_obj.ship2
end
因此,OtherObject.load
调用其他函数,这些函数也访问和修改同一个全局变量。
local some_object = OtherObject:new()
returns 调用结束时的全局变量,在 [=18=20=] 调用中最后设置为 ship2
=] 内部调用 OtherObject:new
.