| Инвентарь |
|
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. Сами вещи, думаю уже всё ясно. Всем, кто хочет читает код, в коде встречается переменные в неправильном регистре! Настоятельно рекомендую запускать код из примера!
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, тут в примере все как то нудно и не понятно...
Любимые игры: 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) а с двоичными файлами еще не работал(как в с++ В С++ нет такого понятия как записать текстовый файл, там данные есть данные. Поэтому здесь ты лукавишь.  Ты можешь попробовать писать сразу цифры друг за другом они будут записываться ровненьким строем в шестнадцатиричном варианте (бинарном), читать точно также. С ГМом, конечно же придется повозится, т.к. встроенное чтение/запись бинарных файлов относится только к одному байту. Остальные, написанные нами функций, могут работать, но могут и сбоить, т.к. я не уверен что мы соблюли все стандарты (плюс обратная запись байтов). Почему я за бинарные файлы? Причём многим это советую. Приведу аналогию. Предположим у нас есть 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
|
Намеки на то, что мне все переписывать надо  . Ладно, я все понял, только скажу что, в чем разбираешься, в том и проще работать. Спасибо за советы. Вообщем не стал я выдирать инвентарь, я так, весь проект кину. Секция: скрипты->InGame->Inv Самое забавное, что у меня инициализация инвентаря идет через строку и массив, там просто где-то ошибка и я не могу через ф-ю считывать последнюю хар-ку предмета(в данном случае - кол-во). Рисование: скрипты->Tech->Menu->menuDrawInv
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 у архиве тоесть что он делает?
|
| |
| |
|
|