Объясните пожалуйста, как делают игры, на подобии ферм, как Stardew valley. Не конкретные особенности этой игры, а именно расположение объектов на области и их дальнейшее сохранение на локации. Как это делается ? Объектов может быть примерно 1394, и возможность ставить их почти на любой локации. Ну не будем же мы пихать все эти объекты в каждую локацию, верно ? Что нужно знать, чтобы вызывать любой объект в любую локацию и сохранять его местоположение ?
Сейчас тычусь носом в массивы, но после того, как узнал вкратце возможности, додумать не получается. Может все возможные объекты в игре занимают своё место в ячейках массива по координатам X ?
>>721754 (OP) >Ну не будем же мы пихать все эти объекты в каждую локацию, верно ? Что нужно знать, чтобы вызывать любой объект в любую локацию и сохранять его местоположение ? Что ещё за «пихать» и «вызывать»? Если ты изучил массивы, тебе уже должен быть понятен общий принцип. Игровая карта в типичной ферме представляет собой большой двумерный массив, то есть массив массивов. К такому массиву можно легко обращаться способом myArray[x][y], где x и y — координаты нужной ячейки. Если тебе в какую-то ячейку надо поместить объект, просто пишешь что-то вроде myArray[x][y] = “тыква”, а функция отрисовки потом обходит этот массив циклом и рисует тыкву, где надо. Естественно, что я привёл упрощённый пример. В реальности содержимое каждой клетки описывается как минимум ещё одним массивом (а зачастую и словарём), т.к. в ней надо хранить не только тыкву, но и тип земли, например. А возможно, для ландшафта существует просто отдельный двумерный массив. Это целиком зависит от разработчика.
>>721754 (OP) > Что нужно знать, чтобы вызывать любой объект в любую локацию и сохранять его местоположение ? Чтобы говно из одной локации переместить в другую, его сначала нужно найти. Например лока может хранить список всех вещей которые в ней находятся, когда найдешь свое говно в этом списке, просто удаляешь его от туда и кладешь в список другой локи и задаешь говну новую позицию как в посте выше.
>>721764 >>721771 >>721780 Спасибо, чуть уяснил. Я понимаю, что у вас дико горит, когда кто то не разбираясь лезет туда, где не осилит. Конечно я не шарю в математике. Но все объяснения, которые лежат на поверхности не дали мне никакого толчка. Вот есть массивы и они умеют так, а ещё вот так, но мне лично это никак не помогло.
>>721764 >>721771 >>721780 Понял, программирование не для всех. Когда начинаешь изучать основы, ничего, а дальше все как один говорят, ну зная это, ты можешь это. Да нихера ты не можешь
>>721771 Словил аневризму с этого поста. >Игровая карта в типичной ферме представляет собой большой двумерный массив, то есть массив массивов Пиздец. Во-первых, нет, во-вторых - двухмерный массив и массив массивов это разные вещи. Массив массивов это вообще такая ебанутая хуйня, что в неё не стоит лезть без скафандра нахуй. >В реальности содержимое каждой клетки описывается как минимум ещё одним массивом (а зачастую и словарём), т.к. в ней надо хранить не только тыкву, но и тип земли, например. Чего, блядь? Массив массивов массивов из словарей? Чет мало навернул, надо ещё списков нахуярить чтобы наверняка. И что, у тебя будет словарь с ключом из массива массивов, который хранит тип земли? Вот такие шизоиды только не лезут в треды ньюфагов и воспитывают новое поколение говнокодеров, пиздец.
>>721859 > пук Что сказать-то хотел? Двумерный массив реализуется массивом массивов во всех популярных скриптовых языках.
Что касается способа хранения информации об игровой ячейке, он-таки обычно и представляет из себя словарь (в терминах питона) или объект (в терминах js). Если только, повторюсь, разработчик не захотел разнести разнородную информацию по отдельным двумерным массивам.
>>721871 > то там именно массив массивов и других структур толком и нет, типа словарей или многомерных массивов Недавно вспомнил давно забытый трюк, как без задней мысли получить двумерные координаты в одномерном массиве. Способ кажется простым но обладает дичайшими подводными камнями. Итак. Чтобы получить (x, y) из одномерного массива, мы должны смело, отважно предположить, сколько у нас столбцов. И теперь, мы не менее смело предполагаем, что наш массив заполняется построчно, когда строка заканчивается, начинается новая строка с первого столбца. Таким образом, если мы поделим нацело на число столбцов, мы получим строку, а если мы возьмём остаток от этого деления, мы получим столбец. Подводные камни в том, что нельзя добавлять и удалять значения по одному. Изволь удалять целыми строками. Сортировка столбцов - отдельная песня. Формируй отдельный массив из значений каждого столбца. Сортируй нужный. Запоминай порядок. Выставляй порядок согласно запомненному в остальных столбцах.
>>721754 (OP) Ну, представь, что сцена это просто координатная сетка определенных размеров + список всех объектов, которые в сцене расположены. Абсолютно каждый объект имеет поле, которое показывает его координату. Как только сцена загружается, специальная функция спавнит все нужные объекты, тупо проходя по списку.
>>721754 (OP) Берёшь, делаешь структуру chunk. В чанке есть WxW блоков, то есть ширина и глубина равна W, что есть константа. Все чанки кладёшь в какой-нибудь ассоциативный массив типа хештаблицы, хештаблицы хештаблиц, дерева какого (?), в общем у них ключ это координаты чанка (x,y или x,y,z для 3D). В каждый блок может быть установлена, например, переменная с типом node. node состоит из указателя на NodeData и некоторых внутренних данных, которые надо сохранять и изменять. Внутри NodeData имеются некоторые поля, которые описывают твой объект (пашня, кусок дома, кусок моба). Это id, текстуры, анимации, модельки, шейдеры, физические свойства, что он дропает, какие коллбеки на разные виды интеракции с игроком, коллбек на процессирование каждый фрейм или каждый физический фрейм и т.д. В node могут быть ещё переменные, которые могут быть разными для одинаковых объектов. Например, есть объект Зомби и у одного осталось 50 ХП, а у другого 100 ХП. Конечно, можно объединить типы node и NodeData, чтобы второй имел тот же тип, что и node и когда создаётся новый node, оно просто копирует соответсвующий NodeData. Это даст больше гибкости, можно будет, например, изменить модельку и текстуру твоего объекта, но с другой стороны это даст сложности с обновлением игры. Например, у тебя объект пашня и в старой версии на нём рос рис 50 минут, а в новой версии 30 минут ты захотел сделать. И когда игрок загрузит игру у него пашня будет всё-равно 50 минут растить рис. Поэтому не всегда так надо. Далее, если надо отрисовать чанк, то проходишь по каждому блоку и если этот блок не динамический (не меняет модельку каждый фрейм или нет анимации), то сохраняешь его вертексные данные в массив графических данных самого чанка. И текстурку батчишь из текстурок всех объектов. А рядом складываешь графические данные для динамических объектов.
Не уверен в этом подходе, он у меня сам придумался, когда пилил свои игры.
>>722157 Как просвящаться ? Еще один популистичный ролик без информации. Даже любые циклы уроков по программированию слишком поверхностные и маленькие. Про зарубежные тоже ничего не говори, там тоже самое.
>>722849 >>722157 ОООО, я замотивировался уже в 84 раз в жизни. В этот раз точно уж что то выйдет. А то до этого я не понимал по урокам, как мне дальше то делать, а тут вот оно что.
>>722146 >программирование - это математика Неправда. Программирование - это логика и алгоритмы. Математика в программировании только в прикладной реализации математических формул, но бОльшая часть задач решается либо без формул совсем, либо с формулами из средней школы. Сегодня программирование вообще на 99.99% состоит из запросов к различным API, передаче параметров из одного места в другое. Программисты разработали для математиков множество "математических" языков, чтобы математики оставили программистов в покое и могли писать свои матановские формулы самостоятельно, однако никто не заставляет тебя играть в математика и программировать на языке для математиков.
В этой теме вообще только структуры данных обсуждаются. В математике нет данных, это только программерская фича.
>>721754 (OP) Такие игры устроены как-то так: 1. Есть "палитра объектов" и/или "палитра тайлов". В ней хранятся записи с информацией о каждом объекте, который может располагаться на карте, будь то тайл земли, кустик или домик. Эта информация может содержать: ссылку на спрайт, проходимость (может ли игрок встать на клетку с этим объектом), какие-либо дополнительные свойства (например, клетка с этим объектом замедляет игрока или наносит ему урон). Палитра нужна для того, чтобы можно было обращаться к единственному объекту в палитре по его номеру. 2. Есть "карта". Это двухмерный или, чаще, трёхмерный массив целых чисел. Каждое число - номер объекта в палитре. Подобные массивы как правило имеют небольшой размер, но их может быть несколько - это позволяет разделить игровой мир на локации/комнаты и сэкономить на оптимизации отображения. Два измерения массива (x, y) отвечают за расположение объекта относительно камеры, третий (z) отвечает за сортировку объектов по глубине (0 - нижний, 1 - поверх него, 2 - поверх их всех). Но в глубину такие карты обычно очень маленькие - хватает 3 слоёв (основной тайл, тайл с дыркой, объект; пример: земля, песок, яблоко - яблоко лежит на земле, частично присыпанной песком). 3. Чтобы нарисовать нашу "карту", мы делаем следующее: организуем два/три вложенных цикла со счётчиком (for), перебираем все ячейки массива-карты. Берём значение из ячейки - если не ноль, тогда ищем в палитре объектов объект с таким же номером. Рисуем тайл/спрайт этого объекта в определённом месте экрана. Место на экране определяется из координат ячейки в массиве (x, y), помноженных на размер тайла карты (для обычных квадратных тайлов это просто). В целях оптимизации мы можем заранее определять, находится тайл на экране или он находится вне экрана, это достаточно просто для обычных квадратных тайлов. 4. Чтобы перемещаться по карте, взаимодействовать с объектами - во время перемещения фигурки игрока мы храним его позицию (x, y) в массиве карты. Перед тем, как переместить игрока, мы проверяем, в какую ячейку массива карты он хочет переместиться. Находим в палитре все связанные с этой ячейкой объекты (все - по оси z), проверяем параметры этих объектов (проходимость и накладываемые эффекты). Учитывая эти параметры, мы либо запрещаем перемещение игрока, либо перемещаем и, при необходимости, накладываем на него дополнительный эффект (а ещё может быть ситуация, когда игрок не перемещается, но получает эффект - к примеру, ожог от костра). В случае взаимодействия игрок не собирается перемещаться, тут нужно смотреть другие параметры объектов в палитре (можно ли объект взять в руки или как-то использовать и т.п.). 5. Если предполагается взаимодействие с картой с помощью мыши - мы, во-первых, должны вычислять позицию курсора мыши в координатах массива карты. Для этого достаточно знать размер тайла карты, смещение карты относительно экрана, позицию курсора в пикселях. Формулы несложные, их легко подобрать методом тыка. Узнав координаты в массиве, мы точно так же проверяем объекты по палитре объектов. 6. Сохранение карт может производиться двумя способами: если это полностью редактируемая карта как в Террарии, тогда она сохраняется в том же формате, в котором загружается; если игрок ограничен и может только изменять состояние отдельных элементов в целом статичной карты, тогда достаточно хранить список изменений, отличающих оригинальную карту от сохраняемой, и во время загрузки применять эти изменения к исходной карте (так сохранение будет занимать значительно меньше места).
Однако большинство из перечисленного актуально только для разработки игры с нуля на самодельном движке или на очень простом фреймворке. Большие движки как правило имеют встроенные компоненты для оперирования тайловыми картами. В случае использования такого движка остаётся только изучать его документацию и смотреть примеры использования его инструментов. Также существуют конструкторы игр - это ещё более простые в освоении инструменты, с ними сделать игру сможет даже маленький ребёнок. Если в твоей игре не планируется чего-то сверхсложного или уникального как в Террарии, тогда присмотрись в первую очередь к конструкторам игр (к примеру, RPG Maker). Если нужны какие-то необычные функции - присмотрись к движкам общего назначения (к примеру, Unity). Писать же игру с нуля тебе потребуется, только если нужно "выжать из железа максимум" - как это делает Terraria. В таком случае стоит присмотреться к SDL и различным простым фреймворкам, но с твоим уровнем знаний ты не потянешь разработку собственного игрового движка.
Также замечу, что техническая реализация игровой карты и взаимодействий с ней - очень малая часть разработки подобной игры. Гораздо важнее нарисовать качественную графику, написать сюжет, продумать геймплей. Игрокам совершенно безразлично, какой код ты напишешь и какой движок используешь - они будут смотреть на графику, читать диалоги и описания, слышать музыку, взаимодействовать с предметами и т.д. Если ты не умеешь рисовать и не имеешь чёткого представления будущей игры - задумываться о программировании такой игры смысла нет.
Сам я могу и уже пробовал делать такие игры, но забрасывал в том числе потому, что не смогу в контент...
В общих словах, ты берёшь объекты и сохраняешь их в массив данных, или таблицу для простоты.
Потом когда подгружается область мира ты подгружаешь эти объекты.
То как именно будет определяться область это уже зависит от реализации. Можно по радиусу, универсальный подход, но не лучший с точки зрения оптимизации.
Проверяешь, если объект в радиусе, то добавляешь его в список обработки, либо делаешь активным. Разумно предусмотреть подобные статусы заранее. Я люблю иметь 3 статуса:
1. inactive - полностью неактивный объект, который никак не обрабатывается, пока действует этот статус, для ещё большей оптимизации можно создавать отдельный список неактивных объектов, которые проверяются переодически, а не каждый тик
2. lazy - полуактивный объект, такие объекты обрабатываются реже и могут иметь свои оптимизации, обычно такие объекты немного за экраном, но их обработка нужна для взаимодействия с игровым миром
3. active - полностью активный объект, обрабатываемый каждый игровой тик
Альтернатива радиусу - область видимости, ещё есть ячейки. На самом деле вариантов больше десятка как это можно реализовать.
Более интересно на мой взгляд именно способ хранения. Если игровой мир большой я предпочитаю использовать ячейки, а именно мир поделён на области, которые подгружаются в зависимости где находится игрок. Соседние ячейки загружаются и имеют лениво обрабатываемые объекты. Когда игрок приходит в зону, эти объекты могут находится в других местах или в другом статусе, что создаёт иллюзию живого мира.
Так же при загрузке области я произвожу генерацию событий, а именно обсчёт исходят из пропущенного времени. Симулируется в упрощёном виде то, что могло бы произойти за 10 минут отсутствия в конкретной ячейки непример и так как это происходит на фоне, то игрок не увидит как за его областью видимости произошла по сути генерация событий. Для игрока будет казаться, что игровой мир постоянно существует, а не выгружается и не становится неактивным.
>>723821 >элементарные вещи Ты какой-то сложной узкоспециальной фигнёй его грузишь, имхо. Даже я не совсем понял, что ты хочешь объяснить. Ему нужна простая тайловая карта, которую вообще не нужно никак оптимизировать, ведь она будет маленькой, это тебе не опенворлд и даже не Fallout 1. Все перечисленные тобой оптимизации нужны для больших игр с открытым миром, обычно это 3D игры, в которых симулируется реальная физика и есть множество графически сложных объектов. А он в примеры приводит 2D-игры с тайловой картой, в которых ни физики, ни сложной графики нет. Оптимизировать всё это придётся только в двух случаях: если нужен опенворлд на десятки километров без деления на "комнаты", и если игра пишется на каком-нибудь слоупочном и жирном говне вроде питона.
>берёшь объекты и сохраняешь их в массив данных В массив нужно сохранять числа. Дублирование ООП-объектов - это одна из главных причин тормозов, тем более в скриптовых ЯП. Вот если у тебя на карте 5 одинаковых деревьев в виде спрайтов, что тебе мешает разместить в том массиве индекс, который будет однозначно указывать на объект "дерево" в палитре объектов? Рендерер сам найдёт этот объект и разместит его на карте - не нужно дублировать данные объекта "дерево" пять раз. Потому что этих деревьев может быть не 5, а 125 или 5000, и пять тысяч спрайтов занимают намного больше места, чем пять тысяч integer (хотя тут хватит и word, в два раза меньше места займёт, вряд ли в игре будет больше 65к видов объектов).
>>724213 > В массив нужно сохранять числа. Дублирование ООП-объектов - это одна из главных причин тормозов, тем более в скриптовых ЯП. Вот если у тебя на карте 5 одинаковых деревьев в виде спрайтов, что тебе мешает разместить в том массиве индекс, который будет однозначно указывать на объект "дерево" в палитре объектов?
Во всех современных языках ООП-объекты имеют ссылочный тип. Это значит, что если новичок специально не заморочится каким-то особым дублированием, а просто положит ООП-объект дерева во все ячейки карты с деревьями, ничего плохого не случится.
>>724231 >ничего плохого не случится Если у нас массив ссылок на ООП-объекты, при этом имеется большо одной ссылки на один и тот же объект, можно случайно удалить объект по ссылке и получится куча ссылок на недопустимую область памяти, и нуб встретится с EAO или её аналогом. А вообще лучше ООП не трогать.
>>724241 >можно случайно удалить объект по ссылке А где такое вообще есть? В JS, Lua и питоне точно нету. Вообще, ссылка на недопустимую область памяти - это что-то раздела крестопроблем, в нормальных языках есть сборщик мусора.
>>724242 >есть сборщик мусора >в нормальных языках В нормальных языках объекты нужно уничтожать руками, сборщик мусора только помогает в этом. В ненормальных языках говнокодер ни на что повлиять не может - объекты накапливаются в памяти, а "сборщик мусора" периодически пропукивает скопившиеся объекты. Лучше не пользоваться такими языками с пропукивающим "сборщиком мусора", это вообще не сборщик, это пропукиватель мусора. В случае JS, увы, альтернативы нет.
>>721754 (OP) Не понимаю что тебя смущает. Ну сделай большой двумерный массив. Не помещается, слишком тяжёлый? Раздели на части и рендерь только часть.
>>721754 (OP) >дальнейшее сохранение на локации Достигается хорошим движком>>721754 (OP) >именно расположение объектов на области Знаниями геометрии, школьный курс. Алгебры, школьный курс.
>>721754 (OP) Храни отдельно карту, а отдельно список объектов. Карта статична, а у объектов может быть свои свойства и позиция на карте. Свойства объекта не должны обновляться не в каждом кадре, а при наступлении к-либо события.
сохранение и загрузка = это сериализация/десериализация. с сохранением/восстановлением нужных параметров. Например: У тебя на локации: 10 клумб. У каждой есть позиция(x,y(float)), степень полива(float), количество цветов(int). При сохранении должэн быть создан файл с содержимым: {[ {posX: 3; posY: 5; watering: 1,2; count: 3} {posX: 6; posY: 2; watering: 1,2; count: 2} ... {posX: 4; posY: 4; watering: 0,3; count: 6} ]} При загрузке этот файл считывается и интерпретируется твоей программой (клумбы расставляются на свои места, неполитым цветам назначается отдельная анимация, отрисовывается нужное количество цветов)
>>728474 Cоздай класс FlowerBed(В котором будут реализованы свойства и функции клумбы); создай класс MapController(он будет управлять картой) в котором будет храниться список FlowerBed-ов. (используй списки - если количество элементов не определено, массивы - если количество элементов четко определено.)Например: предметы в инвентаре - список.(они могут добавляться, удаляться) Информация о тайлах на карте - массив (у тебя четко определенный размер карты на каждом уровне(map[x][y])) Для сериализации есть уже готовые библиотеки, при помощи которых, одной строчкой кода ты можешь преобразовать свой класс MapController в json и сохранить в папке игры. можно конечно написать свою функцию сериализаци/десериализации, но это будет дольше, дороже(в плане производительности) и хуевее
>>729437 потому что на гамаке можно выпустить все свои 2д проекты и перейти к 3д в юнете, так как геймплейно 3д сильно отличается от геймплейно 2д, и смена языка на новый тут будет только плюсом, ящитаю
>>729484 >выпустить все свои 2д проекты и перейти к 3д в юнете Не хочу так. Хочу только 2D. Юнити тяжёлая, лагающая тягомотина. Уходи шиз. Продолжай переходить на 3д в своём гамаке.