Пятница, 03.05.2024, 14:15


Главная
Регистрация
Вход
Dota Allstars ✪ World of WarCraft Приветствую Вас Гость | RSS  
Меню сайта

Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

Главная » Статьи » Dota Allstars » Полезные статьи

Система Super Custom Value (SCV) или RB+cache
Система Super Custom Value (SCV) или RB+cache                                                   

Система Super Custom Value (SCV) или RB+cache

Читатель, мы вплотную подошли к системе SCV. Эта система, которая позволяет сопоставлять ЛЮБОМУ игровому объекту - либо другой объект, либо какое-то значение (или даже массив). Наподобие custom value, но значительно более универсальная. Значение этой системы трудно переоценить. Фактически, она позволяет упростить решение огромного множества задач, избавиться от глобальных переменных и создавать так называемые кешь-переменные прямо во время игры.
С чего тут начать. Пожалуй, с Кеша. Существует такая замечательная вещь, называемая кешь. Программисты называет такие структуры - ассоциативный массив. Кешь в war3 - это особый двумерный массив, в котором в качестве аргументов используются строки. Т.е. вводишь аргументами 2 строки, им сопоставляется значение. Можно сопоставить значение типа integer, типа real, типа string и типа boolean.
Как жаль, что в этот массив нельзя записать ссылку на юниты, предметы, способности и т.п. Стоп, а действительно ли нельзя? Или все таки можно?
Ссылку может и нельзя, но давай вспоминать, что мы узнали про RB. Каждому игровому объекту соответствует уникальный номер, число типа integer. Это число можно найти, и по этому числу можно найти объект. А ведь число типа integer может быть записано в кешь!
(*) Итак, если мы используем кешь не для переброски данных, а для хранения информации, то в качестве хранимой информации кешь способен записать указатели (номера) объектов.
Это первый важный вывод. А теперь подумаем, если мы в кешь можем сохранять объекты, можем ли мы при помощи кешь сопоставить какому-то игровому объекту какое-то значение? Игровой объект имеет свой уникальный номер. Номер есть число, но специальные функции позволяют перевести его в строку.
(**)Договоримся, если мы хотим сопоставить игровому объекту значение в кешь, то в качестве первого аргумента записи будем использовать уникальный номер этого объекта, переведенный в строку.
(***)Что касается второго аргумента кешь, то мы можем использовать его, чтобы дать нашему сопоставлению уникальное имя.
Сопоставь факты, отмеченные выше, и ты поймешь идею SCV.
Рассмотрим функцию вида:
function set_object_iparam takes handle h, string key, integer val returns nothing
 call StoreInteger(udg_cache, I2S(H2I(h)), key, val)
endfunction
Эта функция предназначена, чтобы сопоставлять любому объекту параметр типа integer. Аргументами выступает ссылка на объект handle h, строка key - имя сопоставления и переменная val типа integer - это число, которое мы сопоставляем объекту.
udg_cache - это переменная типа кешь - специальный кешь-файл создается в самом начале игры.
В функции единственное действие:
call StoreInteger(udg_cache, I2S(H2I(h)), key, val) 
Это обычная команда занести значение в кешь.
Для записи в кешь, нудно передать 2 строки-аргумента. Первая строка:
I2S(H2I(h)) 
Разберемся подробнее. Здесь написана функция внутри функции. H2I(h) - мы уже рассмотрели выше. Она вернет номер для объекта, переданного через переменную h. Вторая функция I2S(...) - это обычная варкрафтовская функция перевода числа в строку. Итак, вся конструкция в целом приведет к тому, что первая строка - это переведенный в текст уникальный номер объекта.
Вторая строка key - это строка, которую заполняет сам пользователь, давая имя сопоставлению. Параметр для записи val.
Итак, если у тебя есть юнит u и ему нужно сопоставить число 10, то можно использовать команду:
call set_object_iparam(u, "int", 10) 
имя сопоставления "int".
Отлично! Как делать запись мы выяснили. А можно ли эту запись прочитать обратно? Да! Во-первых, для удобства создадим вторую функцию:
function get_object_iparam takes handle h, string key returns integer
 return GetStoredInteger(udg_cache, I2S(H2I(h)), key)
