Плохо! Плохо!:  0
Страница 1 из 3 123 ПоследняяПоследняя
Показано с 1 по 10 из 29

Тема: Создание скриптов на RGSS для людей со средними знаниями и экспертов

  1. #1

    По умолчанию Создание скриптов на RGSS для людей со средними знаниями и экспертов

    Создание скриптов на RGSS для людей со средними знаниями и экспертов


    Тип: руководство
    Автор: Boris Mikić aka Blizzard
    Перевод: Arnon
    Оригинал: здесь

    Это очень полезное руководство для тех, кто уже изучил основы в написании скриптов и хочет улучшить свои знания в этой области.

    Перевод будет публиковаться постепенно, по главам.

    Содержание:

    [IURL="http://rpgmaker.su/f97/создание-скриптов-на-rgss-для-людей-со-средними-знаниями-и-экспертов-518-post9615/#post9615"]1. Введение
    1.1. О RAM и CPU
    [/IURL]
    [IURL="http://rpgmaker.su/f97/создание-скриптов-на-rgss-для-людей-со-средними-знаниями-и-экспертов-518-post9616/#post9616"]2. Совместимость
    2.1. Псевдонимы
    2.2. Продумайте всё заранее
    2.3. Проблемы с названиями
    2.4. "Слишком глубокий уровень стека"
    2.5. RAM или CPU?
    [/IURL]
    [IURL="http://rpgmaker.su/f97/создание-скриптов-на-rgss-для-людей-со-средними-знаниями-и-экспертов-518-post9617/#post9617"]3. Обработка и хранение данных
    3.1. Зачем использовать циклы?
    3.2. Зачем использовать и методы и функции?
    3.3. Эффективное обращение к данным
    3.4. Модуль или класс?
    3.5. RAM или CPU?
    [/IURL]
    [IURL="http://rpgmaker.su/f97/создание-скриптов-на-rgss-для-людей-со-средними-знаниями-и-экспертов-518-post9618/#post9618"]4. Окна
    4.1. Основы
    4.2. Неправильный способ создания окон
    4.3. Насколько хорошо они выглядят?
    4.4. Окно или спрайт
    4.5. Основы графического интерфейса (HUD)
    4.6. Проблема с отображением не важной информации
    4.7. RAM или CPU?
    [/IURL]
    [IURL="http://rpgmaker.su/f97/создание-скриптов-на-rgss-для-людей-со-средними-знаниями-и-экспертов-518-post9619/#post9619"]5. Борьба с лагами
    5.1. Сложность алгоритма
    5.2. Что такое лаги и их разновидность (в рамках RGSS)
    5.3. Уменьшение времени обработки
    5.4. Не бойтесь использовать больше кода
    5.5. RAM или CPU?
    [/IURL]
    [IURL="http://rpgmaker.su/f97/создание-скриптов-на-rgss-для-людей-со-средними-знаниями-и-экспертов-518-post9620/#post9620"]6. Улучшаем свои навыки
    6.1. Скрипты с фигурными {} скобками
    6.2. Однострочные методы и функции
    6.3. Бесполезные и бессмысленные команды
    6.4. Слишком много SephirothSpawn’а
    6.5. О том как не выставить себя дураком
    6.6. Повторное изобретение колеса
    6.7. Навязывание стандартов
    6.8. О скриптах, которые никому не нужны
    6.9. RAM или CPU?
    [/IURL]
    7. Советы и хитрости
    7.1. Ручка с бумагой или тренируем свой мозг
    7.2. “Game_System” — ваш лучший друг для хранения данных
    7.3. Булева алгебра
    7.4. Злобный баг в инструкции “if”
    7.5. Что же будет первым? – Когда “if” сходит с ума
    7.6. Хитрость в “unless” – Закон де Моргана
    7.7. Сравнения
    7.8. Доступ к переменным экземпляра aka инкапсуляция
    7.9. Мощный итератор “each”
    7.10. Отлов ошибок
    7.11. Глобальные, локальные, переменные экземпляра или константы?
    7.12. Изнутри-вовне или же извне-вовнутрь?
    7.13. “Мм, а для чего эта кнопка?”
    7.14. Сверхклассы и примеси
    7.15. ТС — Требуется сортировка
    7.16. RAM или CPU?

    [IURL="http://rpgmaker.su/f97/создание-скриптов-на-rgss-для-людей-со-средними-знаниями-и-экспертов-518-post9622/#post9622"]8. Полезные ссылки
    [/IURL]
    9. Итоги
    Последний раз редактировалось Arnon; 29.10.2012 в 21:04.

  2. #2

    По умолчанию

    1. Введение

    Итак, вы решили научиться писать собственные скрипты? Значит это пособие НЕ для вас. Чтобы полностью усвоить излагаемые здесь сведения требуются уже сложившиеся минимальные знания скриптинга. Конечно, эту электронную книгу можно прочесть и без них, но вы лишь потратите своё время, если будете понимать лишь половину того, о чём идёт речь.

    Вместо основ, эта электронная книга преподносит знания, которые помогут вам улучшить свои навыки. В настоящее время развелось довольно много скриптеров-новичков, изучивших лишь начальный уровень и не желающих продвигаться дальше. Максимум, что они смогут создать — это собственную систему меню (CMS), но не более. Я же собираюсь научить вас как обрабатывать данные, как создавать по-настоящему хорошие интерфейсные окна и эффективно управлять ими, как избегать лагов, как выискивать ошибки в коде и как при создании собственных скриптов не выставить себя дураками. В конце каждой главы мы будем подводить небольшой итог нашим знаниям, а так же научимся выбирать между свободной оперативной памятью (RAM) и занятостью процессора (CPU) в контексте этой самой главы.

    Учтите, что хоть я и объясняю многие вещи, но это лишь то, с чего стоит начать углубление своих знаний. Одна лишь книга не сделает из вас самых лучших скриптеров, но она подскажет первый шаг, с которого стоит начать, двигаясь в этом направлении. Теорию, изложенную здесь, стоит опробовать и на собственном опыте.


    1.1. О RAM и CPU


    Это один из основополагающих моментов в программировании. Вам всегда придётся выбирать между сохранением оперативной памяти (RAM) и уменьшением занятости процессора (CPU). Другими словами, должна ли программа быть меньше по объёму или же она должна работать быстрее? Чаще всего программисты избегают повторную обработку данных путём их сохранения. Это вариант сберегает загрузку CPU за счёт использования RAM. Позже вы поймёте, где есть смысл использовать этот вариант, а где нет.

    RGSS — скриптовый язык. Скриптовый язык — это такой язык программирования, который не компилируется, а интерпретируется. Интерпретирование означает, что каждая строчка кода обрабатывается отдельно, компилируется и исполняется налету. Те из вас, кто когда-либо писал программы на компилируемых языках, например, C, C++, BASIC (который сначала был скриптовым языком!), Fortran, Pascal, и других, наверняка помнят, что они отводили некоторое время на компиляцию программы, то есть на перевод программного кода в машинный (а время это зависело от размеров кода и иногда становилось весьма длительным…). В RGSS отдавать предпочтение RAM порою более разумно, т.к. сохранение данных в RAM и их загрузка в кэш/регистры CPU выполняются одинаково в каждом языке программирования. Но осторожно! Сохранение и загрузка данных приблизительно в 10-15 раз медленнее, чем выполнение простейших операций, например сложения.



    [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9614&viewfull=1#post9614"]Вернуться к содержанию...[/IURL]
    Последний раз редактировалось Arnon; 05.05.2011 в 08:14.

  3. #3

    По умолчанию

    2. Совместимость

    Эта глава расскажет о том, как удобнее всего создавать свои скрипты совместимыми со скриптами других людей. Если же вы отрицаете возможность, что помимо ваших в игре будут и чужие скрипты, то никто просто не станет пользоваться вашими работами. Например, если у пользователя может оказаться три отличных скрипта от других авторов, причём работающих вместе, и один ваш, который с ними не уживается, то естественно он выкинет ваше творение и предпочтёт использовать только те три. Другая причина, по которой стоит уделить внимание совместимости, тоже важна. Это экономия времени и собственных усилий. Если вы публикуете собственные скрипты, то рано или поздно какой-нибудь пользователь обязательно попросит переделать код так, чтобы он стал совместим с чьим-то другим.

    Если ваш скрипт настраиваемый и в нём устанавливаются какие-то параметры, то с самого начала хорошо бы выставить их по умолчанию, для тех пользователей, которые не читают инструкции. Также будет замечательно, если ваши скрипты работают по системе Plug ‘n’ Play, т.е. так, что для полноценной работы их нужно лишь скопировать в редактор.


    2.1. Псевдонимы


    Под псевдонимами понимается создание своеобразных копий существующих методов. Для этого в RGSS используется зарезервированное слово alias.

    Код:
    alias not_for_underaged alcohol


    Эта строка создаёт псевдоним not_for_underaged для метода alcohol. Теперь экземпляр вашего класса свободно может вызывать метод alcohol через его псевдоним not_for_underaged.

    Код:
    child.not_for_underaged
    child.alcohol


    Обе эти команды делают одно и то же. Конечно же, вы не ограничены лишь методами класса. Также существует одна особенность, которая интересна с точки зрения совместимости: даже если вы переопределите оригинальный метод, псевдоним будет исполнять первоначальный вариант, к которому он установлен.

    Код:
    def alcohol
      loop do
        drink
        have_fun
        if enough or evening_over?
          break
        end
      end
    end
    # контрольная точка 1
    alias not_for_underaged alcohol 
    # контрольная точка 2
    def alcohol
      not_for_underaged
      if promille > 2.5
        hangover
      end
    end


    Этот код делает следующее:
    - определяет метод alcohol
    - даёт alcohol псевдоним not_for_underaged
    - переопределяет alcohol (not_for_underaged будет исполнять старый метод!)
    - обратите внимание, как новый метод alcohol вызывает своё старое определение через not_for_underaged

    Давайте более глубоко проанализируем этот код. Попробуем выполнить:

    Код:
    child.alcohol
    child.not_for_underaged


    Это приведёт к следующему:

    - перед контрольной точкой 1
    Код:
    # запуск alcohol
      loop do
        drink
        have_fun
        if enough or evening_over?
          break
        end
      end
    # ОШИБКА! Неопределённый метод not_for_underaged!

    - перед контрольной точкой 2
    Код:
    # запуск alcohol
      loop do
        drink
        have_fun
        if enough or evening_over?
          break
        end
      end
    # запуск not_for_underaged
      loop do
        drink
        have_fun
        if enough or evening_over?
          break
        end
      end

    - полностью
    Код:
    # запуск нового alcohol
      not_for_underaged
      # запуск not_for_underaged
      loop do
        drink
        have_fun
        if enough or evening_over?
          break
        end
      end
      # продолжаем выполнение alcohol
      if promille > 2.5
        hangover
      end
    # запуск not_for_underaged
      loop do
        drink
        have_fun
        if enough or evening_over?
          break
        end
      end


    Видите ли вы, почему это так полезно для совместимости? Ещё вы можете поместить в конец методов или в их начало какой-нибудь свой код. Конечно, если требуется по-другому обработать данные, нужно расписать всё более подробно.

    Код:
    def alcohol
      loop do
        drink
        have_fun
        if enough or evening_over?
          break
        end
      end
      if promille > 2.5
        hangover
      end
    end
    alias not_for_underaged alcohol
    def alcohol(age = 17)
      age < 18 ? go_home : not_for_underaged
    end


    Изначально, вызывая alcohol всегда запускается go_home (без указания аргументов, где число 17 уже установлено по умолчанию переменной age и где далее проверяется что она менее 18, другими словами: вы не получите выпивку не сказав свой возраст). Вызов alcohol(18) в результате запустит старый код метода alcohol.

    Имейте в виду, вы можете не только добавить свой код в конец или начало метода, но и переписать существующий, добавить условий или по-другому манипулировать им как пожелаете.

    Из моего опыта я узнал, что нельзя задать псевдоним методу модуля, определённого конструкцией def self.нечто.


    схема 2.1.1. – псевдонимы и изменение кода

    Помните, что если вы дадите псевдоним методу, который уже определён в сверхклассе и впоследствии измените метод сверхкласса или его псевдоним, то получите конфликт между ними и некоторые части перестанут работать.


    2.2. Продумайте всё заранее


    Это не обязательно, но порою весьма полезно. Если вы используете несколько ваших методов в более чем одном скрипте, а им назначен одинаковый псевдоним, то пользователи автоматически получать ошибку Слишком глубокий уровень стека (см. подробности в разделе 2.4.). Чтобы избежать такого исхода, вы можете добавить глобальную переменную (например $my_script) и установить её в качестве условия во всех ваших скриптах и тогда она задействует определённую часть кода.

    Код:
    # my_script
    def my_script
      do_something
    end
    if $my_extra_do_something != true
      alias do_something_more do_something
      def do_something
        do_this_and_that
        do_something_more
      end
      $my_extra_do_something = true
    end
    # my_2nd_script
    def my_2nd _script
      do_something_new
      do_something
    end
    if $my_extra_do_something != true
      alias do_something_more do_something
      def do_something
        do_this_and_that
        do_something_more
      end
      $my_extra_do_something = true
    end
    # my_3rd_script
    def my_3rd _script
      do_something
      do_it_again
    end
    if $my_extra_do_something != true
      alias do_something_more do_something
      def do_something
        do_this_and_that
        do_something_more
      end
      $my_extra_do_something = true
    end


    Добавление псевдонима методу do_something происходит лишь один раз, независимо от расположения скриптов в редакторе. Также этот способ может помочь, если другие скриптеры используют ваш псевдоним. Если в каком-то скрипте методу уже причислен псевдоним, то новый создаваться не будет. Конечно, в результате у вас получится больше кода, чем требуется, но это также улучшит совместимость, если использовать всё с умом.


    схема 2.2.1. – взаимодействие скриптов


    2.3. Проблемы с названиями


    Заголовок говорит сам за себя. При создании псевдонима вы должны обратить внимание на то, как вы его называете. Один из хороших образцов: оригинальноеназваниеметод а_вашеимя_названиевашегоск рипта. Или же вы можете выбрать свой, уникальный стиль. Лично я называю свои методы так: оригинальноеназваниеметод а_названиемоегоскрипта_later.

    Также я сокращаю слово initialize до init, update до upd и dispose до disp, так как это самые частые методы, которым приходится давать псевдонимы (для примера обратитесь к любому моему скрипту).

    Также хорошо, если имена не будут слишком длинными (как в SDK, где в образец наименования псевдонимов входят даты и названия классов), так как их не сложно будет отыскать и вероятность получить ошибку Слишком глубокий уровень стека уменьшится.


    2.4. “Слишком глубокий уровень стека”


    Для начала сообщу кое-что для тех, кто знаком с программированием на других языках: RGSS НЕ поддерживает рекурсию! Далее вы увидите хороший пример рекурсии в C/C++. Так выглядел бы обыкновенный код функции, вычисляющей факториал числа:

    Код:
    int factorial(int x)
    {
        int i, result = 1;
        for (i = 2, i <= x, i++)
        {
            result *= i;
        }
        return result;


    А так бы выглядела та же самая функция, но с применением рекурсии:

    Код:
    int factorial(int x)
    {
        if (x <= 0) return 1;
        return x * factorial(x - 1);
    }


    Рекурсия позволяет вызывать тот же самый метод снова и снова до тех пор, пока есть место в стеке (подробности в [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9622&viewfull=1#post9622"]главе 8[/IURL]). Вот та же самая функция, написанная на RGSS:

    Код:
    def factorial(x = 1)
      result = 1
      for i in 2...x
        result *= i
      end
      return result
    end


    А так бы выглядел код, если бы RGSS поддерживал рекурсию:

    Код:
    def factorial(x = 1)
      return 1 if x <= 0
      return x * factorial(x - 1)
    end


    Видели бы вы моё лицо, когда я узнал что RGSS её не поддерживает. А раз так, то появляется ошибка Слишком глубокий уровень стека. Примеры далее как раз вызывают такую ошибку:

    Код:
    def method_1
      method_1
    end


    Код:
    def method_1
      method_2
    end
    def method_2
      method_3
    end
    def method_3
      method_1
    end


    Код:
    alias new_method_1 method_1
    def method_1
      method_2
    end
    def method_2
      new_method_1
    end


    Помните, что в рекурсивном коде ДОЛЖНО БЫТЬ условие для его сброса. Если же функция постоянно вызывает сама себя и не возвращает никаких данных, то ваша программа будет работать со сбоями. Я не учёл этот факт в трёх примерах выше, будьте внимательны.


    2.5. RAM или CPU?


    Пока что это всё. Вы получили основные сведения о том, как сделать ваш скрипт совместимым с чужими или же вашими собственными. Если вам что-то было не ясно, то обратитесь к руководствам по созданию псевдонимов. Работая над совместимостью скриптов старайтесь использовать оперативную память, а не CPU. Самое плохое, что может случится — это то, что у вас будет повторяться одна и та же часть кода в нескольких скриптах, что не так важно, если они слаженно работают вместе, иначе может случится так что в результате сокращения код вообще не будет выполняться.



    [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9614&viewfull=1#post9614"]Вернуться к содержанию...[/IURL]
    Последний раз редактировалось Arnon; 29.10.2012 в 21:14.

  4. #4

    По умолчанию

    3. Обработка и хранение данных


    В этой главе вы научитесь тому, как следует хранить и обрабатывать данные. Она непосредственно касается насущного вопроса «RAM или CPU?» и поможет оптимизировать и улучшить ваш код.


    3.1. Зачем использовать циклы?


    Ответ на этот вопрос очень прост. Взгляните на два примера далее:

    Код:
    call_my_method
    x += do_this
    y += do_that
    call_my_method
    x += do_this
    y += do_that
    call_my_method
    x += do_this
    y += do_that


    Код:
    x = (x + 1) * 3 + 1
    x = (x + 1) * 3 + 2
    x = (x + 1) * 3 + 3
    x = (x + 1) * 3 + 4


    Даже в этих нескольких строчках очень много ненужного кода, а ведь со временем их будет становиться всё больше и больше и тогда даже простые операции будут тяжелы для понимания. В RGSS эта проблема решается с помощью циклов.

    Код:
    for i in 0...3
      call_my_method
      x += do_this
      y += do_that
    end


    Код:
    for i in 1..4
      x = (x + 1) * 3 + i
    end


    Приняв во внимание тот факт, что существует два вида циклов (определённый и неопределённый), мы можем использовать их не только для упрощения кода, но и для создания повторяющихся неопределённое количество раз операций.

    Код:
    loop do
      x = rand(10000)
      if x == 6284
        break
      end
    end


    Этот код будет выполняться до тех пор, пока в виде случайного числа не выпадет 6284. Это лишь краткое объяснение циклов и то, для чего их можно использовать (подробности смотрите в [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9620&viewfull=1#post9622"]главе 8[/IURL]).
    Примечание: Не путайте диапазоны в циклах. 0…3 выполнит итерации с 0 до 2, то есть не включая 3, тогда как диапазон 1..4 выполнит итерации с 1 до 4, включая 4. Помните об этом.


    3.2. Зачем использовать и методы и функции?


    И вновь ответ очень простой. Если у вас есть кусок кода, который вы часто используете, то хорошим решением будет поместить его в функцию. У классов функции называются методами, но это практически одно и то же. Помните, что не так важно поместить какой-то случайный код в функцию, куда важнее действительно объединить то что вам пригодиться. Когда вы называете свою функцию, то давайте ей имя, которое будет отражать её действие. Это поможет сделать код более читаемым, а также упростит его. Ещё очень полезно разбивать код на логические части, подгруппы и уже потом в функции. Далее вы найдёте пример хорошего внешнего вида у кода функции. Но вариантов могут быть тысячи.

    Код:
    def remove_enemy_from_map(enemy)
      id = enemy.get_sprite_id
      if id >= 0
        enemy.set_fading_flag
        enemy.character.active = false
        enemy.freeze_current_action
        @spriteset.sprite_takeover_fade(prepare_sprite_fade(id))
        remove_enemy_character(enemy.id)
        @hud.kills += 1
      end
      return id
    end



    3.3. Эффективное обращение к данным


    Есть множество путей для хранения и использования данных. Напомню, что RGSS — это скриптовый язык, код которого не компилируется, а интерпретируется. По сравнению с компилируемыми языками такая обработка в 10 раз медленнее или даже больше. Вот почему так важно поддерживать быструю работу вашего кода.

    Одной из критических областей в этом вопросе является структура данных. Наиболее часто используемые структуры: список, хэш и стек. Интересно отметить, что в RGSS класс Array (массив) поддерживает команды стека push и pop, тем самым позволяя использовать массивы для создания и списков и стеков.

    Списки работают по принципу FIFO (First In First Out), по-русски «первый пришёл — первый вышел». Это значит что первые добавленные данные в списке будут первыми удалёнными из него. Представьте себе трубу в которую вы заталкиваете один за другим резиновые мячики. Первый, который вы туда положите вылезет позже с другой стороны.

    Стеки работают по принципу LIFO (Last In First Out), «последний пришёл — первый вышел». Последние добавленные данные станут первыми при удалении. Представьте себе стопку тарелок. Если руководствоваться правилом при котором можно взять только одну тарелку, то, такой тарелкой окажется та, которая лежит сверху стопки.

    С хэшем ситуация обстоит несколько иначе. Хэш работает по принципу распределения адресов. В то время как массивы хранят данные последовательно, хэши хранит их в любом месте. Для доступа к данным используется ключ. Естественно что такой доступ наиболее эффективен, если вы управляете множеством данных, которые редко меняются и так называемая таблица хэша заполнена примерно на 75%. У массивов и хэшей сходное поведение в доступе к данным, хотя у хэшей оно более сложное вида O(n). В RGSS в RPG Maker вы в основном будете оперировать небольшим количеством. 1 МБ (в который поместятся 250000 4-байтовых целых чисел) — это относительно мало, учитывая что в среднем у пользователя в наши дни количество оперативной памяти (RAM) составляет 512 МБ. Даже при том что RAM означает Оперативная память (Random Access Memory) и к данным можно обратиться очень быстро где бы они не располагались, существует проблема с L1 и L2 кэшем процессора (CPU) который будет работать намного медленнее если вам придётся загружать данные со всех точек оперативной памяти, так как L2 кэш загружает блоки данных из RAM. А L1 загружает блоки из L2. Это гарантирует оптимальную производительность процессора, поскольку кэш-память L1 более ценна, чем L2, а та в свою очередь более ценна, чем обычная оперативная память. Именно поэтому никто не делает саму оперативную память по той же технологии, что и кэши L1 или L2: материально это не просто не окупается. По этой же причине процессоры с большой кэш-памятью стоят очень дорого, так что не зря я употребил слово «оптимально»; это оптимальный выбор между временем и деньгами. Если запрашиваемые данные находятся не в кэше, то это называется неудачным обращением в кэш и для загрузке нового блока потребуется время. По этой причине я рекомендую использовать хэши только при необходимости, когда это действительно имеет смысл, и ваш код будет более аккуратным и производительность не пострадает. Хорошим примером здесь станет очень быстрое определение столкновения, когда у вас есть хэш с координатами карты в качестве ключей и всеми соответствующими этим координатам персонажами на карте в качестве значений этих ключей.

    Никогда не используйте хэши для настроек! Не позволяйте пользователям устанавливать данные и/или менять настройки в виде хэша! Это очень грубая ошибка и она показывает людям насколько вы не понимаете те методы, которые сами же используете. Проблема заключается в том, что хэши менее эффективны по сравнению с массивами, если вы не храните в них большой объём данных, что редко происходит в RGSS.

    Есть лучшая альтернатива хэшам, которая работает намного быстрее и для понимания она намного проще. Эта альтернатива превосходно подходит для настройки пользователем и работает с данными подобно хэшам. Хитрость в том, что отображение данных распределено, но сами данные хранятся в оперативной памяти как единый блок. В практике же это намного легче для пользователей. Эта альтернатива — простой метод конверсии. В качестве аргумента метод получает ключ, который трансформируется в соответствующее значение. Единственный недостаток данного метода по сравнению с хэшем — это постоянное количество данных в нём. Вы не сможете изменить его состав во время игры. Но все непостоянные настройки так или иначе хранятся в специальных классах (смотрите раздел 7.2.), так что этот метод намного лучше по сравнению с хэшами.
    Пример: Допустим вы хотите, чтобы части экипировки вызывали какие-то специальные навыки. На словах это можно описать так: если используется EQUIP_ID, то возвращаем значение SKILL_ID:

    Код:
    def trigger_skill(id)
      case id
      when 1 then return 12
      when 4 then return 31
      when 7 then return 9
      when 12 then return 4
      when 81 then return 27
      end
      return 0
    end


    То же самое, но с использованием хэша:

    Код:
    TRIGGER_SKILL = {}
    TRIGGER_SKILL[1] = 12
    TRIGGER_SKILL[4] = 31
    TRIGGER_SKILL[7] = 9
    TRIGGER_SKILL[12] = 4
    TRIGGER_SKILL[81] = 27


    Или другим способом определения хэша:

    Код:
    TRIGGER_SKILL = {1 => 12, 4 => 31, 7 => 9, 12 => 4, 81 => 27}


    Последний пример ужасен. Его сложно понять, особенно тем, кто не знаком с программированием. Второй пример более приемлем, но всё же ANSI синтаксис в первом примере намного легче понять (особенно англоязычному пользователю — прим. перев.). Вы можете просто прочесть его “когда id равно 1 тогда возвращаем число 12, когда id равно тогда возвращаем число 31…” А вот второй пример прочесть не так то просто. Использование метода конверсии делает код проще для понимания, особенно если в нём придётся разбираться обычному пользователю и что-то самому изменять. Он так же использует лишь то количество оперативной памяти, которое ему необходимо для выполнения кода, хоть это и занимает БОЛЬШЕЕ пространство, однако хранится он как единый блок данных, позволяя быстрее получать к нему доступ в кэше процессора. Также имейте ввиду, что операции сохраняющие и загружающие что-либо в память в 10-15 раз медленнее, чем арифметически-логические операции. Доступ к одной части хэша требует некоторого времени, доступ к другой занимает ещё дополнительное время и так далее. Доступ же к одному и тому же методу в несколько раз быстрее. В обоих случаях для выполнения методов требуется перенос параметра (ведь получение элемента хэша с использованием ключа это тоже метод!), который сам по себе требует времени для сохранения данных в системном стеке и для возвращения адреса текущей команды. Поэтому это время я не принимаю во внимание при сравнении, здесь ни один метод не выигрывает (см. раздел [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9620&viewfull=1#post9620"]6.2[/IURL]).

    Другая возможность управления данными — использование массивов. Вы можете с легкостью манипулировать данными, добавляя их в конец массива, в начало, удаляя их из конца или из начала. Для этого используются 4 простые команды:

    Код:
    push 	– добавляет новые элемент в конец массива
    unshift – сдвигает массив и добавляет элемент в начало
    pop 	– удаляет последний элемент массива
    shift 	– удаляет первый элемент и сдвигает массив



    схема 3.3.1. – принцип работы команд push, unshift, pop и shift

    Чтобы получить больше информации, прочтите справку к RMXP. Помните, что вы можете добавить в массив всё что пожелаете. Ваши массивы могут содержать различные экземпляры разных классов. Ничто не мешает вам сделать массив с 3 целыми числами, одним героем и 5 строками. Так же можно использовать массив в методе, который должен вернуть несколько значений.

    Код:
    def throw_2_dices
      return [rand(6) + 1, rand(6) + 1]
    end



    схема 3.3.2. – доступ к данным и чтение в a) массиве b) хэше


    3.4. Модуль или класс?


    Вопрос который не даёт покоя многим скриптерам. Однако ответ на него довольно простой. Используйте классы для обработки экземпляров данных. Например, когда герой является экземпляром, как и в случае с числом или группой чисел. Представьте массив с сотней чисел. Классы же больше и поддерживают обработку с помощью методов. Метод — это практически то же самое, что и функция. Единственное отличие в том, что методы напрямую влияют на экземпляр собственного класса. Один класс не может использовать метод другого класса. Например, класс Bitmap покажет сообщение об ошибке «неопределённый метод», если вы попытаетесь использовать в нём метод size, который однако без проблем будет работать в экземпляре класса Array.

    Теперь поговорим о модулях. Модули не содержат данные (помимо особо важных данных), они — сборники методов, которые можно использовать там, где вы пожелаете. Многие скриптеры используют модули для хранения констант для настроек. Это хорошее решение, если у вас 10 или более опций. Это поможет избежать конфликты с другими скриптами, но если же их меньше, то в этом нет никакого смысла.

    Примерами классов служат различные окна в RPG Maker. Вот как можно использовать загруженный экземпляр класса:

    Код:
    win = Window_Status.new
    win.refresh
    win.x += 16


    Использование модулей происходит по-другому. Вам не нужен экземпляр для доступа к нему:

    Код:
    Input.trigger?(Input::B)


    Имейте в виду, что когда вы определяете методы модуля, то можете использовать как обычные варианты определения, например: def method_name и module_function :method_name, так и прямые def self.method_name или def NAME_OF_MODULE.method_name.

    Наверняка вы обратили внимание на Input::B. Так мы получаем доступ к константам внутри модуля. Знак :: называется оператором области видимости. Таким образом модули используются в основном для коллекции методов, функций и констант. В классах тоже можно создать метод вида def self.something и использовать его подобно модулю.

    Подробнее об объектно-ориентированном программировании написано в главе 8.

    Код:
    class Game_Party
      def self.load_from_savefile(file)
        tmp = Marshal.load(file)
        $game_party = tmp if tmp.is_a?(Game_Party)
      end
    end
    Game_Party.load_from_savefile(file)


    Этот пример очень хорошо работает, проверьте сами. Главное убедитесь что используете его на настоящем экземпляре класса IO. Вы можете использовать файл с сохранением и вызывать метод до EOF (End Of File) — конца файла. Вы обнаружите, что при этом загружается состояние партии из файла сохранения.


    3.5. RAM или CPU?


    В этой главе вы познакомились с основами обработки и управления данных. Данные могут стать опасным врагом, если их становится слишком много. Лучше разрешите процессору (CPU) конвертировать данные вместо поиска их в оперативной памяти (RAM), особенно если это постоянные данные. Конвертируемые CPU данные попадают в кэш, в отличие от данных из RAM. Это важно лишь для тех данных, которые распределены, а не сгруппированы вместе. Не спешите применять хэши, делайте это только в крайнем случае.



    [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9614&viewfull=1#post9614"]Вернуться к содержанию...[/IURL]
    Последний раз редактировалось Arnon; 29.10.2012 в 21:07.

  5. #5

    По умолчанию

    4. Окна

    Эта глава научит вас, как эффективно управлять окнами в игре, ведь они на самом деле состоят из нескольких спрайтов и эти самые спрайты могут вызывать множество лагов, особенно если они огромные.


    4.1. Основы


    Окна не так просты, как кажется на первый взгляд. Вот несколько вещей, которые вы должны иметь в виду. Время от времени они могут быть весьма полезны:

    1. Окна состоят из нескольких спрайтов и многие из них вызывают лаги.
    2. Окна использует рисунок под называнием contents, его размер практически идентичен размеру окна, однако, меньше на 32 пикселя по ширине и 32 по высоте и его координаты x и y смещены на 16 пикселей. Если окно меньше 33×33 пикселей, и вы попытаетесь создать его рисунок стандартными средствами, то появится ошибка: невозможно создать Bitmap (could not create Bitmap).
    3. Перерисовка содержимого окна (обычно этот метод называется refresh) занимает время и вызывает лаги. Лучше всего перерисовывать окна в тот момент, когда их содержимое изменилось.
    4. НИЗАЧТО не перерисовывайте окна всё время! Обновляйте — да, но не перерисовывайте (refresh).
    5. Перемещение окон занимает время и вызывает лаги.
    6. Изменение атрибутов x и y перемещает окно, в то время как изменение атрибутов ox и oy заставит переместиться рисунок (bitmap), а не само окно.
    7. Позиция z — это значение третьего измерения, которое определяет как «высоко» должно окно отображаться над другими окнами, спрайтами и т.д. Чем больше это значение, тем окно ближе к игроку.
    8. Если рисунок окна превышает его размеры, то появятся маленькие стрелки, взятые из графики обложки окна (windowskin). Держите размеры рисунка под контролем, чтобы избежать этого.
    9. Если вы сделаете окно активным (active), то курсор (если таковой присутствует) начнёт мигать, тогда как в неактивных окнах его анимация замораживается. Чтобы удалить курсор по умолчанию, вам нужно установить index окна равным -1. Для этого вы можете использовать команду self.index, но не обращайтесь к @index напрямую. Помните, что только в Window_Selectable есть методы управления курсором, а в Window_Base их нет. Однако, вы можете создать ваш собственный класс окна, который сможет работать с курсором и при этом основываться на Window_Base.
    10. Если вы установите окно в режим паузы (pause), то внизу появится маленький индикатор, который знаком вам по окнам сообщений и предназначен для ожидания ввода от пользователя.
    11. Уничтожайте окна (dispose), если вы не используете их часто или они вам больше не нужны. Не забывайте установить переменную, в которой содержится экземпляр окна на nil. Своевременное уничтожение окон и их создание — это ключ к избавлению от лагов, даже если ваши окна анимированные (т.е. перемещаются).
    12. Не делайте окна больше, чем необходимо. Чем оно больше, тем больше лагов оно вызывает.


    В RGSS есть сверхкласс Window с которого наследуются все основные параметры. Любые его экземпляры создаются с уже определенными спрайтами, что довольно быстро, так как класс Window скомпилирован в библиотеке RGSS10XX.dll. Window_Base — это класс с дополнительными методами, которые помогут в работе с окнами. Window_Selectable — подкласс Window_Base и используется для создания окон с элементами выбора, так как в нём для этой цели специально предопределены полезные методы.


    4.2. Неправильный способ создания окон


    Когда при создании окна не загружается экземпляр, а оно прописывается непосредственно. Наиболее часто используемый шаблон для создания окон такой:

    Код:
    class My_Window < Window_Base
      def initialize
        super(x, y, w, h)
        self.contents = Bitmap.new(width - 32, height - 32)
        self.contents.font.name = ‘Arial’
        self.contents.font.size = 22
        refresh
      end
      def refresh
        self.contents.clear
        self.contents.draw_text(x, y, w, 32, ‘string’)
      end
    end


    Если вы создадите окно неправильным способом, то оно будет ужасно выглядеть (схема 4.2.1.). Представьте себе такой метод прорисовки:

    Код:
      def refresh
        self.contents.clear
        self.contents.draw_text(13, 2, 128, 32, 'This')
        self.contents.draw_text(53, 7, 128, 32, 'window')
        self.contents.draw_text(111, 5, 128, 32, 'looks')
        self.contents.draw_text(140, 12, 128, 32, 'awful!')
      end



    схема 4.2.1. – это окно выглядит ужасно

    Почаще проверяйте, как выглядят ваши окна. Весьма полезно использовать последовательное смещение между элементами окна. Следующий код создаёт окно показанное на схеме 4.2.2.

    Код:
      def refresh
        self.contents.clear
        self.contents.draw_text(0, 0, 128, 32, 'This')
        self.contents.draw_text(72, 0, 128, 32, 'window')
        self.contents.draw_text(0, 28, 128, 32, 'looks')
        self.contents.draw_text(72, 28, 128, 32, 'better!')
      end



    схема 4.2.2. – это окно выглядит намного лучше

    Числа 128 и 32 служат специальной цели. 128 — ширина прорисовки. Если ваш текст слишком большой и не влезает в эту границу, то он будет сжат. 32 отвечает за высоту. В основном его можно оставить таким же, 32, так как обычно высота играет меньшую роль, особенно если она больше необходимой. Размер высоты чаще всего совпадает с размером шрифта, однако некоторые шрифты на самом деле всё же могут быть больше, чем их размер. К примеру, размер шрифта равен 24, но размер высоты прорисовки должен быть большее, 26.


    схема 4.2.3. – сжатый текст


    схема 4.2.4. – высота слишком мала

    Я очень рад, что окна в RGSS ограничены прямоугольной формой… Пробуйте создавать свои окна и отыщите ещё больше неправильных способов их отрисовки. И во имя всего святого, ни за что не используйте их!


    4.3. Насколько хорошо они выглядят?



    схема 4.3.1. – ужасные окна!

    Хотя, по правде сказать — они не такие ужасные. По крайней мере, на схеме 4.3.1. Что не так на этом скриншоте? Я имею ввиду, почему они ужасно расположены? Есть три возможные причины этого беспорядка:

    a) размер окон
    b) позиция окон
    c) смещение рисунка окон

    Позвольте сразу дать совет: лучше всего создавать все окна с размерами, делящимися на число 32 (64, 96, 128…) или, в некоторых особых случаях, на 16 (48, 64, 80, 96, 112…). Так же важно не задавать размеры меньше 33×33, в противном случае вы получите ошибку.

    Позиция окна — это немного другая история. Рекомендуется задавать такие расположения окон, координаты (x и y) которых делятся на 8. Если вы перемещаете окно, то на время можете проигнорировать это (эстетическое) правило, пока оно не достигнет своей окончательной позиции.

    Последним, с чем может быть проблема, является превышение рисунком размеров окна (а также позиции, ox и oy). Обычно вам нужно избегать этого. Единственная ситуация, в которой имеет смысл создавать рисунки больше окон — это прокручиваемые окна.

    И помните, что всё это не прописные истины, однако они помогут вам создать интерфейс на который можно взглянуть не получив сердечный приступ.


    схема 4.3.2. – хороший порядок окон

    Взгляните на схему 4.3.2. Разве она не выглядит лучше? Вот свойства окон:

    Код:
    1.	x = 0, 		y = 0, 		width = 160, 		height = 224
    2.	x = 0, 		y = 224, 	width = 160, 		height = 96
    3.	x = 0, 		y = 320, 	width = 160, 		height = 96
    4.	x = 0, 		y = 416, 	width = 160, 		height = 64
    5.	x = 160, 	y = 0, 		width = 480, 		height = 480
    (где x — координата x, y — координата y, width — ширина, height — высота)

    Скорее всего, вы уже заметили, что все номера имеют общий делитель: 32.

    Со следующей проблемой сталкиваются практически все начинающие скриптеры. Знакома ли вам ситуация показанная на схеме 4.3.3?


    схема 4.3.3. – проблемы со стрелками

    Как уже неоднократно говорилось ранее, это происходит, потому что рисунок больше чем размеры окна. В предоставленном примере окно размером 96×64, а его рисунок больше 64×32. Один простой способ избежать этого нежелательного эффекта заключается в указании специальных размеров рисунка в def initialize.

    Код:
      def initialize
        …
        self.contents = Bitmap(width - 32, height - 32)
        …
      end


    Нужная часть выделена красным жирным начертанием. width и height — методы, определяемые в классе Window, которые соответственно возвращают ширину и высоту текущего окна. Главное чтобы слова width и height не были переопределены в методе в качестве локальных переменных. Наш трюк поможет избежать появления стрелок, даже если размеры рисунка всё равно больше чем окно, он просто укоротит его.

    И последняя проблема связана с позицией окна. Взгляните на схему 4.3.4.


    схема 4.3.4. – картина, от которой младенцы сразу начинают плакать

    Перекрывающиеся окна сами по себе не проблема. Проблема проявляется у окон, которые, как кажется, не должны перекрывать друг друга.


    схема 4.3.5. – похоже что дизайнер что-то перепутал

    Схема 4.3.5 выглядит так, как если бы дизайнер окон что-то перепутал и они не должны перекрывать друг друга. Схема 4.3.6 показывает, как можно более красиво использовать перекрытие.


    схема 4.3.6. – ничего особенного, но выглядит лучше


    4.4. Окно или спрайт


    Выбирайте окна, если вы хотите чтобы использовалась графика обложек. Если вы хотите создать прозрачный фон или особое изображение фона, не используйте окно с прозрачностью = 0, используйте спрайт. Помните, что вы столкнетесь с риском того, что вам придется заново переписывать код специальных методов (вроде draw_actor_hp) или скопировать их из класса Window_Base. Хотя это может оказаться даже лучшим вариантом, например, если вы хотите использовать шрифт поменьше и т.д. Но будьте осторожны, ведь вам придётся написать больше кода, а значит, его впоследствии будет труднее понять. В любом случае это уменьшит количество лагов в вашем интерфейсе, ДАЖЕ ЕСЛИ вы напишите больше кода (смотри пункт [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9619&viewfull=1#post9619"]5.4[/IURL]).


    4.5. Основы графического интерфейса (HUD)


    Есть 4 важные вещи, которые вы должны помнить при создании собственного HUD:

    1. Если ваш HUD можно отключить, то убедитесь, что вы УНИЧТОЖИЛИ (DISPOSE) ваши окна/спрайты, а не просто сделали их невидимыми. Вам придётся написать больше кода, однако количество лагов заметно уменьшится.
    2. Отображайте только ту информацию, которую игроку очень нужно видеть всё время. Показывать, например Силу бессмысленно, так как она не так часто меняется и не важна для игрока постоянно, а займёт лишь больше ресурсов и места на экране.
    3. Обновляйте HUD ТОЛЬКО, если данные изменились. Карта уже перегружена спрайтами событий и меньше всего ей нужно обновлять ваш HUD каждую секунду или ещё хуже, каждый кадр. Чтобы сделать это, храните все ваши отображаемые данные в экземплярах переменных и сравнивайте их в методе update с текущими значениями. Если какое-нибудь значение изменилось, обновляйте HUD и записывайте новые значения. Вы можете пойти дальше и обновлять только ту секцию, которая изменилась. Вам потребуется больше кода, но это поможет снизить время обновления. Например, представьте 20 значений, каждому из которых требуется 0.01 секунды для прорисовки. Это приведёт к 0.2 секунды перерисовки всего HUD, причём каждый раз будут заметные на экране лаги. Если же вы перерисуете только ту секцию, которая изменилась, то вам понадобятся номинальные 0.01 и этот процесс пройдёт незамеченным. Вы можете удалить отображаемые части экземпляра Bitmap используя fill_rect(x, y, width, height, Color.new(ANY, ANY, ANY, 0)). Это удалит выбранную область рисунка и вы сможете нарисовать новую информацию. Если вы хотите пойти ещё дальше, то прекратите обновлять статически слова, вроде HP, SP или EXP. В зависимости от того как выглядят ваши изменяемые значения (числа, градиенты и т.п.), возможно вам даже не потребуется удалять их fill_rect перед перерисовкой. (Для своего HUD я прорисовываю значение HP на полосе градиента. Таким образом мне не нужны статические слова HP/MAXHP, всё итак понятно. Мне также не нужно очищать секции градиента перед перерисовкой.)
    4. Учитывайте дилемму о спрайтах и окнах (смотрите пункт [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9618&viewfull=1#post9618"]главе 8[/IURL]).



    4.6. Проблема с отображение не важной информации


    Прежде всего, вам необходимо решить: какие данные важны, а какие нет. HUD, который содержит количество золото и значок будет вызывать лаги каждый раз при перерисовке, занимать место на экране, а обновляться будет лишь после битвы. Если вы работаете над боевой системой ABS, то возможно оно будет обновляться чаще. Но, в конце концов, зачем игроку в глубоком подземелье нужно знать своё благосостояние всё время пока он там? Он, например, может вызывать меню и посмотреть там, если его и правда это интересует. Как уже было сказано, только для ABS это может пригодиться и только, если сделать эти данные небольшими на экране. Наиболее важная информация: HP, SP, EXP и другие значения важные для битвы, вроде накопленных комбо-ударов, процента ярости, выносливости и др. Так же в большинстве случаев HUD вам вообще не понадобится, потому что свои задачи он выполняет только в боевых системах вроде ABS. Или HUD пригодится для мини-игр, специальных параметров, вроде выносливости и т.п. К другому же использованию стоит присмотреться, стоит ли увеличивать лаги на карте, которые итак уже есть благодаря событиям и спрайтам. Не говоря уже об огромных картах размером 200×200.

    Ещё одна проблема — это то, что любая информация занимает экранное место. А чем меньше игрок будет видеть того что происходит в игре, тем меньше он захочет продолжать использовать ваш интерфейс. Поэтому не переполняйте экран и сохраняйте ваш HUD маленьким любыми средствами.


    4.7. RAM или CPU?


    В этой главе вы должны были усвоить идею о том, как заставить ваши окна выглядеть профессионально. В отличие от хаотичного дизайна живой природы, случайность — это табу при создании окон. Не отображайте бесполезной и ненужной информации и не перерисовывайте постоянно ваши окна. Используйте спрайты, если вам нужно создать прозрачный фон и/или вы используйте фоновое изображение. Вы можете нарисовать изображение прямо на спрайте. Так же не забывайте о правиле 32 пикселей. Оно поможет вам сэкономить время при проектировании, ведь у вас будет только 20×15 (640/32×480/32) возможных позиций окон вместо 640×480.



    [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9614&viewfull=1#post9614"]Вернуться к содержанию...[/IURL]
    Последний раз редактировалось Arnon; 29.10.2012 в 21:15.

  6. #6

    По умолчанию

    5. Борьба с лагами

    Эта глава научит вас, как победить главного босса в игре со скриптами: лаг.

    5.1. Сложность алгоритма

    Эта тема достаточно сложная и объёмная, такая, что о ней можно написать 20-страничное эссе. Однако я дам вам лишь краткое объяснение без сложной терминологии о том, что значит это словосочетания и для чего оно нужно. Всё довольно просто: Сложность алгоритма используется для формального определения скорости алгоритма в зависимости от заданных параметров. Посмотрите этот код:

    Код:
    p 1
    if a
      s = Sprite.new
    end
    c = d + 11


    Как вы думаете, какова здесь сложность? Она равна O(1). Теперь этот:

    Код:
    for i in 0…n
      f += determine_special_string(n)
    end


    Сложность алгоритма O(n). А в следующем примере?

    Код:
    for i in 0…n
      for j in 0…n
        for k in 0…n
          make_some_lag
        end
      end
    end


    Здесь сложность алгоритма O(n3). Проще говоря, сложность алгоритма говорит нам, как количество выполняющихся повторений зависит от количества обрабатываемых данных. В последнем примере n равное 2 вызовет 8 итераций в общей сложности, в то время как n равное 3 вызовет уже 27 итераций, а n равное 4 вызовет в алгоритме 64 итераций. Теперь картина складывается воедино? Вы видите как быстро возрастает количество обработки? Ведь n равное 10 вызовет целую 1000 выполнений метода make_some_lag. Наиболее распространенная сложность (n2). В своё время было разработано несколько алгоритмов для уменьшения сложности кода. Один из моих любимых это применение сложности O(n×log2(n)). Функция log (логарифм) является обратной к экспоненте функцией. Например, следующие уравнения значат одно и то же:

    log232 = 5
    32 = 25
    Значения, выделенные одинаковым цветом одинаковые в обоих случаях. На словах это можно передать как: “Если основание равно 2, то экспонента, необходимая для получения числа 32 будет равна 5.” (смотрите ссылки о логарифмической алгебре в [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9622&viewfull=1#post9622"]главе 8[/IURL]). В целом, эта сложность популярна, ведь она работает как демпфер. Вот ещё примеры: log2(2) = 1, log2(32) = 5, log2(1024) = 10, log2(1048576) = 20. При n равным 1000 понадобится только 10 итераций. Даже если n равна 1000000, будет всего 20 итераций. Умножение n в рамках этой сложности серьёзно повлияет на количество итераций, это так, однако же, сложность O(n×log2(n)) гораздо ближе к O(n) чем к O(n2).

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

    Допустим, сложность среднего случая равна 5/4*n4+2*n2+43. Сложность алгоритма просто равна =(n4) так как все факторы и меньшие компоненты сложности удаляются. Ищите ссылки на дополнительную информацию о логарифмической алгебре в [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9622&viewfull=1#post9622"]главе 8[/IURL].

    5.2. Что такое лаги и их разновидность (в рамках RGSS)

    Как известно самые сильные лаги в игре вызывает в основном графика, а также алгоритмы с высокой сложностью. Обработка графики на самом деле гораздо более сложный процесс, чем кажется. Такой простой метод, как set_pixel в классе Bitmap вызывает цепную реакцию. В RGSS за отображение на экране отвечает модуль Graphics. Изменение одного пикселя с помощью метода выше запускает изменение данных внутри экземпляра класса, плюс в окне/спрайте, который управляется экземпляром Bitmap, а также вызывает обновление в модуле Graphics, которому нужно будет обновить изображение на экране, перерисовав его учитывая новую информацию, заданную пользователем, при следующем вызове Graphics.update. По этой причине даже невидимые окна и спрайты вызывают лаги, как вызывают их и каждое обновление информации на экране.

    Конкретно в RGSS спрайты и окна вызывают самые большие лаги. Наибольшее количество лагов будет в интерфейсе с множеством окон или на карте с множеством событий, так как к каждому событию привязан спрайт. А каждый спрайт вызывает лаги, независимо от того установлена ли у него графика или нет, потому как сам процесс проверки и обновления спрайта требует времени на обработку процессором (CPU). Обновление события само по себе происходит довольно быстро, так как классу Interpreter нужно только лишь получить и запустить команды события. На карте, где обновляются 100 событий, но без спрайтов будут лишь незаметные лаги. На карте, где 100 событий и спрайты без графики, которые не обновляются, тоже вызовут небольшие, но уже заметные лаги. Это показывает, что только сам факт наличия спрайтов вызывает лаги. На карте, где 100 событий и 100 видимых спрайтов будет невозможно находиться. По этой причине большинство систем анти-лагов — это системы анти-лагов событий (Event-Anti-Lag Systems), которые способны предотвращать бесконтрольное обновление событий и их спрайтов за пределами экрана, потому что игрок всё равно их не видит. Правда создателей таких систем не волнует, что происходит с событием, они только определяют, должен ли спрайт быть обновлен или нет. В моей системе Blizz-ABSEAL внедрена более мощная техника для предотвращения лагов. Вместо того, чтобы просто отключать обновление спрайтов, ненужные спрайты уничтожаются и полностью удаляются из памяти, если событие выходит из зоны, в которой требуется его обновление. Само собой обновление при этом отключается.

    Так что имейте в виду, что графика в RGSS вызывает самые сильные лаги. Особенно спрайты и окна, в которых содержится несколько спрайтов (смотрите главу 4 с более подробной информацией)! Поэтому вы должны позаботиться об уничтожении невидимых окон и спрайтов, которые больше не нужны. Это увеличит количество строчек кода в вашем скрипте, но сделает его настолько быстрым, что другие позавидуют его производительности.

    5.3. Уменьшение времени обработки

    Запомните один нюанс: выполнение каждой строки вызывает задержки в RGSS. Ускорить ваши скрипты можно несколькими путями. Во-первых, изменить сами строки. Те, что в одинарных кавычках обрабатываются движком быстрее своих собратьев.

    Код:
    bitmap.draw_text(0, 0, 608, 32,
        ‘This string is being processed faster ’ + “than this one.\n”)


    Используйте двойные кавычки, только если вы задействовали символ подстановки (например “\n”) или интерполяцию/внедрение переменных (например, “#{some_numeric_calculation_or_value}”). Также не используйте внедрение переменных, если у вас есть только одно значение. Вы можете использовать функцию value.to_s, которая сконвертирует число в строку.

    Код:
    bitmap.draw_text(0, 0, 128, 32, “#{actor.hp*100/actor.maxhp}%”)

    Код:
    bitmap.draw_text(0, 0, 128, 32, $game_party.gold.to_s)


    Первая строка кода выше прорисовывает оставшееся количество HP героя в процентах с символом %, вторая строка прорисовывает только количество денег, которым владеет партия. Нет никакой необходимости использовать что-то вроде этого:

    Код:
    bitmap.draw_text(0, 0, 128, 32, “#{$game_party.gold}”)


    Или ещё хуже:

    Код:
    bitmap.draw_text(0, 0, 128, 32, “#{$game_party.gold}”.to_s)


    Другой пример того, как уменьшить время обработки, это, очевидно, писать меньше кода. И под меньшим количеством кода я подразумеваю не короткие скрипты, а избавление от бесполезных и ненужных временных переменных (смотрите 5.4. для подробностей). Ещё одно полезное решение — это ветвление. В этом случае даже если у вас огромное количество строк кода, он будет достаточно быстрым, так как будет обрабатываться только когда это необходимо. Вы также можете уменьшить время обработки, используя блоки памяти, а не распространение адресации памяти (смотрите 3.3. для подробностей).

    Ещё одна хитрость уменьшения времени обработки состоит в сохранении результатов выполнения метода так, чтобы не было необходимости запускать его снова и снова. Вместо того чтобы использовать такой код:

    Код:
    for actor in $game_party.actors
      actor.hp -= calculate_special_skill_damage(skill)
    end


    Следует использовать код, подобный этому:

    Код:
    result = calculate_special_skill_damage(skill)
    for actor in $game_party.actors
      actor.hp -= result
    end


    Однако, имейте в виду, что это действенно только в случае сложных вычислений. Сохранение и загрузка памяти между CPU и RAM в 10 или 15 раз медленнее простых арифметических операций, о чём я уже говорил. В первом примере метод запускается каждый раз для каждого героя. Во втором примере метод запускается только один раз и его результат сохраняется и может быть использован позднее. Может это и не сильно уменьшит время обработки скрипта, но представьте себе ситуацию, где вам нужно будет запустить метод для обработки каждого навыка в базе данных, коих, к примеру, 200 штук и в течение этого метода нужно будет выполнить другую вещь, например, для 300 анимаций. В итоге получится 200×300 = 60000 выполнений части кода для анимации. Вы хотите, чтобы ваш скрипт запускался 60000 лишних раз только в одном кусочке кода? Я так не думаю. Заметьте, что это имеет смысл только в том случае, если результат одинаковый для каждого актера, как в данном примере. А вот пример, где это не поможет:

    Код:
    for actor in $game_party.actors
      actor.hp -= calculate_special_skill_damage(actor.id)
    end


    Код:
    result = calculate_special_skill_damage(actor.id)
    for actor in $game_party.actors
      actor.hp -= result
    end


    Второй пример кода вызовет ошибку (undefined method ‘id’ for nil:NilClass) или ещё хуже: сработает. В этом случае результат будет зависеть от того, к какому герою применяется метод, так что вы не можете рассчитать всё заранее и сохранить результат. У вас нет другого выбора, кроме как производить вычисление каждый раз для каждого героя, так как он зависит от героя.

    Еще одно действие, которым вы можете улучшить производительность, это предотвратить обработку данных более чем один раз. В основном, это происходит, если вы не до конца понимаете, как работает RMXP. Вот пример обработки одного и то же два раза:

    Код:
    number = 5
    “#{number}”.to_s


    Это лишнее. Внедрение переменной и вызов .to_s делают одно и то же, только вот внедрению требуется больше времени на обработку. Использование to_s, позволяет снизить время обработки почти в два раза. Но будьте осторожны! Взгляните на приведённые ниже примеры.

    Код:
    nums = [0, 1, 2, 3]
    “#{nums[0]} #{nums[1]} #{nums[2]} #{nums[3]}”


    Код:
    nums = [0, 1, 2, 3]
    nums[0].to_s + nums[1].to_s + nums[2].to_s + nums[3].to_s


    Что вы думаете? Какой из них будет работать быстрее? Если вы думаете, что второй, то вы абсолютно правы. Однако разница незначительна и составляет всего-навсего 2%. Почему так мало? Всё очень просто. Возможно, операции to_s и требуется меньше времени на выполнение, чем внедрению переменных, но конкатенация строк (или другими словами присоединение одной строки к концу другой оператором +) приведет к потере времени процессора. Таким образом, если вам нужно сконвертировать число в строку, используйте to_s, но если вам нужно сконвертировать в строку и соединить с другими строками, то, по сути, нет разницы какой метод. Главное не используйте оба одновременно.

    5.4. Не бойтесь использовать больше кода

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

    Первый появляется с большим количеством лишних строк, в то время как вы могли бы использовать другую идею или метод для обработки данных. Возможно, вы даже могли бы использовать меньшее количество памяти для обработки данных. Это не плохо, если у вас есть такие строки, но стараюсь свести их до минимума. Большинство из них появляются в результате недостаточных знаний о том, как работаю компьютерные системы, а также о том, как устроен интерпретатор RGSS. Со временем вы обязательно наберётесь больше опыта и, взглянув на свои старые наработки, сразу же заметите такие строки и подумаете или даже воскликните “Эй! А зачем мне нужно ЭТО?! Ведь я могу сделать то же самое намного проще, сохранив время для обработки и при этом оставить только 4 команды из 7…” или “Эй… Тут столько ненужных переменных…” или…

    Второй вид я называю разделением кода. Само собой есть такие вещи, которые можно спроектировать элегантно, используя лишь несколько строчек кода, например панель с градиентом. Но сколько будет смысла в том, что я сделаю? Этот вид кода использует ветвление условий для разделения процессов в коде. Ваш элегантный код может быть в состоянии обработать это и то и ещё одну штуку в том числе, но если есть лучшее решение для этого и того, то зачем нужна универсальная обработка, если есть более эффективный способ? Использование ветвления позволит отделить мух от котлет и обработать это в основном процессе, вместо того, чтобы создавать новый код для того и ещё одной штуки. Такое решение непременно займет больше строчек кода, но сам скрипт будет выполняться намного лучше. Возьмем, к примеру, градиентную панель, к которой надо применить 2 стиля.

    Код:
    class Bitmap
      def gradient_bar_2(x, y, w, h, fill_rate, c1, c2)
        # fill background with black color
        fill_rect(x, y, w, h, Color.new(0, 0, 0))
        # iterate through x coordinates, but not for all, only for the
        # fill_rate
        for i in 0...(w * fill_rate).to_i
          # iterate through y coordinates
          for j in 0...h
            # how the calculation works:
            # 1. base color is the color of c1
            # 2. get the difference between c2 and c1
            # 3. depending on which iteration it is, a color between
            # c1 and c2 will be chosen
            # 4. what “* i / w” is for: it will multiply the difference
            # with the “percentage” of the current iteration and modify
            # the difference
            r = c1.red + (c2.red - c1.red) * i / w
            g = c1.green + (c2.green - c1.green) * i / w
            b = c1.blue + (c2.blue - c1.blue) * i / w
            # if the second style is used
            if $style == 1
              # This will modify the colors depending on which “row” is
              # currently being drawn. “style 1” will make the upper
              # lines darker than lower lines. The lowest lines are in
              # the normal color. The result is a multi gradient.
              r = r * j / h
              g = g * j / h
              b = b * j / h
            end
            set_pixel(x+i, y+j, Color.new(r, g, b))
          end
        end
      end
    end


    Прорисовка пиксель за пикселем (а это то, что делает метод set_pixel) занимает довольно продолжительное время и может вызвать лаги. set_pixel почти на 40% быстрее, чем fill_rect и это значит, что set_pixel следует использовать только для прорисовки одного пикселя, а fill_rect если нужно прорисовать два и более пикселя. В следующем решении прорисовка стиля 1 будет всё так же занимать какое-то время, однако стиль 0 будет прорисовываться ГОРАЗДО быстрее.

    Код:
    class Bitmap
      def gradient_bar_2(x, y, w, h, fill_rate, c1, c2)
        fill_rect(x, y, w, h, Color.new(0, 0, 0))
        # check for style 1 already at the beginning
        if $style == 1
          for i in 0...(w * fill_rate).to_i
            for j in 0...h
              r = (c1.red + (c2.red - c1.red) * i / w) * j / h
              g = (c1.green + (c2.green - c1.green) * i / w) * j / h
              b = (c1.blue + (c2.blue - c1.blue) * i / w) * j / h
              set_pixel(x+i, y+j, Color.new(r, g, b))
            end
          end
        # this piece will get executed if “style 0” is being used.
        else
          for i in 0...(w * fill_rate).to_i
            r = c1.red + (c2.red - c1.red) * i / w
            g = c1.green + (c2.green - c1.green) * i / w
            b = c1.blue + (c2.blue - c1.blue) * i / w
            fill_rect(x+i, y, 1, height, Color.new(r, g, b))
          end
        end
      end
    end


    Если последовательно сравнить эти два кода (без строк с комментариями), то вы увидите, что второй больше первого на 4 строки, однако работает быстрее при использовании стиля 0. Пока что это голословное заявление, и вы можете не поверить, что второй код работает ГОРАЗДО быстрее со стилем 0. Чтобы убедиться своими глазами, просто скопируйте первый код и попробуйте испытать каждый стиль. Затем скопируйте второй код и попробуйте снова. Вы сразу заметите невероятные лаги со стилем 1 в обоих случаях, но со стилем 0 второй код будет выглядеть невероятно быстрым. Если вы, дочитав досюда, действительно решили опробовать сделать это, то создайте новый проект в RMXP и используйте следующий код. Просто добавьте его выше категории Main, как и один из кодов для градиента выше.

    Код:
    $style, $c1, $c2 = 1, Color.new(255, 0, 0),  Color.new(255, 255, 0)
    $sprite = Sprite.new
    $sprite.bitmap = Bitmap.new(128, 16)
    $sprite.z = 1000
    class Scene_Map
      alias _5_4_test update
      def update
        $sprite.bitmap.gradient_bar_2(0, 0, 128, 16, 0.8, $c1, $c2)
        _5_4_test
      end
    end


    Вы можете подумать, что улучшение в коде не очевидно, но представьте себе, если потребуется управлять 6 стилями, для 5 из которых код работает быстрее.
    Если вы заботливый скриптер и выпускаете обновления для ваших старых скриптов, то в своём старом коде вы обязательно заметите возможность усовершенствовать его тем или иным способом. Вы просто почувствуете необходимость сделать их лучше, чтобы они отражали ваше текущее состояние знаний. (могу привести пример из своей жизни, в сети вы больше не найдёте мой ранний скрипт под названием Credits. Новый скрипт Picture Movie Scene делает тоже, что делал Credits, но у него гораздо больше возможностей.)


    5.4.1. – злобный лаг, вызванный градиентом (слева стиль 0, справа стиль 1)

    5.5. RAM или CPU?

    Лаги являются проблемой во всей области программирования, не только в разработке игр. Само слово «лаг» — это только мирской термин, который говорит о том, что процессор (CPU) недостаточно мощный для обработки данных с такой скоростью, чтобы это прошло незамеченным. Изучайте чем живёт область программирования, изучайте как работают алгоритмы, изучайте как работает скриптовый язык и изучайте принципы работы процессоров и тогда вы шаг за шагом приблизитесь к избавлению от лагов. Заметьте, что эта глава не только объясняет, откуда берутся лаги, но и помогает вам лучше понять почему и что можно с этим сделать. Собственно говоря, всё это пособие рассказывает о том, как избежать лагов.



    [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9614&viewfull=1#post9614"]Вернуться к содержанию...[/IURL]
    Последний раз редактировалось Arnon; 30.10.2012 в 10:57.

  7. #7

    По умолчанию

    6. Улучшаем свои навыки

    Итак, вы скриптер или программист, но прежде всего, человек, как и все остальные. Однако по какой-то причине в мире есть такие персоны, которые считают себя лучше других, при это подкрепляя свои доводы ненастоящими или уж совсем идиотскими причинами. Вы никогда не будете крутым, если грубите и унижаете других. В этой главе мы проработаем с вашими отношениями с окружающим миром, так как не он вращается вокруг вас, а вы вращаетесь вокруг него.

    6.1. Скрипты с фигурными {} скобками

    Чтобы в самом начале отсечь все недоразумения, поясню, что команда {…} делает абсолютно то же самое, что и do … end. Они обе используются для определения блока. В блоке команды собираются вместе и интерпретируются в целом. Это МОЖЕТ улучшить производительность вашего скрипта, если используется правильно, но совсем не обязательно. Все локальные переменные, определённые в блоке удаляются после выхода из этого блока.

    Код:
    loop {
      a = 0 if a == nil
      a += 1
      break if a == 100
    }
    a.ceil


    Такой код покажет ошибку undefined method or variable (неопределённый метод или переменная) для объекта a. Более подробную информацию можно найти в файле помощи к RMXP. Помните, что фигурные скобки {} используются и для определения хэша Hash — произвольного класса в RGSS, который очень похож на Array, где для определения используются квадратные скобки []. Фигурные скобки {} также указываются во время внедрения переменной в строку (смотрите раздел 5.3). Вы видите, что у {} есть несколько функций. Таким образом, один лишь факт использования фигурных скобок {} в скриптах не делает вас крутым скриптером, даже если вы подражаете более известным личностям.

    6.2. Однострочные методы и функции

    Однострочные методы и функции — это напрасная трата свободного места в коде. Для того чтобы разобраться, почему они являются операциями, занимающими лишнее время, нужно понять что происходит во время вызова такого метода. Я дам только краткое объяснение принципов работы архитектуры CPU, потому что всё описание целиком может занять целую книгу.

    У процессоров обычно есть несколько регистров, которые выступают в качестве рабочей памяти, которая хранит обрабатываемые в настоящий момент данные (у разных CPU разное количество регистров, так например у Pentiums 4 их 128, у более старых ARM их 37, и т.д.) Эти регистры намного ближе к самому процессору, чем так называемый L1 кэш. Процессор работает непосредственно с этими регистрами. Обычный размер регистра равен 32 битам (или 4 байтам), но в настоящее время всё более популярны на рынке процессоры с 64-битными регистрами.

    1. Ваш код в скрипте не запускается в таком виде, как он есть, для начала его нужно перевести на язык понятный процессору. Так как RGSS является объектно-ориентированным языком (в главе 8 это описано более подробно), то процесс перевода довольно сложен. За первые шаги перевода ваш код чаще всего трансформируется в более простой код (который занимает больший объём), где, допустим, ваши циклы полностью упрощаются. В конце код переводится в ассемблерные команды и затем в машинный код. Некоторые интерпретаторы без встроенной оптимизации могут перевести код сразу в команды ассемблера, который займёт меньше места, но замедлит работу CPU из-за выполнения множества ненужных команд.
    2. Во время вызова функции в вашем компьютере происходит следующее:

      • Все команды в вычислительном конвейере необходимо усечь, что приводит к потере 20 циклов процессора на Pentium 4 и означает, что простой вызов метода уже занимает такое же время, как 20 операций сложения.
      • Процессор хранит адрес текущей команды в оперативной памяти (RAM) в стеке, который занимает времени на обработку в 10 или 15 раз, чем время, за которое CPU бы сложил два числа.
      • Теперь все аргументы, которые передаются на функции, должны быть добавлены в стек, что снова отнимает время у процессора.
      • Теперь за дело берётся т.н. счетчик команд (который определяет адрес следующей выполняемой команды) и устанавливается адрес переводимой функции.
      • Вычислительный конвейер заполняется, от чего следует, что CPU нужно подождать ещё 20 циклов до выполнения следующей команды.

    3. Теперь функция запускается на выполнение. После того как достигнуто её окончание, запускается очень похожий процесс, который восстанавливает старую позицию в коде, в которой следует продолжать выполнение. Плюс ко всему в стеку сохраняются все возвращаемые значения, ведь CPU нужно получить доступ к результатам выполнения функции уже после её выполнения, в том месте, где она вызывалась. И вот вновь вычислительный конвейер нужно заполнить командами ожидающими выполнения с того места, где обработка остановила выполнение кода для перехода к адресу функции.


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

    Код:
    def sum_two_numbers(a, b)
      return a + b
    end


    Код:
    class Scene_Load < Scene_File
      def commandnewgame_partysetup
        $game_party.setup_starting_members
      end
    end


    Даже самый плохой программист не стал бы использовать нечто вроде этого. Для таких ужасных скриптов не может быть абсолютно никаких оправданий, особенно учитывая то, что код делает ненужные действия и тормозит весь процесс обработки. Единственная ситуация, где имеет смысл применить однострочный метод — это перенаправление переменных из класса так, что код станет проще.

    Код:
    class Game_Enemy
      def gold
        return $data_enemies[@enemy_id].gold
      end
    end


    Избегайте однострочные методы любой ценой. Ещё немного информации об архитектуре процессора можно найти в [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9622&viewfull=1#post9622"]главе 8[/IURL].

    6.3. Бесполезные и бессмысленные команды

    Как же я обожаю такие вещи. Встречаются люди, которые публично заявляют себя великолепными скриптерами и каким-то образом другие люди им верят, хотя такие ораторы совершают грубые ошибки и пишут код из 20 строчек там, где можно обойтись лишь 10. Это не было бы так плохо, не будь их ошибки очевидными. Я не буду называть имя автора следующего кода, но я думаю его довольно легко узнать. Он позволяет переключить лидера партии путём последовательного выбора каждого героя при нажатии кнопок L или R (Q или W). Взгляните на следующий код и, скорее всего, вы найдете способ сократить его самостоятельно.

    Код:
    class Game_Party
      def shift_forward
        @actors << @actors.shift
        $game_player.refresh
      end
      def shift_backwards
        @actors.insert(0, @actors.pop)
        $game_player.refresh
      end
    end
    class Scene_Map
      alias_method :s____partycycling_scnmap_update, :update
      def update
        if Input.trigger?(Input::L)
          $game_party.shift_forward
        elsif Input.trigger?(Input::R)
          $game_party.shift_backwards
        end
        s____partycycling_scnmap_update
      end
    end


    Не правда ли он прекрасен? О да, прекрасен в своём безобразии. Следующий код будет делать то же самое:

    Код:
    class Scene_Map
      alias upd_ptc_later update
      def update
        if Input.trigger?(Input::L)
          $game_party.add_actor($game_party.actors.shift.id)
        elsif Input.trigger?(Input::R)
          $game_party.actors.unshift($game_party.actors.pop)
          $game_player.refresh
        end
        upd_ptc_later
      end
    end


    Это возвращает нас к названию этого раздела: используйте то, что уже есть. Я использовал метод add_actor из класса Game_Party, в котором уже есть вызов функции $game_player.refresh. Так как нет способа добавить героя на первую позицию в партии и передвинуть каждого героя на одну позицию, я удалил последнего героя (pop) и поставил его на первое место (unshift) (смотрите [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9617&viewfull=1#post9617"]раздел 3.3[/IURL] где описывается принцип работы с массивами). Используйте то, что вам дано, не пишите новый код, если он не нужен. Вызов метода является очень дорогостоящей операции ко времени выполнения, особенно одностроковые методы (смотрите [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9620&viewfull=1#post9620"]6.2[/IURL] для подробностей). Обратите внимание, как мне удалось управлять массивом @actors с помощью вызова методов pop и unshift и это не смотря на то, что массив @actors приватный экземпляр переменной в Game_Party, и доступен только для чтения, но не для изменения. Это значит, что вы можете обратиться к $game_party.actors, но не можете ничего изменить $game_party.actors = something (смотрите 7.8. для подробностей).

    6.4. Слишком много SephirothSpawn’а

    Смотрите разделы 6.2., 6.3., 6.5. и 6.7., где описаны все типичные ошибки.

    6.5. О том как не выставить себя дураком

    Что я понимаю под дураком: это когда автор скрипта, во-первых, полон невежества, во-вторых, высокомерен и в-третьих, предосудителен. Если это не о вас, то можете пропустить эту часть.
    Если кто-нибудь обнаружил в вашем творении баг, ОБРАТИТЕ НА ЭТО ВНИМАНИЕ. Не говорите “Это твоя вина, у меня всё работает.” Конечно, можно упомянуть “Попробуй установить последнюю версию.”, может вы уже исправили его там. Но если пользователь уже использует новую версию, то постарайтесь найти ошибку. Очень часто происходят такие ситуации, когда вы не рассмотрели все возможные результаты обработки скрипта или же просто допустили опечатку. Так же бывает, что обычное изменение кода (даже если вы вносили исправление!) приносит новые баги. Чем больше и сложнее ваш скрипт, тем больше вероятность произвести баг. А чем больше скриптов в проекте, тем больше вероятность, что они будут конфликтовать друг с другом. Даже сделав ваши собственные скрипты совместимыми друг с другом, вы можете избежать многих ошибок, будь это скрипт с 5 или 1000+ строками кода, или очень сложная система (вроде энкодера или дектриптора).

    Если кто-то у вас попросит помощи разобраться с чужим скриптом, не делайте кислую мину и не говорите “Чего?! Это не мой скрипт. Иди к его автору. Тут одни нубы!” Не надо обижать новичков исходя только из того факта, что вы не автор. Само собой очевидно, что автор лучше разбирается в своём творении, но вы всегда можете сказать “Я посмотрю, но ничего не обещаю. Будет лучше связаться с автором, он лучше знает свой скрипт.” Это имеет отношение не столько к скриптам, сколько к хорошим манерам. Очень неприятно видеть именитых скриптеров, которые ведут себя не самым лучшим образом. Разочарование от их слов разрушает ваше представление о человеке и в дальнейшем с ним не захочется иметь ничего общего.
    Никто не будет использовать ваши скрипты, если вы грубиян. В мире много и других отличных скриптеров на RGSS. К тому же если вы читаете эту электронную книгу, то вы, скорее всего, не один из лучших.

    6.6. Повторное изобретение колеса

    Многие пытаются избежать этого, но зачем?! Это очень хорошая возможность для каждого скриптера изобрести колесо заново. В этом случае вы НЕ ищите легких путей и смысл не в том, чтобы сделать более хороший скрипт, а в том, чтобы научиться чему-то новому. Используя только чужие наработки, вы далеко не уедете. Ваши скрипты не будут уникальными, процесс отладки затруднится из-за недостатка понимания принципов работы RGSS и ваши скрипты будут полны лагов, потому что другие скриптеры что-то напутали при разработке, а вы не знаете, как это починить. Не поймите меня неправильно, вы можете использовать чужие инструменты, но следует попытаться создать и свои, которые будут работать наравне и даже лучше чужих. Большую пользу от чужих работ принесет не слепое использование, а проверка и анализ его кода. Только тогда вы сможете чему-нибудь научиться.

    Вам нравится панельки у SephirothSpawn’а? Или у Trickster’а? А может мои? Но почему бы не попробовать создать их самостоятельно? Скачайте все наши работы, сравните их, разберитесь, как они работают и (что наиболее важно) почему они работают. Затем попробуйте создать собственный скрипт. Да, вы снова изобретёте колесо, но это будет хорошим опытом. Вы узнаете, как работать с рисунками и как создавать их с помощью скриптов.

    Вы можете подумать “Но скрипт, который мне нужен УЖЕ существует. Зачем создавать ещё один? Ведь он будет точно таким же…” Это не так. Ваш код никогда не будет идентичен другим. Он может быть похож, но не точно таким же (если только ты не скопипастишь, ворюга!). Ваши мысли о том как долны работать вещи, например, переключение игроков в партии, скорей всего, будут полностью отличаться от идей других людей. В этом случае у вас должна быть задача “Сделать скрипт лучше, чем этот парень.” Учитесь на чужих ошибках. Улучшение не значит лишь добавление новых фишек или изменение внешнего вида. Улучшение также может означать избавление от ненужного кода и замена его на полезный код.

    С другой стороны, можно сделать свой скрипт легким для понимания, даже путем добавления кода. Само собой лишь пара новых методов каши не сварят. Вам нужно будет составить коллекцию методов, которые другие люди смогут использовать в нужной для них ситуации, а не дожидаться пока посыпятся “А как мне сделать это и это? Помоги мне?” Не бойтесь и сами задавать такие вопросы, вы ничего не теряете.

    Я всегда горжусь тем скриптером, который задаёт мне вопрос или просит о помощи, порой чуть ли даже не к половине моих скриптов. Но, в конце концов, он создаёт свою собственную работу и в большинстве случаев выбирает для этого другой путь, нежели я. Да, он спросил меня, но в итоге стал сам себе учителем. Почему так получается? Он спрашивает меня одно, потом второе, потом третье и т.д. и как следствие от ответов собирает достаточно знаний, которые помогают ему воплотить все свои идеи и сделать скрипт проще и лучше. Он мог бы использовать мой скрипт и остановится на этом, но нет. Он пошёл верным путём и понял, как скрипт работает и смог сделать, то, что ему нужно самостоятельно.

    6.7. Навязывание стандартов

    НЕ НАВЯЗЫВАЙТЕ СТАНДАРТЫ! Наличие стандартов — это хорошо, использование стандартов — тоже неплохо, но навязывание стандартов — это кривая дорожка корпорации Microsoft: Людям приходится использовать их, или всё пойдёт не так. Люди такие существа, у которых есть идеалы и индивидуальные особенности. Навязывая им свои стандарты, вы ОБЯЗАТЕЛЬНО наживёте себе врагов, которые не согласны с вашим подходом. Именно поэтому из принципа многие не станут использовать ваши скрипты или им просто не захочется внедрять их в свои игры, потому что они не совместимы с другими системами. В итоге вы окажитесь невежественным придурком, постоянно повторяющим “Вам нужно это, вам нужно то, вам нужно третье, чтобы мой скрипт заработал, потому что он основан на стандартах и ни на шаг от них не отойдёт.”, особенно если это даже не общепринятый стандарт. О том, как не выставить себя дураком смотрите в разделе 6.5.

    Не поймите меня неправильно, стандарты хороши, но только не тогда, когда они надуманы самим автором. В них нет никакого смысла, если не ВСЕ ЛЮДИ пользуются и следуют им. Если у вас нет полномочий для обеспечения соблюдения стандарта, не делай их!

    Маленькая заметка на полях: SDK (Standard Development Kit = Стандартный комплект разработчика) весьма ироничное название, потому что на самом деле оно не соответствует самоопределению «Стандартный». Не существует такой вещи, как стандартная зависимость. SDK своим существованием вызывает только несовместимость в скриптах, разделяя их на использующие и SDK не использующие SDK скрипты, независимо от того, применяются ли псевдонимы (смотрите раздел [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9616&viewfull=1#post9616"]2.1[/IURL]). SDK 2.x ещё более несовместимы, чем скрипты для SDK 1.x. Даже сегодня в программировании не существует стандартов, так как это довольно творческая ветвь индустрии. Просто к настоящему времени достаточно развиты лишь несколько методов и подходов для программирования. Стандарты не имеют никакого смысла, пока все повсеместно не начнут их использовать. А этого никак нельзя достичь, навязывая их, особенно, заявив, что ваши стандарты безупречны, что само собой не так. Пытаться установить стандарты не следует людям, которые не являются профессионалами в этой области, и которые не имеют достаточного авторитета. Если лучшие из лучших не могли создать стандарты в течение 50 лет программирования, как несколько любителей в состоянии это сделать?

    6.8. О скриптах, которые никому не нужны

    Эту тему довольно трудно объяснить. Пример поможет лучше понять, что я имею ввиду:

    Вместо того, чтобы герой умирал от нулевых HP, пусть умирает когда SP равны нулю.

    Иногда это не легко увидеть, но иногда просто очевидно. Главная причина, почему не стоит тратить время на создание таких скриптов — их никто не будет использовать. Вы бы использовали упомянутый мною скрипт? Я бы не стал. Даже с точки зрения игрока я не вижу необходимости в такой функции. Это будет раздражать. А не подогревать интерес к игре. Подумайте об этом.
    Разум человека может придумать всё что угодно, даже абстрактные формы и это значит, что в реальном мире они в них не будет никакого смысла. Так и со скриптами, есть такие идеи, которые попросту не нужны. Другой подобной проблемой является проблема со скриптами, у которой бессмысленные настройки. Вы когда-нибудь хотели выбрать в бою 2 случайных героя, которые не были бы одним из тех героев, что выбирает конкретный враг или одного врага, следующего в списке за тем, что выбирает герой?! Извините меня, но это идиотизм.

    Определите цель скрипта, который вы создаёте, и подумайте о том, сколько в ней смысла, и следует ли вкладывать туда бесполезные настройки, которыми никто не пользуется. Это прекрасно, если в нём несколько жизненно важных вариантов использования или гибкость настройки, а может быть и совместимость с другими скриптами. Но слишком много настроек только запутает пользователя так, что он не захочет использовать ваше творение и наверняка принесёт головную боль и вам самим.
    Представьте себе скрипт на 100 строчек с 30 настройками (что даёт приблизительно 70 строк рабочего кода). Нужно ли пользователю дать возможность выбирать 13 или 14 кадров в переходе экрана, если в любом случае можно использовать стандартное значение?! Если и найдётся такой человек, которому понадобится эта возможность, то он попросту попросит вас об этом. Вы скажите ему, как персонализировать ваш скрипт под его нужны, изменив одну или две строчки кода, чтобы всё работало, вместо того чтобы терять драгоценное время на реализацию отдельной настройки и параллельно нескольких других. Лучше уж пусть будет несколько нужных настроек, чем гора ненужных. Конечно, если у вас накопится несколько запросов одной и той же опции, то её можно добавить. Хорошая программа рождается постепенно по мере работы с клиентами, а не наличием кучи опций в самом начале. Эта лишняя трата времени.

    Большинство людей не читает инструкции, и не знает на что способен ваш скрипт, особенно если там надо изменить 30 и более опций. Это довольно обескураживающе, когда встречаешь новенький скрипт, который должен добавлять тень и отражение, а в нём 5-страничная инструкция с 50 вариантами настройки, большинство из которых бесполезные. Обычный пользователь не владеет навыком написания скриптов, они довольны тем, что вы даёте игрушку и она работает сразу после добавления в их проект. Придерживайтесь качества, а не количества.

    6.9. RAM или CPU?

    В этой главе рассказывается, что вы не превосходите других людей. Она поясняет, что большой размер скрипта это не обязательно круто, если в этом нет необходимости. Не делайте больших скриптов только ради объёма и не обрабатывайте ненужные данные. Если вы хороший скриптер, то придерживайтесь минимально необходимого объёма кода, а не надувайте воздушные шары. Если вы хороший скриптер, это также не означает, что вы лучше других людей. Уважайте их так, как они уважают вас. Если никто не использует скрипт в который вложена масса усилий, из-за того что вы дурак и с плохими манерам, то в вашем скрипте для других людей нет смысла. В таком случае пишите скрипты для себя и наслаждайтесь вашим одиночеством и раздутым эго.

    Ах, право, я отвлёкся… В рамках нашей темы, используйте ваши внутренние CPU и RAM в равных количествах. Подумайте головой прежде, чем сделать что-то и храните в памяти важные вещи, такие как хорошие манеры. Прямо сейчас сохраните в вашей памяти вот что: вы ничем не лучше остальных, что бы вы о себе не мнили. Ведите себя сдержанно и будьте спокойными. Рано или поздно вас похвалят за скромность. Если кто-то действует вам на нервы, просто игнорируйте. В один прекрасный день вы осознаете, что чужие нападки не имеют значения. Если вы не можете сидеть спокойно, то идите и начните революцию — это никогда не поздно.



    [IURL="http://rpgmaker.su/showthread.php/518-Создание-скриптов-на-RGSS-для-людей-со-средними-знаниями-и-экспертов?p=9614&viewfull=1#post9614"]Вернуться к содержанию...[/IURL]
    Последний раз редактировалось Arnon; 29.10.2012 в 21:18.

  8. #8

    По умолчанию

    Резерв для главы №7.

  9. #9

    По умолчанию

    8. Полезные ссылки

    Так как это электронное руководство объясняет лишь базовые принципы, я привожу ссылки, по которым можно получить дополнительную информацию о предметах наших обсуждений.

    Ruby

    http://ru.wikipedia.org/wiki/Ruby

    Стек

    http://ru.wikipedia.org/wiki/Стек

    Рекурсия

    http://ru.wikipedia.org/wiki/Рекурсивная_функция

    Интерпретатор

    http://ru.wikipedia.org/wiki/Интерпретатор

    Компилятор

    http://ru.wikipedia.org/wiki/Компилятор

    Машинный язык/код

    http://ru.wikipedia.org/wiki/Машинный_код

    Процессор (CPU)

    http://ru.wikipedia.org/wiki/Процессор
    http://ru.wikipedia.org/wiki/Архитектура_процессора

    Объектно-ориентированное программирование

    http://ru.wikipedia.org/wiki/Объектн...рование

    Память (RAM)

    http://ru.wikipedia.org/wiki/ЗУПД

    Массив

    http://ru.wikipedia.org/wiki/Массив

    Хэш

    http://ru.wikipedia.org/wiki/Хеш-таблица

    HUD

    http://ru.wikipedia.org/wiki/Head-Up_Display_(игры)

    Сложность алгоритма

    http://habrahabr.ru/post/104219/
    http://ru.wikipedia.org/wiki/Вычислительная_сложность

    Логарифм

    http://ru.wikipedia.org/wiki/Логарифм

    Булева алгебра

    http://ru.wikipedia.org/wiki/Булева_алгебра

    Вызов по значению/Вызов по ссылке

    http://ru.wikipedia.org/wiki/Передач...ование)
    Последний раз редактировалось Arnon; 29.10.2012 в 21:00.

  10. #10

    По умолчанию

    Резерв для главы №9.

Страница 1 из 3 123 ПоследняяПоследняя

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Метки этой темы

Социальные закладки

Социальные закладки

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •