Инвентарь - Форум Game Maker. Разработка игр.
Здравствуй Гость | Перейти на сайт

Главная | Форум | Регистрация | Войти
gmaker.net ;) [ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
Страница 1 из 11
Форум Game Maker. Разработка игр. » Разработка игр на Game Maker (Simple Mode) » Примеры, статьи » Инвентарь (Статья + пример.)
Инвентарь
Dragon33 Дата: Воскресенье, 22.02.2009, 19:45 | Сообщение # 1
Хрен заткнешь
Группа: Проверенные
Сообщений: 289
Статус: Offline
Итак, я надеюсь, что данная статья поможет вам создать свой инвентарь, или просто поможет понять как его можно создать. Так же хочу подчеркнуть, что данная статья рассчитана на более-менее понимающих в программирование на Game Maker (или просто программировании), а так же она не поможет тупо вставить код из статьи и получить готовый инвентарь, многое вы должны будете делать сами. А готовый пример инвентаря прикреплен ниже (естественно написан мною).

1. Для начала разберемся, знаем ли мы что такое массив, если знаем, то нам к следующему пункту, если – нет, то рекомендую к прочтению:
Массив – это определенное количество элементов (имеющих свой идентификатор) одного типа. Под «типами» в программном смысле подразумевается вещественный, логический, строковый типы и другие, т.е. допустим, массивом являются все целые числа. Другим же примером может служить алфавит – все элементы – символы. А если брать примеры из реальной жизни : стопка книг – каждый элемент стопки является книгой, класс учеников – элементы массива – ученики и так далее.
Подозреваю, что вы уже поняли, что такое массив. Далее рассмотрим двумерный массив – это массив, имеющий главный элемент и «дополнительный» элемент. Примерами двумерного массива могут служить: любая таблица (допустим главный элемент – столбцы, а дополнительный – строки), матрица. В принципе – это основные примеры.
Как же объявить массив? Одномерный массив объявляется как array[i] = …, где ‘array’ – имя массива, а ‘I’ – идентификатор элемента (число). Соответственно двумерный: array[I,k], где ‘k’ – дополнительный элемент массива (тоже число).

2. Итак, в каком же случае можно использовать двумерный массив при создании инвентаря? Например, это могут быть ячейки инвентаря (ведь это тоже самое, что и таблица), хотя тут можно использовать и одномерный массив, но поверьте, двумерный удобнее. Далее это может быть База Данных наших вещей. Всё это мы рассмотрим далее. А сейчас себя спросим : знаем ли мы как работать с циклами? Если нет, то идем читать справку по Game Maker.

3. А теперь будем программировать. Итак, инвентарь, мы имеем определенное количество ячеек в нем. Пораскинув мозгами, нужно понять, что ячейки должны иметь информацию о содержащихся в них предметах или просто пустую информацию (т.е. предмета в ячейке нет). Смело пишем в событии создания инвентаря :

Code
for(i=0;i<cell_count;i+=1)
{
  Cell[I,0] = ‘’
}

Рассмотрим вышеописанный код. Имеем цикл, cell_count – количество ячеек в инвентаре, cell[I,0] = ‘’ – задаем каждой ячейке пустую строку.
ПРИМЕЧАНИЕ : в дальнейшем cell[I,0] будем использовать под имя предмета.
Но предмет-то имеет не только имя, но и множество другой информации, например:
Спрайт, урон, броня, описание, тип, требования, максимальное количество и так далее. Т.е. пишем в цикл всё это :
Code
for(i=0;i<cell_count;i+=1)
{
  cell[I,0] = ‘’ // Имя
  Cell[I,1] = noone // Спрайт
  Cell[I,2] = 0 // урон
  // И так далее
}

4. Уже что-то ясно? Да? Отлично. Разберем рисование.

Code
Var n; n = 0;
For(i=0;i<cell_count/cells_on_line;i+=1)
  For(k=0;k<cells_on_line;i+=1)
  {
   draw_sprite(s_cell,-1,x+33*k,y+33*i)
   n+=1;
  }

С помощью ‘n’ мы будем определять номер массива прямо в цикле (естественно я тут всё не распишу, поэтому всё это можно в примере увидеть). С помощью двойного цикла мы можем рисовать инвентарь как таблицу, а с помощью ‘n’ – определять номер. Cells_on_line – количество ячеек в линию (строку), задается в событии создания.
Так же хочу напомнить про открытие и закрытие инвентаря, не забудьте про это (если инвентарь закрыт, то не рисуем (ставим перед циклом условие)).
Ну а далее всякие тонкости рисования сами разберете.


The Sinner: Rebirth
 
Dragon33 Дата: Воскресенье, 22.02.2009, 19:45 | Сообщение # 2
Хрен заткнешь
Группа: Проверенные
Сообщений: 289
Статус: Offline
5. Теперь будем рассматривать различные составляющие инвентаря.
5.1. Drag&Drop, что дословно значит «Перетащить и Выкинуть», т.е. здесь рассмотрим поднятие, замену, выкидывание предмета обратно в инвентарь.
Что бы поднять предмет мы должны «взглянуть» на него, в смысле мышку на него навести. Значит, делаем условие сразу в том же рисовании, внутри тех двух циклов:
Code
If (mouse_x>x+33*k)&&(mouse_x<x+32+33*k)&&(mouse_y>y+33*i)&&(mouse_y<y+32+33*i)

Теперь определяем нажатие ЛКМ:
Code
if mouse_check_button_pressed(mb_left)

Ну и последнее условие:
Code
if (drag = 0)&&(can_alarm = 1)

Здесь надо пояснить: drag = 0 – значит что мы не перетаскиваем предмет, а can_alarm = 1 – значит что можем запустить аларм (таймер). И далее пишем что, предмет успешно поднят, освобождаем ячейку, запихиваем поднятый предмет (т.е. всю информацию о нём) во временной (дополнительный) массив (мой называется temp_item):
Code
for (j=0;j<32;j+=1)
temp_item[j] = cell[n,j]
cell[n,0] = ''
alarm[0] = 1

Итак, для чего нужен аларм? А в аларме мы пишем:
Code
drag = !drag
can_alarm = 1

Так почему же это нельзя написать в событии поднятия? Ну вот напишете выкидывание предмета в инвентарь без аларма и получится что предмет не будет «выкидываться». Я думаю, сами поймете почему.
Осталась замена:
И тут тоже всё предельно просто. Заводим еще один массив (мой назван temp_temp_item), делаем условия и при нажатии ЛКМ производим следующие события:
В temp_temp_item кидаем инфу о cell[I,k] -> в cell[I,k] помещаем инфу от temp_item -> и наконец, всё из temp_temp_item кидаем в temp_item.
Ну и напоследок не забываем рисовать предмет, который перетаскиваем (if drag=1 …).

5.2. Добавление предмета в инвентарь.
В моём примере это функция, названая add_item. Имеет два аргумента: имя предмета и его количество. Т.е. с помощью этой функции я ввожу имя предмета и его количество и получаю данный предмет в данном количестве в инвентарь. Вы, конечно, можете по-другому сделать, но всё же основываться буду на свою функцию.
Значит, имея при себе имя предмета и количество, нам надо добавить его в инвентарь. В моей базе данных предметов у каждого предмета свой идентификатор (не только имя), а точнее его первый элемент массива (более подробнее см. в Items_Help). Итак, определим же этот идентификатор:

Code
var item_id;   
for (e=0;e<255;e+=1)
      if item_to_add = inv.item[e,0]   
      {
          item_id = e
          break
      }

E<255 – максимальное кол-во предметов в моей БД (это для начала).
И поскольку у вас уже отложился опыт с пункта 4 и пункта 5.1, то думаю, справитесь сами, а я просто немного уточню:
Для начала необходимо определить: если ли добавляемый предмет в инвентаре и что бы количество не равнялось максимальному количеству. Да? То добавляем второй аргумент функции к текущему количеству (так же можно проверку на максимальное количество сделать, см. пример). Нет? Создаем новый.

5.3. Одевание предметов.
Создаем массив схожий с массивом cell, только на один аргумент больше. Массив я назвал equip_cell, а новый аргумент содержит информацию о типе ячейки, т.е. какой на неё предмет можно одеть (меч, щит, шлем, ботинки…).
Итак, идем в рисовании к нашим двум циклам. Ищем наведение условия для наведения мышки на объект. Ну а дальше уже должно быть понятно: проверка на ПКМ, проверка на занятость слота и далее как и с Drag&Drop’ом: если занято, то помещаем во временной массив, нет – equip_cell[l]=cell[n].
Насчет двуручного оружия и щита... Пусть это будет вашим домашним заданием =).
А так, успехов в создании своего инвентаря.
Если ничего самостоятельно не получается, то мой пример вам в помощь.

