试图在Lua中实现面向对象的编程,但它并不是很有效

时间:2018-05-20 11:06:00

标签: lua lua-table love2d

好的,所以我试图按照这里的说明进行操作:https://www.lua.org/pil/16.1.html在Lua(以及LOVE游戏框架)中做类似于OO编程的操作,但是它不起作用。这是我的代码的核心。我有一个通用的Object类:

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类:

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的新实例分配给ship1ship2,而直接分配给 {{1}因为我无法理解的原因。我做错了什么,或者这是解释器的一个奇怪的错误?

2 个答案:

答案 0 :(得分:1)

解决!显然,需要的是这个小片段:

function Object:new(arg)
    local o = {}
    setmetatable(o, self)
    self.__index = self
    o:load(arg)
    return o
end

在我的所有o方法中使new本地解决了所有问题。我不知道它是如何工作的但是我认为在全局变量空间中它在设置元表时会破坏某些东西。

答案 1 :(得分:1)

它不是解释器的bug,它是语言的设计行为。 private sending(data) { this.myApi.send({ type: 'json', data: data }).then(response => { this.onChange.next(response); }, httpError => { throw httpError; } ); } 创建全局变量,这是程序员不期望的。 "为什么会这样?"是语言创建者经常提出的问题。有many efforts来控制这种行为更简单。

o={}没有o = {}创建全局变量全局变量可以在程序中的所有函数之间访问和共享,除非您使用花哨的环境范围技术。在函数内使用全局变量为各种副作用打开了大门,你应该注意副作用。

我删除了一些语法糖,上面添加的代码可以等效编写如下:

local

现在,如果从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

因此,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() 内部调用ship2,调用内Ship:newOtherObject.load {1}}。