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

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
0
15
4 года назад
0
PT153:
Никаких статей по этому поводу не нашёл
Плохо искали.
Хоть убейте, не нашёл. Как мне, к примеру, реализовать внутри метода "класса" цикл foreach, который пробегает по всем созданным объектам данного "класса"?
0
24
4 года назад
Отредактирован prog
0
Хоть убейте, не нашёл. Как мне, к примеру, реализовать внутри метода "класса" цикл foreach, который пробегает по всем созданным объектам данного "класса"?
Хранить список созданных экземпляров где-нибудь, например в метатаблице, чтобы был простой доступ к этому списку. Создание экземпляров реализовать через метод-фабрику, который инициализирует экземпляр и назначает ему метатаблицу.
Для большего удобства - список экземпляров можно либо записывать в каждый экземпляр при его создании либо положить в индексную таблицу в метатаблице, чтобы до этого списка было еще проще добраться из экземпляров.
0
15
4 года назад
Отредактирован JackFastGame
0
prog:
Хоть убейте, не нашёл. Как мне, к примеру, реализовать внутри метода "класса" цикл foreach, который пробегает по всем созданным объектам данного "класса"?
Хранить список созданных экземпляров где-нибудь, например в метатаблице, чтобы был простой доступ к этому списку. Создание экземпляров реализовать через метод-фабрику, который инициализирует экземпляр и назначает ему метатаблицу.
Для большего удобства - список экземпляров можно либо записывать в каждый экземпляр при его создании либо положить в индексную таблицу в метатаблице, чтобы до этого списка было еще проще добраться из экземпляров.
Почему-то в цикле он пробегает только по последнему созданному объекту, причём сколько всего объектов, столько раз по нему и проходит.
Реализовывал и через pairs, и через for i = 1, #list.
Для добавления в список я использую table.insert(list, object).
Что я делаю не так?

Вот фрагмент кода. В main loop выводит урон последнего созданного объекта.
Skillshot = {}
list = {}

function Skillshot:Create (damage)
    local obj = {}
    
    setmetatable(obj, self)
    self.__index = self
	table.insert(list, obj)
    
    self.damage = damage

    return obj
end

function Skillshot.Update ()

    --Main loop
    for i = 1, #list do 
        local obj = list[i]

        Debug("i = " .. i .. " " .. list[i].damage)
    end
end

do
    local InitGlobalsOrigin = InitGlobals
    function InitGlobals()
    InitGlobalsOrigin()

        function test()
            local dmg = 5
            TimerStart(CreateTimer(), 2.0, true, function ()
                dmg = dmg + 5
                local skillshot = Skillshot:Create(dmg)
            end)
        end
        test()
    end
end
2
28
4 года назад
2
который пробегает по всем созданным объектам данного "класса"
А какой ООП язык это вообще позволяет без создания массива объектов этого класса?

function Skillshot:Create (damage)
    local obj = {}
    
    setmetatable(obj, self)
    self.__index = self
	table.insert(list, obj)
    
    self.damage = damage

    return obj
end
Я не спец, но разве не у obj нужно ставить переменную damage?
0
29
4 года назад
0
Почему все носятся с ООП как с писанной торбой и пытаются применить её ко всем ЯП?
3
16
4 года назад
3
когда у тебя в руках молотов всё вокруг кажется гвоздями
0
30
4 года назад
0
NazarPunk, к чему привыкли, то и используют, очевидно же.
0
29
4 года назад
0
когда у тебя в руках молотов всё вокруг кажется гвоздями
Напоминает это
<?php
/********************************************************************
Model-View-Controller implementation according to POSA
(Pattern-Oriented Software Architecture
  http://www.hillside.net/patterns/books/Siemens/book.html)
********************************************************************/
 
class HelloWorldController {
    private $model;
    function __construct($model) {
        $this->model = $model;
    }
 
    function handleEvent($args) {
        $this->model->setStrategy($args[2]);
        $this->model->addText($args[1]);
    }
}
 
 
class HelloWorldModel {
    private $text;
    private $observers = array();
    private $strategy;
    