Про архив:

Quote
Итак, архив содержит 4 файла :
1. colors_rgb.gm6
2. inv_v1,03.gm6
3. item_creator.gm6
4. items.ini

1. С помощью данного примера можно использовать больше цветов (всего их 35). Поскольку эти скрипты используются в инвентаре, то я решил добавить их в отдельный исходник (размер не так страшен, поэтому можно и скачать =)), список цветов написан в ф-ии draw_color(Color) .

2. Соотвественно сам инвентарь. Основные роли того или иного кода с комментариями, поэтому не страшно что-либо изменить (например окошки). А теперь более подробно :
- есть ф-ия Drag&Drop, т.е. перетаскивания и замена предметов в рамках инвентаря (к сожалению пока еще не сделал для одевания предметов), важную роль играет Левая Кнопка Мыши;
- одевание предметов - Правая Кнопка Мыши;
- ф-ия add_item('Item_name',Item_count);
- ф-ию drop_item() пока еще не сделал, возможно потом...
- items() - список предметов, копируем из items.ini (не забываем удалять секции);
- items_help() - шпаргалка по предметам .

3. Редактор вещей(громко сказано, но всё же...):
- Space Pressed - добавить вещь
- Delete Pressed - удалить вещь из Базы Данных
- за характеристиками предметов обращаться в items_help (см. выше).

