Ответы пользователя по тегу Программирование
  • Создание лицензии для движка, что прочитать?

    @bromzh
    Drugs-driven development
    Не проще ли открыть код под GPLv3/LGPL (чтобы его не смогли использовать в закрытых проектах) и предусмотреть коммерческую лицензию для закрытых проектов за деньги? Для некоммерческих и открытых проектов разрешить использовать код бесплатно. Плюс, бери деньги за техподдержку. Так сделано у очень многих проектов (Qt, например).
    А то вдруг твоё поделие никто покупать не захочет? Большой проект трудно поддерживать маленьким коллективом (в случае открытых исходников многие смогут отправлять пулл-реквесты). А маленький вряд-ли кто-то купит (если он не обладает какой-нибудь супер уникальной фичей).
    Ещё можешь посмотреть, как лицензируются большие движки. Некоторые берут процент с продаж продукта. который их использует, некоторые позволяют использовать движки бесплатно до тех пор, пока прибыль или количество установок проекта не превысят определённую планку.
    Вообще, чем более либеральная лицензия, тем больше будет желающих использовать твой движок. Деньги, опять же, можно и с ТП получать (как это делают RedHat. nGinx, и прочие).
    Ответ написан
  • Bestpractices по ООП и паттернам в js?

    @bromzh
    Drugs-driven development
    Вопрос из серии "почему в функциональных языках нет циклов и переменных и как с этим жить". Так вот, жить можно вполне хорошо. Просто немного по-другому.
    Советую изучить, что же такое ООП и какое оно бывает. За пару минут можно найти инфу, что в жаваскрипте ООП - прототипное, а в питоне "классоориентированое". Т.е. в первом всё есть объект, и создавать новые объекты можно только клонируя основной объект, все методы и поля ищутся сперва у объекта, а потом у всех его прототипов. Во втором случае есть разделение на классы и объекты - экземпляры этих классов. Там диспетчеризация устроена по-другому: методы и поля ищутся у класса, а потом у всех его предков.
    И обходиться без наследования и метаклассов можно довольно легко, если знать, для чего же вообще нужно наследование и метаклассы. Метакласс позволяет манипулировать создаваемым классом на уровне его создания. Т.е. в питоне есть 2 понятия: класс и его экземпляр. В конструкторе класса можно определить поведение создаваемых экземпляров (через __new__ и __init__). Чтобы изменить поведение самого класса (а не его экземпляра) и нужны метаклассы: там, в функциях __init__ и __new__ можно переопределить поведение при создании класса. Так как в жаваскрипте такого разделения нет, то и отпадает само понятие метакласса: каждый объект создаётся путём клонирования от базового объекта (Object в js, хотя можно клонировать и любой другой объект: Array, Function, твой собственный). Такая же фигня и для наследования: там ты просто указываешь, какие поля могут выступать в качестве прототипов для всех "дочерних" объектов, это когда пишешь MyClass.prototype.someMethod = function(args) { ... }. В данном случае, someMethod будет сперва искаться среди самого объекта. Если там такого нет, то ищется в прототипе, т.е. в MyClass. Ну "классы" там объявляются функциями, потому что синтаксис не предусматривает создание класса. Да и то, функция-класс - просто синтаксический сахар: при вызове оператора new MyClass эта функция исполняется и возвращает копию объекта Object, над которой применили некие операции (которые ты как раз и описываешь в ней). Для каждой функции создаётся свой локальный контекст, который хранится в переменной this. Ты можешь в функции-классе описать, какие поля добавить в this, и она вернёт тебе как раз-таки этот изменённый this. Вот в lua нет даже оператора new, и ничего, вполне удобное ООП.

    У каждого подхода есть и плюсы и минусы. Мне удобно писать в обоих стилях. Единственное, могут возникнуть проблемы, когда в классе вытаешься присвоить полю какую-то функцию (callback). This внутри этого колбека будет иметь локальный контекст этой функции, а объекта, в котором находится это поле. На помощь приходит функция bind.

    P.S. Важно понимать, что функции являются объектами (в обоих языках). Но в js использование функций как переменных встречается гораздо чаще. Поэтому, строго говоря, нет никаких методов и полей в js. У объекта просто есть члены, которые могут быть как простыми данными и объектами, так и функциями. Собственно, для питона это тоже верно, ведь сами классы тоже являются объектами (экземпляры типа type). Просто там есть 2 понятия, как бы двухуровневая система. Ну и там куда реже члену объекта присваивают функцию, нежели в JS.
    Ответ написан
    1 комментарий
  • Как реализовать систему эффектов (модификаторов) накладываемых на игрока?

    @bromzh
    Drugs-driven development
    Так как ты не сказал, на каком языке пишешь, скину код на питоне:
    class Effect:
    
        def __init__(self, name, mods):
            self.name = name
            self.mods = mods
            # mods - это словарь с модификаторами
            # ключ - имя поля в классе User
            # значение - функция, которая принимает экземпляр класса User и промежуточное значение поля
            # а возвращает изменённое значение поля
    
    
    class User:
    
        def __init__(self, name, strength, agility):
            # Инициируем начальные значения
            self.name = name
            self.strength = strength
            self.health = strength * 100
            self.agility = agility
            self.effects = list()
    
        # в самом классе храним только независимые значения
        # но любой доступ к параметрам должен идти через геттер
        # для каждого необходимого параметра создаём функцию-геттер
        # которая будет учитывать применение эффектов
        # можно вместо этого использовать @property
        def get_strength(self):
            strength = self.strength
            for effect in self.effects:
                if effect.mods.get('strength'):
                    strength = effect.mods['strength'](strength, self)  # вызываем функцию - модификатор
            return strength
    
        def get_agility(self):
            agility = self.agility
            for effect in self.effects:
                if effect.mods.get('agility'):
                    agility = effect.mods['agility'](agility, self)  # вызываем функцию - модификатор
            return agility
    
        def get_health(self):
            health = self.health
            for effect in self.effects:
                if effect.mods.get('health'):
                    health = effect.mods['health'](health, self)  # вызываем функцию - модификатор
            return health
    
        # Это зависимый параметр
        def get_max_health(self):
            max_health = self.get_strength() * 100  # первоначальное значение вычисляется на основе силы
            for effect in self.effects:
                if effect.mods.get('max_health'):
                    max_health = effect.mods['max_health'](max_health, self)  # вызываем функцию - модификатор
            return max_health
    
    
    if __name__ == '__main__':
        foo = User('Foo', 10, 10)
        god_strength = Effect('God strength', {
            'strength': lambda s, u: s + 10
        })
    
        def _life_power_func(value, user):
            return value + 100
    
        life_power = Effect('Life Power', {
            'max_health': _life_power_func
        })
    
        def _extra_agility_func(value, user):
            return value + 10
    
        # этот эффект влияет сразу на 2 параметра
        extra_agility = Effect('Extra agility', {
            'agility': _extra_agility_func,
            'max_health': lambda h, u: h - 400
        })
        print(foo.get_strength(), foo.get_max_health(), foo.get_health(), foo.get_agility(), [e.name for e in foo.effects])
        foo.effects.append(god_strength)
        print(foo.get_strength(), foo.get_max_health(), foo.get_health(), foo.get_agility(), [e.name for e in foo.effects])
        foo.effects.append(life_power)
        print(foo.get_strength(), foo.get_max_health(), foo.get_health(), foo.get_agility(), [e.name for e in foo.effects])
        foo.effects.append(extra_agility)
        print(foo.get_strength(), foo.get_max_health(), foo.get_health(), foo.get_agility(), [e.name for e in foo.effects])

    Результат:
    10 1000 1000 10 []
    20 2000 1000 10 ['God strength']
    20 2100 1000 10 ['God strength', 'Life Power']
    20 1700 1000 20 ['God strength', 'Life Power', 'Extra agility']
    Ответ написан
    3 комментария
  • Что входит в обязанности "тонкого контроллера" и как при нем происходит связь вида с моделью?

    @bromzh
    Drugs-driven development
    Но в объектно-ориентированном программировании используется активная модель MVC, где модель — это не только совокупность кода доступа к данным и СУБД, но и вся бизнес-логика. Следует отметить возможность модели инкапсулировать в себе другие модели. В свою очередь, контроллеры представляют собой лишь элементы системы, в чьи непосредственные обязанности входит приём данных из запроса и передача их другим элементам системы. Только в этом случае контроллер становится «тонким» и выполняет исключительно функцию связующего звена (glue layer) между отдельными компонентами системы.


    Как это можно было не заметить на википедии?
    Ответ написан