Добавлен
Столкнулся с такой проблемой, как ООП в Lua. Никаких статей по этому поводу не нашёл, пока что их очень мало на сайте. На Хайве попытался найти наработки на Луа, но не нашёл реализацию систем через классы (таблицы). Подскажите, где можно достать какой-нибудь Lua-скрипт в Варкрафте с реализацией класса, или может быть зарубежная статья по этому поводу? Очень непривычно работать с этими таблицами как классами и пока непонятно, как лучше оформлять код, неизвестны многие нюансы. Как говорил кто-то, у 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
0
16
4 года назад
0
Doc:
Каких-то особых удобств ООП в луа не дает.
Дает, оборачивание дамми, снарядов, контейнеров и прочие вещи в объекты позволяет быстро и удобно плодить их в процессе разработки, делая универсальными, видя что может предоставить тебе класс. ООП незаменимая вещь где бы она ни была. Просто в варкрафте её должно быть по-меньше, но оно имеет место быть. Делать всё через функциональщину мерзко и неудобно.
>Приватные переменные вы не сделаете
Это возможно если использовать способ ООП, который описывал я
3
29
4 года назад
3
ООП незаменимая вещь где бы она ни была. Просто в варкрафте её должно быть по-меньше, но оно имеет место быть.
Красивое мнение, жаль, что неправильное.
позволяет быстро и удобно плодить их в процессе разработки, делая универсальными
А как это с ООП то связано конкретно?
Делать всё через функциональщину мерзко и неудобно
У меня почему-то большие сомнения, что Вы знаете, что такое функциональщина.
Это возможно если использовать способ ООП, который описывал я
Для этого придется все функции писать в теле конструктора и они будут копироваться на каждый объект, создавая рантайм оверхед.

В дополнение этого объекты созданные таким образом невозможно перезагрузить в рантайме, если подобная функция используется.
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.