4. Сами вещи, думаю уже всё ясно.

Всем, кто хочет читает код, в коде встречается переменные в неправильном регистре! Настоятельно рекомендую запускать код из примера!
Прикрепления: inv_v103.rar(21Kb)


The Sinner: Rebirth
 
SRes Дата: Понедельник, 23.02.2009, 08:20 | Сообщение # 3
Каждый 5й пост мой
Группа: Страж
Сообщений: 2526
Статус: Offline
Прочитал все до 5.1 (включительно), неплохо. Для начинающего вполне поможет.
P.S.
Quote
If (mouse_x>x+33*k)&&(mouse_x<x+32+33*k)&&(mouse_y>y+33*i)&&(mouse_y<y+32+33*i)

Quote
выбранный елемент инвентаря = (mouse_x - начало Х инвентаря) div 32


Velociped Inc.
 
luxorix Дата: Понедельник, 23.02.2009, 17:01 | Сообщение # 4
Хрен заткнешь
Группа: Проверенные
Сообщений: 255
Статус: Offline
Ни черта не понял, но вроде бы написано доходчиво, думаю если сидеть и делать, то все по полкам разложится.
 
OPALsmoke Дата: Четверг, 26.02.2009, 13:15 | Сообщение # 5
Хрен заткнешь
Группа: Проверенные
Сообщений: 365
Статус: Offline
Dragon33 +1 за стараиния. Но блин...Полностью солидарен с мнением luxorix, тут в примере все как то нудно и не понятно... wacko


Любимые игры: Hogs of war, Flashpoint, UFO enemy unknown (X-COM), Jagged alliance 2, ice climber(nes), Doom 1-2, Heretic, Hexen, Quake 1 - 3, clive barker's undying, Heavy Metal: F.A.K.K.², Soldiers of fortune, Ва-банк!(the sting!), Gothic 1, Serious sam первая кровь, Петька и василий иванович спасают галактику, Казаки: снова война, mount & blade, Рогалики
 
baho Дата: Четверг, 23.04.2009, 10:35 | Сообщение # 6
Молчун
Группа: Пользователь
Сообщений: 18
Статус: Offline
до пункта 5 всё доходчива спасиба

