Разработчикам игр на Atril, часть 5: Пример - инвентарь
Пт Июн 06, 2014 15:25
- Доступные действия:
Jumangee
Во всех бочках затычка
Разработчикам игр на Atril
Часть 5: Пример – инвентарь
Актуально для: Atril 2.1
По просьбам трудящихся рассмотрим на примерах работу с движком, "инвентарь" это часто используемый элемент в играх и сложности в нём нет. Но для понимания работы скриптов необходимо знать теорию массивов в javascript.
- Ассоциативный массив (хеш), где данные хранятся по произвольному ключу.
- Числовой массив Array, где данные хранятся по номерам.
Javascript – очень гибкий язык, поэтому технически в Array можно хранить произвольные ключи, как в Object. Но лучше использовать типы по назначению.
Для хранения данных по номеру предназначен тип Array. var arr = new Array()
2 arr.test = 5
3 arr[1] = "blabla"
4 ...
В типе Array есть специальные методы, ориентированные именно на работу с числовыми ключами.
Создание и изменение
Есть два эквивалентных способа создания массива:var a = new Array()
var a = [ ]
Или, сразу со значениямиvar a = new Array("a", 1, true)
var a = ["a", 1, true]
Эти способы работают одинаково, кроме объявления вида new Array(10), когда у конструктора есть единственный аргумент-число.
Такое объявление создаст пустой массив (все элементы undefined) длиной 10. По возможности, не используйте new Array.
Отсчет элементов начинается с нуля:alert(a[ 0 ]) // => "a"
Массив хранит данные по численным ключам, но внутри он использует точно такой же хэш (ту же структуру данных), как и обычный объект, поэтому можно сделать так:var a = [ ]
a[ 1 ] = 1
a[ 999999 ] = 2
и массив a будет занимать память, нужную для хранения этих двух соответствий, а не займет длинный непрерывный кусок памяти, как это произошло бы в языке С.
Авто-длина length
У каждого массива есть свойство length, которое автоматом меняется при каждом обновлении массива. Длина массива – это не количество элементов, а максимальный целый ключ + 1:alert(a.length) // всего 2 элемента, но выведет 1000000
Добавлять новый элемент можно эквивалентными вызовамиa[a.length] = "new element"
a.push("new element")
Перебор элементов
Перебор элементов обычно (когда индексы непрерывные) осуществляется простым циклом:1 var arr = [ "array", "elements", "here" ]
2 for(var i=0; i<arr.length; i++) {
3 ... сделать что-то с arr[i] ...
4 }
Если индексы – с разрывами, то перебор осуществляется так же, как в объектах:1 var arr = []
2 arr[ 1 ] = 123
3 arr[ 9999 ] = 456
4
5 for(var i in arr) {
6 if (!arr.hasOwnProperty(i)) continue;
7 ... сделать что-то с arr[ i ] ...
8 }
Очередь + стек
В массиве есть всё необходимое, чтобы работать с ним как с очередью или со стеком, или и с тем и другим одновременно.
Методы push и pop добавляют или вынимают значение с конца массива1 var arr = [3,5,7]
2 arr.push( 9 )
3 var last = arr.pop() //= 9
4 var last = arr.pop() // = 7
5 alert(arr.length) // = 2
Методы shift/unshift делают то же самое, с начала массива.1 var arr = [4,6,8]
2 arr.unshift(2) // arr = [2,4,6,8]
3 arr.unshift(0) // arr = [0,2,4,6,8]
4 var last = arr.shift() // last = 0, arr = [2,4,6,8]
5 arr.shift() // arr = [4,6,8]
shift/unshift обычно приводят к перенумерации всего массива. shift сдвигает все элементы на единицу влево, а unshift – вправо. Поэтому на больших массивах эти методы работают медленнее, чем push/pop.
Другие методы
slice
slice(begin[, end])
Возвращает подмассив с индексами begin…end.
splice
splice(index, deleteCount[, element1,…, elementN])
Удалить deleteCount элементов, начиная с index, и вставить на их место element1…elementN
Есть и еще много методов:
join
reverse
...
Пт Июн 06, 2014 15:26
- Доступные действия:
Jumangee
Во всех бочках затычка
Вариант реализации инвентаря в Atril могут отличаться в зависимости от книги-игры, потому что в книгах-играх нюансы механики могут повлиять на неё. Например, в инвентаре могут находиться вещи "в количестве штук", а могут просто находиться или нет. Во втором случае, довольно элементарно добавлять и проверять наличие вещей просто используя функционал хэш-массивов javascript.
В этом случае мы активно используем тот факт, что в случае, когда значение элемента массива по указанному ключу не задано, оно равно undefined.
Например (параграф simpleInventory в коде примера):onload:
vars.inventory = {};
addItem: // добавлям предмет
var name = args.name; // получаем название проверяемого предмета
... // проверка адекватности значения (см. в редакторе)
vars.inventory[ name ] = true; // пишем в хэш-массив наличие
checkItem: // проверяет наличие предмета в инвентаре
var name = args.name; // получаем название проверяемого предмета
... // проверка адекватности значения (см. в редакторе)
return (vars.inventory[ name ] == true); // если в хэш-массиве указано наличие, возвращаем true
removeItem: //удаляем предмет
var name = args.name; // получаем название проверяемого предмета
... // проверка адекватности значения (см. в редакторе)
delete vars.inventory[ name ];
Несмотря на простоту данная реализация обладает базовой гибкостью и может быть преобразована в более сложные.
Например, при добавлении предмета можно присваивать не true, а количество предметов:
vars.inventory[ name ] = 1;
Принципиальное изменение тут только в проверках на типы, ведь для добавления/удаления предметов надо помнить про изначальное значение undefined:
addItem:
if (vars.inventory[ name ] == undefined){
vars.inventory[ name ] = 1;
return;
}
vars.inventory[ name ]++; // добавляем
removeItem:
if (vars.inventory[ name ] > 0){ // значение undefined не сработает
vars.inventory[ name ]—; // удаляем
}
checkItem:
return (vars.inventory[ name ] > 0);
В примерах выше name может принимать любое значение. Можно передавать название предмета на русском языке, т.е. при получении списка инвентаря использовать название для отображения:
getItemList:
var list = []; // результирующий список предметов инвентаря
for (var name in vars.inventory){ // пробегаем по массиву
if (!vars.inventory.hasOwnProperty(name)){ continue; } // отбрасываем "технологические" свойства
if (vars.inventory[name] > 0) { // если в инвентаре предметы есть, добавляем в список
list.push(name);
}
return name;
}
Но всегда помнить и использовать в параграфах книги-игры полное правильное название предмета (включая регистр!) проблематично и чревато ошибками, приводящими к наличию в инвентаре одного предмета с разными названиями, или попытку проверить наличие предмета по другому имени.
Чтобы избежать этого, можно использовать предопределённый массив названий:onload:
vars.inventory = {};
vars.itemNames = {
'MAIN KEY': 'Ключ от главной двери',
'BLUE KEY': 'Синий ключ от запасного выхода',
'KEY': 'Какой-то ключ'
}
Теперь, при всех операциях с инвентарем используем ключи, а при получении списка, делаем преобразование:getItemList:
...
if (vars.inventory[ name ] > 0){
list.push(vars.itemNames[ vars.inventory[ name ] ]);
}
...
Разделы форума
-
Книго-игровые марафоны
- Битва в Замке Миража
- День приключенца
- Одолей Титана
- На Змеином острове
- Власть страха
- Монстр наносит ответный удар
- Теневой демон
- Стеклянные небеса
- Фон
- Зеркало Парфины: Повергнуть демона храма
- Королевская битва
- Киберпанк: Тени Найт-Сити
- Время решений
- Падшие ангелы
- Зиккурат Ленина
- Зловещие тропы Алмана
- Рандеву
- Корона королей
- Герои
- Небо над Бангкоком
- Каслевания: Битва в старом замке
- Рыцарь живых мертвецов
- Кольца злобы
- Око Сфинкса
- Мадам Гильотина
- Турнир юнлингов
- Политический отбор
- Хачиманский марафон
- Преддверие
- Идущие на смех
- Убийство в клубе Диоген
- Марафон безумного переводчика
- Рок-марафон
- Болотная лихорадка
- Проклятие замка «Пяти башен»
- Подземелья замка кошмаров
- Джунгарское нашествие
- Марафон
- МАКИМ
- МАКИМ
- Книго-игровой марафон 2014
- МАКИМ
-
Конкурсы
-
Обсуждение форумных РПГ
-
Большой Адронный Коллайдер
-
Утилиты для помощи ДМам
-
Безвременье
-
События и мероприятия
-
Книгровой клуб "Мы Текстовые!"