    function attach($observer) {
        $this->observers[] = $observer;
    }
 
    function getData() {
        $facade = new HelloWorldFacade($this->strategy);
        return $facade->getHelloWorld().$this->text."\n";
    }
 
    function addText($text='') {
        $this->text = $text;
        $this->notify();
    }
 
    function setStrategy($strategy) {
        $this->strategy = $strategy;
    }
    
    function notify() {
        foreach ($this->observers as $observer) {
            $observer->update();
        }
    }
}
 
class HelloWorldView {
    private $model;
 
    function initialize($model) {
        $this->model = $model;
        $model->attach($this);
        return $this->makeController();
    }
 
    function makeController() {
        return new HelloWorldController($this->model);
    }
 
    function update() {
        $this->display();
    }
 
    function display() {
        echo $this->model->getData();
    }
}
 
 
/*********************************************************************
"Business logic"
********************************************************************/
 
class HelloWorld {
   function execute() {
       return "Hello world";
   }
}
 
class HelloWorldDecorator {
   private $helloworld;
   function __construct($helloworld) {
       $this->helloworld = $helloworld;
   }
 
   function execute() {
       return $this->helloworld->execute();
   }
}
 
abstract class HelloWorldEmphasisStrategy {
    abstract function emphasize($string);
}
 
class HelloWorldBangEmphasisStrategy extends HelloWorldEmphasisStrategy {
    function emphasize($string) {
       return $string."!";
    }
}
 
class HelloWorldRepetitionEmphasisStrategy extends HelloWorldEmphasisStrategy {
    function emphasize($string) {
       return $string." and ".$string." again";
    }
}
 
class HelloWorldEmphasizer extends HelloWorldDecorator {
   private $strategy;
   function HelloWorldEmphasizer($helloworld,$strategy) {
       $this->strategy = $strategy;
       parent::__construct($helloworld);
   }
 
   function execute() {
       $string = parent::execute();
       return $this->strategy->emphasize($string);
   }
}
 
class HelloWorldStrategyFactory {
    static function make($type) {
        if ($type == 'repetition') return self::makeRepetitionStrategy();
        return self::makeBangStrategy();
    }
 
    static function makeBangStrategy() {
        return new HelloWorldBangEmphasisStrategy;
    }
    static function makeRepetitionStrategy() {
        return new HelloWorldRepetitionEmphasisStrategy;
    }
}
 
class HelloWorldFormatter extends HelloWorldDecorator {
   function execute() {
       $string = parent::execute();
       return $string."\n";
   }
}
 
class HelloWorldFacade {
    private $strategy;
    function __construct($strategyType) {
        $this->strategy = HelloWorldStrategyFactory::make($strategyType);
    }
 
    function getHelloWorld() {
        $formatter = new HelloWorldFormatter(
                new HelloWorldEmphasizer(
                    new HelloWorld,$this->strategy));
        return $formatter->execute();
    }
}
 
$model = new HelloWorldModel;
$view = new HelloWorldView;
$controller = $view->initialize($model);
$controller->handleEvent($_SERVER['argv']);
0
24
4 года назад
Отредактирован prog
0
Я не спец, но разве не у obj нужно ставить переменную damage?
Именно так.