а дальше мне кажется станет яснее если поковырять

 
Dragon33 Дата: Пятница, 24.06.2011, 16:32 | Сообщение # 7
Хрен заткнешь
Группа: Проверенные
Сообщений: 289
Статус: Offline
В своей игре тут наковырял новый инвентарь, немного по-другому сделал. Если кому интересно:
Через редактор я делаю вещи, они сохраняются в виде строки
Code
item_name|item_sprite|item_damage...

и потом зашифровываются.
Далее в игре читается строка, расшифровывается и такой передается в ячейку инвентаря.
Т.е. инвентарь у нас состоит из одномерного массива(был еще вариант с динамическим листом, но они медленние и неудобно обращаться к значениям):
Code
invItem[i] = "длинная, длинная строка";


Значения считываю через функцию:
Code
inv_valueGet ( string string, int position > 0 );

Позицию нужного нам элемента определить легко, если ты заранее указал все позиции в константах:
Code
ITEM_NAME = 1;
ITEM_SPRITE = 2;
...

А дальше логическое программирование.


The Sinner: Rebirth
 
Ang3L Дата: Пятница, 24.06.2011, 18:00 | Сообщение # 8
Каждый 5й пост мой
Группа: Админы
Сообщений: 2741
Статус: Offline
Постоянный парсинг строк не самое лучшее занятие для процессора во время игры. В двоичном виде сохранил (они уже будут непонятны 99% пользователей, при этом гораздо быстрее в производительности), эти же данные загрузил и распихал по двумерному массиву (на самом деле он одномерный, но выводить можно как одномерный, так и двумерный).

P.S.: Вообще, в играх нужно использовать только цифры, если какое-то описание или повествование, тогда да - текст. А так, только лишняя работа на проц. и код программы.


Blogpost
 
Dragon33 Дата: Пятница, 24.06.2011, 18:40 | Сообщение # 9
Хрен заткнешь
Группа: Проверенные
Сообщений: 289
Статус: Offline
Ang3L, не, там не постоянно парсит. Я использую поверхности для отображения хар-ок предметов(да и вообще для всего интерфейса), т.е. парсинг идет только когда открываем инвентарь, не думаю что это сильно нагружает.
Можно конечно протестировать, создать 100 предметов и посмотреть на какое время подвиснет.
з.ы. а с двоичными файлами еще не работал(как в с++(редактор), так и в gml).


The Sinner: Rebirth
 
Ang3L Дата: Пятница, 24.06.2011, 19:19 | Сообщение # 10
Каждый 5й пост мой
Группа: Админы
Сообщений: 2741
Статус: Offline
Quote (Dragon33)
т.е. парсинг идет только когда открываем инвентарь

Хорошо, тогда такой вариант. А почему ты не делаешь парсинг всего 1 раз при загрузке игры? Тогда не надо было делать каждый раз при открытий инвентаря. Была строка, парсируем в "клеточки" массива, работаем с ними, выходим из игры, парсируем из клеточек обратно в строку. Получается парсинг работает только при входе и при выходе из игры. Считай, экономия на пустом месте. Конечно, в строке (как в структуре) есть свои плюсы, допустим скопировать предмет или перенести его в другую клетку будет гораздо проще. Тут уж надо взвесить все плюсы и минусы.

Quote (Dragon33)
а с двоичными файлами еще не работал(как в с++

В С++ нет такого понятия как записать текстовый файл, там данные есть данные. Поэтому здесь ты лукавишь. wink Ты можешь попробовать писать сразу цифры друг за другом они будут записываться ровненьким строем в шестнадцатиричном варианте (бинарном), читать точно также. С ГМом, конечно же придется повозится, т.к. встроенное чтение/запись бинарных файлов относится только к одному байту. Остальные, написанные нами функций, могут работать, но могут и сбоить, т.к. я не уверен что мы соблюли все стандарты (плюс обратная запись байтов).

Почему я за бинарные файлы? Причём многим это советую. Приведу аналогию. Предположим у нас есть 2 человека разговаривающих на китайском, и нам нужно перенести данные от одного к другому. И вместо того чтобы передать данные напрямую, многие начинающие делают так:
1) берут у первого китайца данные,
2) переводят с китайского на русский
3) эти данные подносят ко второму китайцу
4) переводят с русского на китайски
5) дают второму китайцу его родные записи