endfunction
Она похожа по структуре на предыдущую, только аргументов на один меньше. Это потому, что функция нужна не для записи значения в кешь, а для чтения значения из кеша.
return GetStoredInteger(udg_cache, I2S(H2I(h)), key) 
Т.е. наша функция вернет значение выражения GetStoredInteger(udg_cache, I2S(H2I(h)), key) . А что это за выражение? Стандартная функция для чтения из кеша. В качестве первой строки указывается уникальный номер объекта, переведенный в строку. Вторая строка - определена пользователем.
Итак, если мы хотим узнать, что записано в записи кеша "int" для юнита u, используем команду:
set i = get_object_iparam(u, "int")
Т.е. можно и записывать значения и читать их. Читатель, не замечаешь чего-то общего между нашими сопоставлениями и custom value? По сути, custom value - это тоже сопоставление, но менее универсальное, т.к. можно сопоставлять юнитам (и только юнитам) одно (и только одно) значение типа integer. А при помощи SCV можно сопоставить что угодно и чему угодно. Поэтому я называл эту систему Super Custom Value (SCV) , а сопоставления-записи - для краткости cv.
А как сопоставить юниту u - другой юнит u2? Очень просто.
call set_object_iparam(u, "int", H2I(u2)) 
Мы записали в параметр "int" уникальный номер u2.
Этот номер мы можем прочесть обратно. Проблема лишь в том, как при помощи этого номера получить ссылку обратно на u2. Для этого в SCV есть специальные функции.
function I2U takes integer i returns unit
return i
return null
endfunction
и
function get_object_uparam takes handle h, string key returns unit
 return I2U(GetStoredInteger(udg_cache, I2S(H2I(h)), key))
endfunction
Первая функция по уникальному номеру возвращает сам юнит, вторая сделана для простоты - она читает уникальный номер из записи в кеше и при помощи первой функции возвращает ссылку на этот юнит.
Так что, если нужно прочесть какой юнит записан в cv "int" для юнита u, используем команду
set u2 = get_object_uparam(u, "int")
Вот и все. Остальное все по аналогии. Есть и другие функции для сопоставления чисел real, строк, флагов boolean. Есть функции для нахождения не только юнитов по их номеру, но и других объектов - точек, регионов, спецэффектов и др.
Есть правда еще одна функция
function flush_object takes handle h returns nothing
 call FlushStoredMission(udg_cache, I2S(H2I(h)))
endfunction
  • она позволяет быстро отчистить все записи кеша, относящиеся к какому-то объекту.
Скажем, собираешься ты удалить юнит u. Для того, чтобы cv этого объекта не занимали место в памяти, когда объекта уже нет, пишешь команду:
call flush_object(u) 
Все эти функции в сумме вмещаются на 1-1.5 экрана. Переносить систему из сценария в сценарий - элементарно. Просто копируем код, создаем переменную cache и при событии Map Initizlization создаем кешь-файл.
Читатель, попробуй представить себе все возможные способы применения SCV. Вспомни примеры, которые мы рассмотрели ранее. Может быть есть способ что-то сделать проще, быстрее и надежнее ? ;)
Когда ДимонТ выпустил систему, я разработал по ней небольшой обучающий сценарий, который демонстрирует ее возможности, в том числе создание переменных и массивов cv. Я хочу, чтобы ты подробно изучил этот сценарий.
Освоив SCV ты поднимешься на следующую ступень мастерства.

 Да здравствует SCV!

Рассмотрим один из наших старых примеров – полет юнита снаряда. Можно ли улучшить его при помощи SCV? Раньше нам приходилось использовать массивы, чтобы сохранить информацию, что такой-то юнит-снаряд летит к такой-то цели и имеет такой-то уровень заклинания. Теперь мы можем сопоставить эти данные непосредственно юниту-снаряду при помощи SCV. Т.е. записать все необходимые данные в cv. А как нам сделать периодический цикл по всем юнитам снарядам, чтобы сдвигать их? О, тут у нас появляются новые интересные возможности. Мы можем для каждого юнита-снаряда создать отдельный триггер с периодом 0.05, отвечающий за его передвижения к цели.
Ну допустим, мы создали триггер с событием Периодическое 0.05. А как прописать, что этот триггер должен работать только для определенного юнита-снаряда? Очень просто, мы сопоставим триггеру (триггер ведь тоже игровой объект!) нужный нам юнит-снаряд. И при запуске триггера сможем определить, что нужно двигать такой-то юнит-снаряд.
В целом система организации движения юнита-снаряда становится довольно простой. На основе этого принципа я сделал несколько геройских заклинаний - предлагаю тебе ознакомиться с ними. К примеру, герой Лорд Хаоса. Заклинания Звездный конус, Групповой файербол и Сфера Хаоса сделаны таким способом. Это открывает широчайшие возможности по созданию триггерных заклинаний любой сложности.

Кстати, огромное достоинство системы SCV, что ее можно легко дополнить. Допустим, нам нужно чтобы объектам можно было сопоставлять триггеры и таймеры. К функциям SCV добавим новые:
function I2Tm takes integer i returns timer
 return i
 return null
endfunction

function I2Tr takes integer i returns trigger
 return i
 return null
endfunction
и еще две
function get_object_tmparam takes handle h, string key returns timer
 return I2Tm(GetStoredInteger(udg_cache, I2S(H2I(h)), key))
endfunction

function get_object_trparam takes handle h, string key returns trigger
 return I2Tr(GetStoredInteger(udg_cache, I2S(H2I(h)), key))
endfunction
Вот и все.

Категория: Полезные статьи | Добавил: TRACTOR (12.04.2012)
Просмотров: 548 | Рейтинг: 0.0/0
Вход на сайт

Поиск

Copyright MyCorp © 2024Сделать бесплатный сайт с uCoz