Добавлен
Столкнулся с такой проблемой, как ООП в Lua. Никаких статей по этому поводу не нашёл, пока что их очень мало на сайте. На Хайве попытался найти наработки на Луа, но не нашёл реализацию систем через классы (таблицы). Подскажите, где можно достать какой-нибудь Lua-скрипт в Варкрафте с реализацией класса, или может быть зарубежная статья по этому поводу? Очень непривычно работать с этими таблицами как классами и пока непонятно, как лучше оформлять код, неизвестны многие нюансы. Как говорил кто-то, у Lua своя парадигма программирования — в чём её суть и действительно ли удобна она?
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
29
4 года назад
0
Избыточность информации усложняет и делает невозможным усваивание материала, нельзя начинать учить что-то, давая сразу всю инфу, нужно абстрагировать от глаз всё что происходит за кулисами и скормить лишь суть, как этим воспользоваться.
А потом пропускать мимо ушей критику вооружившись аргументом "работает же"
prog:
Drulia_san, фигню понаписал, у тебя методы создаются для каждого экземпляра, а должны для индексной таблицы создаваться один раз, иначе зачем тебе метатаблица и индексная таблица тогда...
0
28
4 года назад
0
Drulia_san, поэтому лучше погуглить решения от спецов в Lua, которые ерунду не понапишут, а потом на основе их сделать своё решение, или использовать их, если оно подходит под задачи. Чем больше погуглишь, тем лучше.
0
29
4 года назад
0
поэтому лучше погуглить решения от спецов в Lua, которые ерунду не понапишут
Я конечно не спец, но ерунду напишу. Простейший пример метатаблиц
Unit = { x = 0, y = 0 }
function Unit:new (id, unitid, x, y, face)
	local data = {}
	setmetatable(data, self)
	self.__index = self
	data.unit    = CreateUnit(id, unitid, x, y, face)
	return data
end
function Unit:x(x)
	if x == nil then return GetUnitX(self.unit) end
	SetUnitX(self.unit, x)
	return self
end
function Unit:y(y)
	if y == nil then return GetUnitY(self.unit) end
	SetUnitY(self.unit, y)
	return self
end
function Unit:xy(x, y)
	if x == nil and y == nil then return GetUnitX(self.unit), GetUnitY(self.unit) end
	SetUnitX(self.unit, x)
	SetUnitY(self.unit, y)
	return self
end
function Unit:name(name)
	if name == nil then return GetUnitName(self.unit) end
	BlzSetUnitName(self.unit, name)
	return self
end

local u = Unit:new(Player(0), FourCC('hfoo'), 0, 0, 0)
u:x(13):y(3):name('OOP mazafaka')
0
15
4 года назад
0
PT153:
Я не спец, но разве не у obj нужно ставить переменную damage?
Ох, действительно, спасибо!
prog:
Drulia_san, фигню понаписал, у тебя методы создаются для каждого экземпляра, а должны для индексной таблицы создаваться один раз, иначе зачем тебе метатаблица и индексная таблица тогда...
Да, сразу это заметил. Но это ведь для наглядности, ничего не мешает вынести эти методы.
В общем, всем спасибо, практически разобрался в принципе работы. Отдельная благодарность к Drulia_san.
Единственное, нужно уточнить один нюанс. Как реализовать деструктор? Имеется список skillshotObjectList, содержащий все создаваемые экземпляры. Необходимо реализовать удаление экземпляра из памяти и соотвественно очистку его из skillshotObjectList.
function Skillshot:Create (...)
    local this = {}
    
    skillshotIndex = skillshotIndex + 1
    skillshotObjectList[skillshotIndex] = this
    this.id = skillshotIndex

	...
end

function Skillshot.Destroy (this)
    ???
    skillshotIndex = skillshotIndex - 1
end
3
24
4 года назад
3
JackFastGame, если не важен порядок, то практически в любом языке один из самых быстрых способов удаления чего-либо из списка это поменять его местами с последним элементом списка, занулить последний элемент и сократить длину списка на 1.
0
15
4 года назад
Отредактирован JackFastGame
0
prog:
JackFastGame, если не важен порядок, то практически в любом языке один из самых быстрых способов удаления чего-либо из списка это поменять его местами с последним элементом списка, занулить последний элемент и сократить длину списка на 1.
Тьфу, оказывается я неправильно вызывал функцию.
Это полностью очищает экземпляр из памяти?
function Skillshot:Destroy ()
    skillshotObjectList[self.id] = skillshotObjectList[skillshotIndex]
    skillshotObjectList[self.id].id = self.id
    table.remove(skillshotObjectList)
    self = nil
    skillshotIndex = skillshotIndex - 1