Наш пример:
1) берем бинарные данные у редактора
2) переводим их в текст
3) кладем в файл
4) загружаем из файла, переводим из текста в бинарные
5) передаем игре

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

P.S.: Dragon33, если необходимо, ты можешь обновить исходничек для текущего поколения.


Blogpost
 
Dragon33 Дата: Пятница, 24.06.2011, 20:07 | Сообщение # 11
Хрен заткнешь
Группа: Проверенные
Сообщений: 289
Статус: Offline
Quote (Ang3L)
Хорошо, тогда такой вариант. А почему ты не делаешь парсинг всего 1 раз при загрузке игры? Тогда не надо было делать каждый раз при открытий инвентаря. Была строка, парсируем в "клеточки" массива, работаем с ними, выходим из игры, парсируем из клеточек обратно в строку. Получается парсинг работает только при входе и при выходе из игры. Считай, экономия на пустом месте. Конечно, в строке (как в структуре) есть свои плюсы, допустим скопировать предмет или перенести его в другую клетку будет гораздо проще. Тут уж надо взвесить все плюсы и минусы.

Вот тут и правильно сказал, со строкой проще работать, если допустим взять инициализация инвентаря. И да, вопрос в оперативной памяти очевиден: в случае со строкой - инициализируем 100 пустых строк, в случае с разными типами - я делаю двойной массив(как в первом примере). Как мимним начальная потребляемая память в пользу строк.
Теперь насчет начальной загрузки. Для этого надо будет(как ты и сказал) делать двойные массивы для хранения - лишние потребление памяти, я же строки уже делаю, в противном случае мен надо будет вернуться в первый пост. Вопрос вот только что выгоднее использовать - лишний раз проц нагреть или память.
А так у меня что-то типа того: draw_text(x, y, inv_valueGet(..))

Quote (Ang3L)
В С++ нет такого понятия как записать текстовый файл, там данные есть данные. Поэтому здесь ты лукавишь. wink Ты можешь попробовать писать сразу цифры друг за другом они будут записываться ровненьким строем в шестнадцатиричном варианте (бинарном), читать точно также.

А как же классы StreamWriter и fstream, там же можно писать строки, лайны, числа. Или я чего-то не понимаю?)

Quote (Ang3L)
Наш пример:
1) берем бинарные данные у редактора
2) переводим их в текст
3) кладем в файл
4) загружаем из файла, переводим из текста в бинарные
5) передаем игре

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

Тут что не понятно. Наверно наоборот.
Quote (Ang3L)
P.S.: Dragon33, если необходимо, ты можешь обновить исходничек для текущего поколения.

Это потом вырежу, если все-таки это будет хороший пример.


The Sinner: Rebirth
 
Ang3L Дата: Пятница, 24.06.2011, 21:03 | Сообщение # 12
Каждый 5й пост мой
Группа: Админы
Сообщений: 2741
Статус: Offline
Quote (Dragon33)
Вот тут и правильно сказал, со строкой проще работать, если допустим взять инициализация инвентаря. И да, вопрос в оперативной памяти очевиден: в случае со строкой - инициализируем 100 пустых строк, в случае с разными типами - я делаю двойной массив(как в первом примере). Как мимним начальная потребляемая память в пользу строк.
...
Вопрос вот только что выгоднее использовать - лишний раз проц нагреть или память.

Ага! Мы пришли всё к той же палке оптимизаций: память <-> производительность. Что-то больше жрёт того, но меньше второго, либо наоборот. Вечный вопрос и всегда актуальный!

Quote (Dragon33)
Наверно наоборот.

Это неважно. Важно только направление, которое уже выбирает сам пользователь. Т.е. не важно из редактора в игру или наоборот, последовательность действий будет одинакова (единственная разница, как потом эти данные будут использованы).

Quote (Dragon33)
там же можно писать строки, лайны, числа. Или я чего-то не понимаю?)

