Попытка реализовать объектно-ориентированное программирование в Lua, но это не совсем работает - PullRequest
0 голосов
/ 20 мая 2018

Хорошо, поэтому я пытаюсь следовать инструкциям, найденным здесь: https://www.lua.org/pil/16.1.html, чтобы сделать что-то похожее на ОО-программирование в Lua (и игровой инфраструктуре LOVE), но это не работает.Вот суть моего кода.У меня есть общий 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

Теперь проблема в том, что я создаю два таких корабля какчлены другого объекта с этим кодом:

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 по причинам, которые я не могуПонимаю.Я сделал что-то не так или это странная ошибка интерпретатора?

Ответы [ 2 ]

0 голосов
/ 22 мая 2018

Это не ошибка интерпретатора, это разработанное поведение языка.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:new внутри вызова OtherObject.load внутри вызова OtherObject:new.

0 голосов
/ 20 мая 2018

Решено!Очевидно, что был нужен этот маленький фрагмент:

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

Создание o локальным во всех моих new методах решило все.Я не знаю, как это работает точно, но я предполагаю, что наличие этого в глобальном пространстве переменных сломало что-то, когда мета-таблицы установлены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...