Почему-то в цикле он пробегает только по последнему созданному объекту, причём сколько всего объектов, столько раз по нему и проходит.
Все правильно оно проходит. Просто у тебя значения damage нет в экземплярах, ты его задаешь только для метатаблицы, которая одновременно является индексной таблицей. Вот и берется это значение для экземпляров у которых нет такой переменной.
1
16
4 года назад
Отредактирован Drulia_san
1
NazarPunk:
Почему все носятся с ООП как с писанной торбой и пытаются применить её ко всем ЯП?
Потому что это удобно.
Не читал что вы понаписывали, объясню ООП в луа на пальцах. Объяснения с теориями всякими, объяснением что такое метатаблицы - всосная муть, которая только усложняет.
Короче. В луа есть переменные и функции. В луа все функции это еще и переменные, а переменные могут хранить и функции. Они могут хранить в себе другие переменные и функции если присваивать их через оператор точку ( . ), например var.a = 4. Мета-таблицы создают завершенность этого механизма, позволяя эту магию использовать в качестве ООП.
Ты хочешь создать класс, допустим класс Projectile. Класс снаряда, которому ты дашь параметры, а потом запустишь и он полетит себе так как ты прописал.
Для начала объявим его глобально:
Projectile = {}
Тут мы просто создали пустой массив, он необходим чтоб хранить объекты со всей их инфой о нашем классе, мы к нему никогда обращаться напрямую не будем, просто ну вот так надо, не задумывайся. Не думай вообще что такое мета-таблицы, такие объекты и так далее, просто работай с этим и всё, потом осознание что это такое придет само (или почувствуешь сам что готов про это почитать отдельно). А пока не засоряй себя и идем дальше.
У класса должен быть конструктор, то с чего всё начинается.
Объявляем:
-- У нас конструктор принимает путь к эффекту effectStr и две локации, откуда лететь и куда лететь (locA, locB)
function Projectile:new(effectStr, locA, locB) 
    local this = {} -- Собственно наш новый объект, текущий экземпляр, просто массив-локальная переменная которая хранит наши члены и методы
    
    -- Сначала объявим методы, я не буду писать реализацию снаряда, главное понять приницп

    function this.Move() -- Метод Move, двигает наш снаряд, если он достиг цели - возвращаем false, иначе - true
         ...........
    end

   function this.destroy() -- Деструктор. Луа не умеет их вызывать самостоятельно, вызываем вручную где надо
   ...
   end

    function this.Launch() -- Метод запуска, вызывает в таймере метод Move() пока он не вернет false
        local t = CreateTimer()
        save(GetHandleId(t), 1, this)
        TimerStart(t, 0.01, true, function()
                local t = GetExpiredTimer()
                local This = load(GetHandleId(t), 1)
                if not This.Move() then
                        This.destroy()
                        DestroyTimer(t)
                end
          end)
    end

    --А теперь код самого конструктора, напомню что мы снова пишем в скоупе функции Projectile:new, нашего "конструктора"
   this.Dummy = CreateDummy(bla bla bla)
   this.effect = CreateEffect(bla bla bla)
   ... -- И так далее
   
    -- Это должно быть обязательно
    setmetatable(this, self)
	self.__index = self
	return this
end
Итак, у нас есть свой класс, который что-то делать, пройдемся еще раз, начинку класса объявляем внутри конструктора function Projectile:new(effectStr, locA, locB) , локальная переменная this в нём и есть объект класса, который мы потом вернём. Объявление функций внутри конструктора с префиксом this. это и есть объявление методов, внутри них все манипуляции с классовыми членами и методами делаются строго через написание перед ними this. , потом уже сам код конструктора, инициализируем нужные члены, ресурсы, подготовим все и в конце вот это:
    setmetatable(this, self)
	self.__index = self
	return this
Не думай вообще что это такое, знание этого тебе ничего не даст, просто скопируй, оно вернет в конце рабочий this в место где ты создаешь объект.
Как пользоваться? Изи.
proj = Projectile.Create("war3imported\\myEffect.mdl", myloc, dest)
proj.launch()
Ничего сложного
Вот еще пример с очень простым классом, скопируй и тестируй тут: www.lua.org/cgi-bin/demo
Код для теста под катом
-- Пример класса суммирующего 2 переменные
Sum = {}

function Sum:new(a, b)
    local this = {}
    
    function this.Calc()
        print( this.a + this.b )
    end

    this.a = a
    this.b = b
    setmetatable(this, self)
    self.__index = self
    return this
end

-- Test
mySum = Sum:new(2, 5)
mySum.Calc()
0
24
4 года назад
Отредактирован prog
0
Drulia_san, фигню понаписал, у тебя методы создаются для каждого экземпляра, а должны для индексной таблицы создаваться один раз, иначе зачем тебе метатаблица и индексная таблица тогда...
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.