Для нас (для людей) они выглядят по разному, а для машины они выглядят как последовательность единиц и нулей (жёстких носителях выемки, принципиально других технологий нет, либо они совсем не массовые). Любая сложная структура состоит из базовых типов, поэтому их можно скинуть в файл как последовательность базовых типов. В свою очередь, базовые типы скидываются в файл как единицы и нули (ну бинарный тип, что понимает комп. и HDD, конечно). Если в шестнадцатиричной системе эти данные лежат от 30 до 39 (эквивалент в десятичной от 48 до 57) то мы видим их как числа, а чуть дальше пойдут буквы. Просто люди в какой-то момент договорились, что вот такие-то числа будут отображать такие-то данные и всё это назвали таблицей ASCII (одна из). Поэтому никаких текстовых файлов не бывает, там просто подобраны шестнадцатиричные данные так, что в таблице ASCII они соответствуют буквам для отображения и нам виден текст, хотя в файле все те же цифры от 0 до 255 (байты). Это в ГМ сделали такое разграничение, чтобы было проще школьникам (и мне кажется, многих это вводит в заблуждение, а потом ещё в индусский код не даёт покоя нашим пионэрам).

Видел такие перлы в С++. Func() - что-то делает и возвращает строку, а код примерно след.:
Code
string result;

result = Func();

if(result == 'TRUE')
     действие1;
if(result == 'FALSE')
     действие2;

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

Другой вопрос, тебе записывать в бинарнике или в текстовом варианте? Я бы предпочел всё же именно бинарник ещё по той причине, потому что ты сделал редактор. Т.е. у тебя есть инструмент которым ты можешь работать (смотреть и редактировать файл) и нет необходимости использовать блокнот для редактирования. А раз нет необходимости ни редактировать, ни просматривать файл блокнотом, то сразу бинарничек (и он у тебя как бы будет автоматически зашифрован).

Quote (Dragon33)
Это потом вырежу, если все-таки это будет хороший пример.

Ок.


Blogpost
 
Dragon33 Дата: Пятница, 24.06.2011, 21:10 | Сообщение # 13
Хрен заткнешь
Группа: Проверенные
Сообщений: 289
Статус: Offline
Намеки на то, что мне все переписывать надо happy .
Ладно, я все понял, только скажу что, в чем разбираешься, в том и проще работать.
Спасибо за советы.

Вообщем не стал я выдирать инвентарь, я так, весь проект кину.
Секция: скрипты->InGame->Inv
Самое забавное, что у меня инициализация инвентаря идет через строку и массив, там просто где-то ошибка и я не могу через ф-ю считывать последнюю хар-ку предмета(в данном случае - кол-во).
Рисование: скрипты->Tech->Menu->menuDrawInv
Прикрепления: -GM-The_Sinner.rar(373Kb)


The Sinner: Rebirth

Сообщение отредактировал Dragon33 - Пятница, 24.06.2011, 21:17
 
Ang3L Дата: Пятница, 24.06.2011, 22:15 | Сообщение # 14
Каждый 5й пост мой
Группа: Админы
Сообщений: 2741
Статус: Offline
Quote (Dragon33)
Намеки на то, что мне все переписывать надо .

Не-не-не, я не к тому. Все так считают почему-то... Я ж не пишу тебе: "Стирай всё и делай как я - это догма!" Просто выражаю некий опыт с которым знаком, ты же можешь его рассмотреть, и принять либо нет на вооружение. Чисто ещё одна точка зрения и всего.


Blogpost
 
Pro100off_1g3y Дата: Понедельник, 28.11.2011, 05:37 | Сообщение # 15
Молчун
Группа: Заблокированные
Сообщений: 19
Статус: Offline
Можна вопрос /что за файл ILF у архиве
тоесть что он делает?
 
Форум Game Maker. Разработка игр. » Разработка игр на Game Maker (Simple Mode) » Примеры, статьи » Инвентарь (Статья + пример.)
Страница 1 из 11
Поиск:



Сообщество Gmaker.SU 2005-2012
Используются технологии uCoz
Простой вход