Скрипты - Базовое написание скриптов
В этом уроке рассмотрено базовое написание скриптов в GameStart.
Глоссарий
Далее описаны важные понятия используемые в этом уроке:
- Класс: - объект языка программирования который содержит (инкапсулирует в себе) переменные и функции.
- Экземпляр: - экземпляр класса (объект класса) в памяти используемый для хранения содержимого класса, отдельной копии переменных.
Вы можете найти дополнительную информацию об объектах скриптах в Документации по Squirrel.
Теория
Скрипты основанные на событиях
Скриптинг в GameStart основан на событиях. Это означает что цикл ядра обрабатывается движком и ваши скрипты обрабатывают специфичные события, когда те возникают.
Например, типичный скрипт элемента (скажем, корабля) может выглядеть примерно так:
class PlayerShip { function OnUpdate(item, dt_clock) { // ... Делаем нечто для обновления корабля. } function OnCollision(item, with_item) { // ... Обновляем "энергию" корабля или взрываем корабль если она достигло нуля. } }
Давайте опустим то как связать скрипт с элементом, мы рассмотрим это позже. Сейчас давайте сосредоточимся на самом скрипте.
Этот класс определяет две функции: OnUpdate() вызывается при каждом обновлении кадра, OnCollision() вызывается когда два объекта сталкиваются.
Обратите внимание что первый параметр обоих этих функций item (элемент). Это делается для того, что вы могли использовать этот класс для более чем одного элемента и знали для какого из элементов вызывается ваш скрипт.
Эти функции обратного вызова - основа вашего приложения, таким образом вы знаете какие функции обратного вызова доступны, это имеет важное значение для получения максимальной отдачи от средств которые обеспечивает движок.
Обратите внимание: Полный список функций доступен тут.
Сохранение состояния в скрипте
Конечно вы можете хранить переменные в вашем классе для отслеживания состояния элемента. В предыдущем скрипте, на примере корабля, нам нужно сохранить "энергию" корабля. Изменения в скрипте будут следующими:
class PlayerShip { energy = 0 function OnUpdate(item, dt_clock) { // ... Делаем нечто для обновления корабля. } function OnCollision(item, with_item) { // ... Обновляем "энергию" корабля или взрываем корабль если она достигло нуля. } function OnSetup(item) { energy = 50 } }
Появилась новая функция обратного вызова: OnSetup(), она вызывается движком во время установки элемента (один раз). Эта функция используется для установки здоровья корабля в значение по умолчанию 50.
Важно обратите на то что элемент создаёт свой экземпляр класса. Таким образом, хотя код класса может быть общими для двух различных элементов (путем присвоения того же класса обоим элементам) они будут использовать различные области памяти для хранения переменных класса.
Вернёмся к нашему кораблю: например, если задать класс PlayerShip для двух различных элементов, уменьшение энергии одного корабля не приведет к уменьшению энергии другого, даже если они оба выполняют одинаковый код.
Надеюсь, вы теперь получили более четкое представление о том как работают скрипты элементов.
Но скорее всего вашим скриптам нужно общаться со сценой окружающей среды, так что давайте посмотрим, как это сделать.
Взаимодействие скриптов
GameStart обеспечивает несколько путей для того чтобы получить экземпляр скрипта элемента (или любого заскриптованного объекта). Для элементов вы можете использовать функцию ItemGetScriptInstanceFromClass(item, string class_name).
Теперь как только вы получили экземпляр элемента вы можете иметь доступ к нему подобно любому экземпляру. Давайте рассмотрим подробный пример того когда два корабля сталкиваются:
function OnCollision(item, with_item) { local other_item_script = ItemGetScriptInstanceFromClass(with_item, "PlayerShip") energy -= other_item_script.energy / 2 }
Теперь когда два корабля сталкиваются, в функции OnCollision() получаем экземпляр скрипта для экземпляра класса PlayerShip и вычитаем половину его энергии из нашей и результат присваиваем переменной которая хранит энергию нашего корабля.
Обратите внимание: конструкция вида a -= b это эквивалент конструкции a = a - b. Также вы можете использовать эту нотацию для всех операторов(a *= b, a &= b, и так далее...).
Подождите секунду! Там очевидная проблема с этим пример кода: Что если объект столкновения не является экземпляром класса 'PlayerShip'? В этом случае скрипт "выбросит" исключение. Это специальная конструкция языка для обработки таких не очевидных случаев. Исключение можно обработать и продолжить выполнение программы. Посмотрите на код ниже:
function OnCollision(item, with_item) { try { local other_item_script = ItemGetScriptInstanceFromClass(with_item, "PlayerShip") energy -= other_item_script.energy } catch (e) // "перехватываем" исключение { // Не экземпляр класса "PlayerShip" energy -= 5 } }
Отлично. Теперь когда будет вызвана функция ItemGetScriptInstanceFromClass() сработает исключение и выполнится блок "catch" присоеденённый к блоку "try".
Ntgthm мы знаем что будет если корабль столкнётся с другим объектом.
Другой способ избежать этого состоит в том чтобы использовать функцию ItemHasScript(item, string class_name) для проверки, есть ли экземпляр скрипта в элементе.
Выбор за вами. Вы можете использовать исключения для того чтобы иметь один общий скрипт который может обрабатывать множество типов объектов или же использовать проверку на наличие нужного скрипта проверяя это с помощью конструкции вида (if (has_script) ... else ... и так далее...) и реагировать на различные типы классов.
Практика
Назначение скриптов элементам
Назначение скрипта к любому скриптуемому элементу в GameStart делается на панели Script в окне Property View, для добавления скрипта щелкните кнопку Add....

Назначенный скрипт для Viper Scout на панели Script
Имеется несколько встроенных скриптов для базового поведения и общего использования.
Обратите внимание: Скрипт может быть добавлен к элементу путём перетаскивания из проводника прямо на объект в окне 3D просмотра.