000176. Выделение памяти
Всем привет! В этом уроке мы ознакомимся с функцией выделения памяти и рассмотрим подробный пример работы этой фишки.
Иногда при проектировании больших скриптов возникают проблемы с хранением каких-либо значений в CLEO-скриптах:
Количество локальных переменных мало;
Глобальные переменные не рекомендовано использовать в CLEO;
Глобальные CLEO-переменные могут привести к конфликтам между скриптами;
Проблемы очевидны и решить их можно несколькими способами. Сегодня мы рассмотрим способ с выделением динамической памяти.
Допустим, у нас стоит задача: создать 100 актёров. Их нужно где-то хранить, и буфер является очень привлекательным вариантом. Рассмотрим опкоды, для работы с ними:
Первый опкод выделяет память под буфер, где 120
— это размер (в байтах), а 0@
— переменная, которая будет хранить указатель на начало области памяти (он же совпадает с началом буфера). Второй опкод освобождает выделенную память.
Возникает вопрос: как узнать размер выделяемой памяти, чтобы нам хватило места для записи этих актёров? Поскольку переменные для создания/записи актёров являются ссылками, то размер одного сегмента этой памяти будут равняться 4 байтам, а общий размер выделяемой памяти — 100 × 4 = 400
байт.
Для того, чтобы получить 1 элемент этого буфера, легче всего сделать несколько SCM-функций, которые делали бы навигацию по этой области памяти. Первый участок кода будет выделять память под актёров, а второй — очистка выделенной памяти:
Я назвал SCM-функции "создать массив" и "удалить массив" согласно принципам, по которым они работают. Теперь добавим возможность читать/записывать в ячейку памяти нужное значение по индексу. Индекс будет определятся как Номер × размер
, размер ссылки естественно 4 байта:
Поскольку у нас идёт работа с памятью, мы обязательно применяем опкоды 0A8C
и 0A8D
для чтения и записи её участка. Адрес чтения мы получили за формулой: Начало буфера + ( размер ссылки × индекс )
. Поэтому наши SCM-функции будут обязательно принимать ссылку на выделенный буфер:
Итак, запишем в наш массив 100 случайных актёра, разместив их у Гроув Стрит:
Результат:
Как видим, в скрипте использовалась всего 1 переменная 1@
и мы не потеряли полный доступ ко всем остальным актёрам. Давайте теперь удалим созданных актёров и посмотрим работают ли наши функции удаления и очищения памяти:
Результат:
Улица снова пуста! Интересно понаблюдать за самим процессом создания/удаления этих актёров: видно сколько примерно времени занимает одна итерация цикла.
Думаю, многие заметили, что в цикл я добавил нетипичную для него задержку в 0 милисекунд. В нашем случае без задержки игра вылетит, что конечно не радует. Надеюсь, что этот пример пригодится вашим проектам, где есть смысл хранить данные именно таким способом.
Чтобы не превышать лимиты, не создавайте слишком много сущностей за один раз!
Не используйте этот способ для хранения данных, которые нужно восстанавливать после перезагрузки игры!
В main.scm
этот способ нужно использовать с осторожностью, но там ситуация с переменными более благосклонна к нам.
Кроме актёров, таким вот образом можно записать и другие сущности, а также целые и/или вещественные числа. Также нет привязки к конкретному типу данных: мы можем в разные ячейки записать разные значения. Главное не забыть что и куда было записано :)
На этом, пожалуй, всё. С Вами был wmysterio!
Last updated