end
2
24
4 года назад
2
JackFastGame, полное удаление из памяти происходит только когда выполнится два условия: во-первых отсутствие ссылок на объект где-либо, не считая слабых ссылок, а во-вторых цикл сборки мусора должен добраться до этого объекта.
В коде выше мне не совсем понятно что происходит, но во-первых self = nil делать не надо, во вторых зачем одновременно и работа с массивом на основе стандартных функций table и отдельный счетчик skillshotIndex, когда можно использовать # на массив для получения кол-ва элементов, раз уж используется стандартная реализация массива.
0
15
4 года назад
0
Почему self = nil можно не делать, ведь удаляя объект из списка (таблицы) экземпляров, мы удаляем не сам объект, а ссылку на него из этого списка, разве нет?
Этого будет достаточно?
function Skillshot:Create (...)
    local this = {}
    
    table.insert(skillshotObjectList, this)

	...
end
function Skillshot:Destroy ()
    table.remove(skillshotObjectList, TableFindElement(skillshotObjectList, self))
end
2
28
4 года назад
Отредактирован PT153
2
Почему self = nil можно не делать
Потому что это аргумент функции, локальная переменная, она уничтожится после выхода из функции.
Двоеточние это синтаксический сахар, который в определение метода добавляет аргумент self на первое место, а при вызове метода через : передаёт объект, что стоит до двоеточия, в аргумент self.
3
29
4 года назад
Отредактирован Doc
3
Не понимать работу базовых вещей и браться за костыли в виде ООП в луа - классика жанра. Делать так не советую. Каких-то особых удобств ООП в луа не дает. Приватные переменные вы не сделаете, полиморфизм в языке и так по дефолту из-за динамической типизации. Разве что наследование, которое даже практиканты ООП уже не советуют, потому что есть композиция.
0
23
4 года назад
0
какие вы фигни расказываете.

--
-- Реализация класса с наследованием
--

function Class(parent)
	local class = {}
	local mClass = {}

	-- Сам класс будет метатаблицей для объектов.
	-- Это позволит дописывать ему метаметоды.
	class.__index = class

	-- Поля объектов будут искаться по цепочке __index,
	-- и дотянутся, в том числе, до родительского класса.
	mClass.__index = parent

	-- Резервируем поле Super под родителя.
	class.Super    = parent


	-- Функция, которая будет вызываться при вызове класса
	function mClass:__call(...)
		local instance = setmetatable({}, class)

		-- Резервируем поле класса "init"
		if type(class.init) == 'function' then
			-- Возвращаем экземпляр и всё что он вернул функцией init
			return instance, instance:init(...)
		end

		-- Но если её нет - тоже ничего.
		return instance
	end

	return setmetatable(class, mClass)
end

-- Основной класс.
Shape = Class()

function Shape:init(x, y)
	-- в качестве self мы сюда передаём инстанс объекта.
	self.x = x or 0
	self.y = y or 0

	return '!!!'
end

function Shape:posArea()
	return self.x * self.y
end

-- Так как таблица Shape является метатаблицей для рождаемых ей объектов,
-- мы можем дописывать ей метаметоды.
function Shape:__tostring()
	return '[' .. self.x .. ', ' .. self.y ..']'
end

local foo, value = Shape(10, 20)

print('foo, value', foo, value) --> [10, 20] !!!

-- Наследник
Rectangle = Class(Shape)

function Rectangle:init(x, y, w, h)
	-- В данный момент, self - это пустая таблица,
	-- к которой прицеплена таблица Rectangle, как мета.

	-- Вызов родительских методов через Super.
	self.Super.init(self, x, y)
	-- Вызов собственных методов при инициализации - тоже возможен.
	self.w, self.h = self:getDefault(w, h)
end

function Rectangle:area()
	return self.w * self.h
end

function Rectangle:getDefault(w, h)
	return w or 10, h or 20
end

function Rectangle:__tostring()
	return '['..self.x..', '..self.y..', '..self.w .. ', '..self.h..']'
end

rect = Rectangle(10, 20, 30, 40)

print('rect',           rect)           --> [10, 20, 30, 40]

print('rect:area()'   , rect:area())    --> 30 * 40 = 1200

-- Вызов родительского метода
print('rect:posArea()', rect:posArea()) --> 10 * 20 = 200
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.