Можно ли использовать наследование с Codea?

Можно ли использовать наследование с Codea? Хотя я довольно новичок в Lua, но после некоторого быстрого поиска в Google, похоже, что методы наследования и полиморфизма немного " вовлечены". Есть ли какая-либо техника, которую можно безопасно использовать с движком Codea Lua-хостинга?


Вот простой работающий тест, который я пытаюсь заставить работать. Мой суперкласс:

Superklass = class()

function Superklass:init(x,y)
    self.x = x
    self.y = y
end

function Superklass:debug()
    print(string.format("(%d, %d)", self.x, self.y))
end

Подкласс:

Ship = class()

function Ship:init(x, y)
    -- you can accept and set parameters here
    print('ship:init() called')

    self = Superklass(x,y) -- ???
    print('attempting to call self:debug()')
    self:debug() -- works! prints  
    print('ok!')
end

function Ship:draw()
    print('ship:draw() called')
    
    print('attempting to call self:debug()')
    self:debug()
    print('ok')
end

И точка входа в программу:

-- initial setup
function setup()
    ship = Ship(HEIGHT/2, WIDTH/2)
end

-- called once every frame
function draw()
    ship:draw()
end

Вот результат запуска этого:

ship:init() called
attempting to call self:debug()
(384, 375)
ok!
ship:draw() called
attempting to call self:debug()
error: [string "Ship = class()..."]:16: attempt to call method 'debug' (a nil value)
Pausing playback

Я уверен, что это невероятно наивно - но я бы хотел получить совет в отношении того, что может работать в контексте Кодеа.

2 ответа

Решение

Просто чтобы дать рабочее решение (наследование классов в Codea) и указать на некоторые из подводных камней. Во-первых, я должен отметить, что Codea загружает классы в порядке вкладок, поэтому вкладки для суперклассов должны быть перед вкладками для подклассов. Я бы порекомендовал посмотреть эту ветку на форумах Codea. Здесь обсуждается техника ниже, а также дается некоторое представление о базовой механике.

Сначала мы определим суперкласс AbstractSprite, конструктор которого принимает координату (x,y). Он предоставляет метод debug для вывода этой координаты на консоль.

AbstractSprite = class()

function AbstractSprite:init(x,y)
    self.position = vec2(x,y)
    
    print("new AbstractSprite created")
end

function AbstractSprite:debug()
    print(string.format("(%d,%d)", self.position.x, self.position.y))
end

Далее мы определяем реализующий класс Ship, который реализует пользовательскую отладку, которая вызывает super, демонстрируя, как двигаться вверх по иерархии классов.

Ship = class(AbstractSprite)

function Ship:init()
    AbstractSprite.init(self)
    print("new Ship created")
end

function Ship:debug()
    print("I am a ship, calling my superclasses' methods!")
    AbstractSprite.debug(self)
end

Точка входа в программу. Мы создаем как Ship, так и "raw" AbstractSprite, вызывая debug для каждого:

function setup()
    ship = Ship()
    ship:debug()
    
    asteroid = AbstractSprite(150, 200)
    asteroid:debug()
end

И вывод консоли:

new AbstractSprite created
new Ship created
I am a ship, calling my superclasses' methods!
(0,0)
new AbstractSprite created
(150,200)

Отказ от ответственности: я являюсь автором среднего класса, OO-lib для Lua.

Основанное на замыкании, которое вы указали в первом примере, является хорошим интеллектуальным упражнением, но оно имеет небольшую практическую ценность. В Lua ориентация объекта лучше достигается с помощью таблиц (как показано в примере, указанном во втором примере) - это дает эквивалентную функциональность с большей скоростью. Единственные различия синтаксические.

Есть много библиотек, которые используют стандартный основанный на таблицах подход для выполнения OO в Lua. Вы можете найти список здесь:

http://lua-users.org/wiki/ObjectOrientedProgramming

Используя средний класс, ваш код станет таким:

require 'middleclass'

-- middleclass needs the class name as a parameter
SuperClass = class('SuperClass') -- I don't see the point of using a K here, BTW

function SuperClass:initialize(x,y) -- initialize instead of init
    self.x = x
    self.y = y
end

function SuperClass:debug()
    print(string.format("(%d, %d)", self.x, self.y))
end
--

Ship = class('Ship', SuperClass) -- notice that we put the superclass here

function Ship:initialize(x, y) -- initialize instead of init again
    -- you can accept and set parameters here
    print('ship:initialize() called')

    self = SuperClass.initialize(self,x,y) -- notice the extra self and initialize here
    print('attempting to call self:debug()')
    self:debug() -- works! prints  
    print('ok!')
end

function Ship:draw()
    print('ship:draw() called')

    print('attempting to call self:debug()')
    self:debug()
    print('ok')
end
Другие вопросы по тегам