Понедельник, 14 Октября 2024, 08:00

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 3
  • 1
  • 2
  • 3
  • »
Генерация мира. Нужны ответы
SaiteiДата: Пятница, 24 Августа 2012, 12:15 | Сообщение # 1
старожил
Сейчас нет на сайте
Привет всем! Я вот решился писать что-то вроде Minecraft, но с использованием примеров (т.е. не с 0). Писаться всё это чудо будет на ЯП C++.
OpenGL и DirectX не использовал. Использовал лишь движки GEGE и HGE. DirectX по неким причинам использовать не могу (в чистом виде, ну а если в движок вшит - то можно).
Собственно, тема такая:
какой движок юзать? как работает вообще эта генерация? примеры есть? Я видел source code из minetest, но там всё запутанно и архитектура приложения весьма сложная.
Пока я пришёл лишь к тому, что координаты и расположение блоков будут храниться в byte map[x][y]. Например map[1][1] = 1; - это блок земли в X:1, Y:1.
Я не знаю в чём работать и на что смотреть. Нужен "старт". Надеюсь, что вы меня поймете...
mobipakДата: Пятница, 24 Августа 2012, 12:20 | Сообщение # 2
Подрывник
Сейчас нет на сайте
А ты его в 2D или 3D будешь делать?
SaiteiДата: Пятница, 24 Августа 2012, 12:22 | Сообщение # 3
старожил
Сейчас нет на сайте
crayan, привет. Вообще хотелось бы в 3д (думаю наложить текстурку на куб не так уж сложно), но в 3д ведь добавляется третья ось. Получается, что генератор придется писать куда сложнее. От 2д не плююсь, но хотелось бы всё-таки 3D. Однако принципы генерации карт как в 2д, так и в 3д понять не могу. Ну а все знакомые говорят, что всё на самом деле просто...
mobipakДата: Пятница, 24 Августа 2012, 12:25 | Сообщение # 4
Подрывник
Сейчас нет на сайте
Ну вообще на Unity есть примеры генерации, как в минекрафт. Даже кто-то ссылку давал. Только для тебя это будет безполезно, это ж для Unity и C#...
SaiteiДата: Пятница, 24 Августа 2012, 12:29 | Сообщение # 5
старожил
Сейчас нет на сайте
crayan, C# я знаю. Но у Unity3D свои функции и в интерфейсе я теряюсь
LunarPixelДата: Пятница, 24 Августа 2012, 13:01 | Сообщение # 6
старожил
Сейчас нет на сайте
Quote (Saitei)
Ну а все знакомые говорят, что всё на самом деле просто...

Ну так чего тебе эти знакомые не объяснили как делать?! smile

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




Сообщение отредактировал LunarPixel - Пятница, 24 Августа 2012, 13:02
SaiteiДата: Пятница, 24 Августа 2012, 13:03 | Сообщение # 7
старожил
Сейчас нет на сайте
LunarPixel, ну... Многие в офисах сидят, работают
Quote (LunarPixel)
Пробегаешь во всей карте, и расставляешь блоки по определенным правилам (максимальная высота, относительно соседних блоков, вид блока и т.д.)
Или изначально строишь возможные свободные пути перемещения, а остальное пространство заполняешь блоками.
Это как пример, есть и другие способы, конечно.

Великий рандом чтоли?
LunarPixelДата: Пятница, 24 Августа 2012, 13:06 | Сообщение # 8
старожил
Сейчас нет на сайте
Quote (Saitei)
ну... Многие в офисах сидят, работают

не вижу связи.. smile

Quote (Saitei)
Великий рандом чтоли?

Quote (LunarPixel)
по определенным правилам

Quote (LunarPixel)
возможные свободные пути перемещения

Какой уж тут рандом?! Хотя, конечно, рандом будет присутствовать, генерация же случайная (рандомная) smile


SaiteiДата: Пятница, 24 Августа 2012, 13:11 | Сообщение # 9
старожил
Сейчас нет на сайте
Quote (LunarPixel)
не вижу связи..

Очень занятые люди (вроде)
Quote (LunarPixel)
Какой уж тут рандом?! Хотя, конечно, рандом будет присутствовать, генерация же случайная (рандомная)

эх... мне бы код глянуть глазком...
LunarPixelДата: Пятница, 24 Августа 2012, 13:12 | Сообщение # 10
старожил
Сейчас нет на сайте
Возьмем, например, примитивнейшую генерацию в 2D.

Вся локация - поле, состоящее из секций 32х32.
Начитаем строить землю по столбикам, слева направо. Устанавливаем диапазон возможной начальной высоты поверхности. Ставим в этом диапазоне блок земли. От этого блока до низа заполняем все землей. Переходим на второй столбец уровня, ставим второй блок, исходя из условий, что он может быть либо на 32 ниже предыдущего, либо на 32 выше, либо на том же уровне. Ставим блок, заполняем ниже него все землей, переходим на следующий столбец и там делаем тоже самое. Все, будет случайная генерация поверхности. Теперь просто расширяем условия, чтобы генерация была более разнообразной. smile


FadeBakerДата: Пятница, 24 Августа 2012, 13:15 | Сообщение # 11
JavaSE Game Developer
Сейчас нет на сайте
Самый простой пример:
Code
int meter = random(30, 50);
for (int x = 0; x < ширина_карты; x++) {
     for (int y = meter; y < высота_карты; y++) {
        Block block = Block.dirt;
        if (y - meter > random(5, 10)) block = Block.stone;
        if (y == meter) block = Block.grass;
        создатьБлок(x, y, block); //твоя функция создания блока
     }
     meter += random(-1, 1);
}



Уроки по GM
Minecraft 2D на GM
— Мои проекты —
Blood Harvest [2D] — Original
Blood Harvest [2D]: Remastered Edition
Adventure Craft [2D] — Sandbox
Space Shock [2D] — Scroll Shooter
Intel® Core™ i5-3570K 3.40 GHz, 8 GB RAM, GeForce GTX 750 Ti, Monitor: LG 23EA63V-P.


Сообщение отредактировал Fade - Пятница, 24 Августа 2012, 13:16
SaiteiДата: Пятница, 24 Августа 2012, 13:16 | Сообщение # 12
старожил
Сейчас нет на сайте
Quote (Fade)
int meter

за что отвечает эта переменная?
FadeBakerДата: Пятница, 24 Августа 2012, 13:18 | Сообщение # 13
JavaSE Game Developer
Сейчас нет на сайте
Quote (Saitei)
за что отвечает эта переменная?

Высота поверхности. Меняется при каждой итерации первого цикла.


Уроки по GM
Minecraft 2D на GM
— Мои проекты —
Blood Harvest [2D] — Original
Blood Harvest [2D]: Remastered Edition
Adventure Craft [2D] — Sandbox
Space Shock [2D] — Scroll Shooter
Intel® Core™ i5-3570K 3.40 GHz, 8 GB RAM, GeForce GTX 750 Ti, Monitor: LG 23EA63V-P.
TimKruzДата: Пятница, 24 Августа 2012, 17:17 | Сообщение # 14
старожил
Сейчас нет на сайте
Quote (Saitei)
Пока я пришёл лишь к тому, что координаты и расположение блоков будут храниться в byte map[x][y].

Главное не зацикливайся на одном массиве, чтобы не делать его 10000x500 блоков. Лучше генерируй, загружай и сохраняй порциями, так будет более-менее оптимально.
Генерируешь рандомно, с учётом простых условий и дополнительных данных... Либо по "ключу" (как в minecraft), для этого свой random() придётся делать, потому что стандартный обычно использует системные часы.
Вот, для примера:
1. Закрываем всё ниже уровня 0 (уровень моря) - землёй (1), остальное - воздух (0).
2. Берём порцию (0;-32) размером (32;32) (ниже поверхности).
3. Смотрим - ага, уровень -32..0. Что тут у нас? Каменный уголь - 5%, камни - 10%. 32x32 = 1024, 1024*5/100 = 51 (округляем), значит, нужно 51 раз добавить уголь в разных местах, а камень - 102 раза.
4. Делаем что-то типа этого:
Code
var x, y, coal:word;
begin
   coal:=51;
   while coal>0 do
   begin
     x:=random(32);
     y:=random(32);
     if map[x,y]<>2 then //ещё не уголь
     begin
       map[x,y]:=2;
       dec(coal);
     end;
   end;
end;

То же для stone. Это самое простое. Получается случайный разброс N-ного числа угля/камня, правда, это будет выглядеть ненатурально.
Можно делать иначе, по-сложнее, но более удачно выглядящее. Выбираем случайную точку в заданном диапазоне, выбираем случайную массу месторождения угля (например, от 5 до 15 блоков в одном месте), вписываем двойки в матрицу так, чтобы все блоки были рядом, из общего числа вычитаем число блоков в этом месторождении. Далее ищем следующую точку - но теперь так, чтобы она не касалась предыдущего месторождения, скажем, так: берём случайную точку и вычисляем расстояние до ближайшего блока угля - должно быть, например, не менее 10 блоков. Таким образом получаем несколько разных залежей угля разной массой, но общим числом 51.
Естественно, добавляем разброс числа - в каждом квадрате 32x32 точно под поверхностью может быть не только 5%, но и 4, и 6, и даже 1%, или вообще не быть угля.
Точно так же делаем с остальными блоками. Горы и пещеры делаем как-то так: берём случайную точку под землёй (пещера) и вырезаем случайную область определённого объёма, скажем, 100 соединённых блоков; можно задать определённую форму - берём прямую ось или плоскость определённой длины, и удаляем блоки только в определённом радиусе, не дальше - получаем, например, каньон; горы наращиваем, выбрав случайную точку на поверхности, задав определённую высоту и добавляя земляные блоки случайным образом вверх, до этой высоты.

Главное не слишком баловаться с random(), или написать свой, экономичный вариант. Обычно эта функция требует много времени, а генерация карты на полчаса мало кого порадует.
Варианты функции random-а можешь найти в интернете и написать свою, в которой ключ генерации задаётся явно, а потом этот ключ задавать с помощью стандартного random, перед генерацией карты.


daunДата: Пятница, 24 Августа 2012, 17:33 | Сообщение # 15
постоянный участник
Сейчас нет на сайте
А разве там не 3D массив (map[x,y,z]).
По координатам гг определяем его положение в массиве, показываем его окружение, при перемещении достраиваем мир.
SaiteiДата: Суббота, 25 Августа 2012, 19:47 | Сообщение # 16
старожил
Сейчас нет на сайте
Вот с Fade мудрили-мудрили, а споткнулись на мелочи (здесь не его вина (т.к. он вообще программирует на Java, а я - на С++)). У нас не получалось сделать так, чтобы в классе создавались новые экземпляры блоков (членов). Синтаксис ругался. Точно уже не помню, но, кажется, конкретно с этим проблема всплыла. Ну а я пытался выучить джава - много подхватил, НО мне там очень неудобно работать (eclipse 64-bit удивительным образом критовал, а 32-bit ужасно глючит). Итак, давайте всё логически распишем? От начала до конца, пунктами? Очень пригодилось бы. Код TimKruz посмотрел. Спасибо, немного открылись глаза. Но хотелось бы сейчас поэтапно расписать всю эту генерацию (в игре будут разрушаться блоки)
TimKruzДата: Суббота, 25 Августа 2012, 23:17 | Сообщение # 17
старожил
Сейчас нет на сайте
Quote (Saitei)
Синтаксис ругался.

Прочитай описание или номер ошибки, поищи решение в интернете и перечитай об использовании классов в самоучителе. wacko
Quote (Saitei)
чтобы в классе создавались новые экземпляры блоков (членов)

Каждый блок - экземпляр класса? По-моему, это даже хуже, чем тупо массив... wacko Ведь в массиве все данные друг за другом идут, и информация о позиции каждого блока не хранится, а если делать классами - нужно хранить x и y.
В Minecraft, по-моему, поверхности описываются формулами, поэтому такая производительность...
Ещё можно отбрасывать полностью пустые массивы. Например, над поверхностью есть несколько пустых частей по, скажем, 256 блока воздуха. Зачем хранить эти нули? Можно отбросить этот массив, считая его пустым, пока на его месте игрок не попытается что-то поставить. А ещё можно сворачивать массивы, например, так: 90% массива составляет земля, остальные 10% - примеси вроде камней, угля, пустот. Тогда можно установить тип "земля" для данного участка карты, т.е. любая клетка по-умолчанию будет землёй, а не земляные клетки (или области) описываются отдельно. Но это будет удобно только для записи в файл.
Quote (daun)
А разве там не 3D массив (map[x,y,z]).

Для 3D игры - да, но ему хотя бы 2D как-нибудь сделать... biggrin
Quote (Saitei)
Код TimKruz посмотрел.

Ну это самый простой вариант, вот что-то типа второго варианта (со скоплениями):
Code
var i, x, y, coal, mt:word;
begin
    coal:=51;
    while coal>0 do
    begin
      mt:=random(10)+5; //Объём
      if mt>coal then mt:=coal;
      repeat //Ищем точку, отдалённую от других залежей
        x:=random(32);
        y:=random(32);
      until nearest_block(2); //Отдельная функция, ищет блоки указанного типа в радиусе нескольких блоков
      for i:=1 to mt do
      begin
        map[x,y]:=2;
        case random(4) of //Выбираем направление движения
        0: inc(x);
        1: dec(x);
        2: inc(y);
        3: dec(y);
        end; //case
      end; //for
      dec(coal,mt);
    end;  //while
end;

Ну тут не обрабатываются исключения, типа вариантов, когда нет точки, удалённой от остальных скоплений (зациклится), нет проверки возвращения назад (когда перешли сначала от начальной точки, а потом вернулись тем же путём) и других проблем... Но это сделать несложно, сам должен разобраться...
Quote (Saitei)
eclipse 64-bit удивительным образом критовал, а 32-bit ужасно глючит

Ну не обязательно использовать Eclipse, ещё есть NetBeans и другие среды... В конце концов, можно скачать другую версию Eclipse...
Quote (Saitei)
Итак, давайте всё логически распишем? От начала до конца, пунктами?

А давай ты попробуешь сам тут логически расписать то, что уже понял и до чего сам додумался. Тут ведь разные алгоритмы могут быть, нельзя принимать что-то одно как универсальное решение. huh
Главное сделай свою функцию, выдающую случайные числа, а то стандартная тут не пойдёт. Она непредсказуема. sad
Quote (Saitei)
что координаты и расположение блоков

Вообще-то, координаты и расположение нигде не хранится, в таком массиве хранится только тип клетки/блока и какие-либо его свойства, а вот положение его вычисляется по смещению от начала массива.

***
Quote (Saitei)
в игре будут разрушаться блоки

Какое отношение имеет это к генерации? При разрушении изменяй число в массиве на 0 и всё. Это, конечно, если ты будешь использовать массивы.




Сообщение отредактировал TimKruz - Суббота, 25 Августа 2012, 23:18
SaiteiДата: Воскресенье, 26 Августа 2012, 01:50 | Сообщение # 18
старожил
Сейчас нет на сайте
Quote (TimKruz)
Какое отношение имеет это к генерации? При разрушении изменяй число в массиве на 0 и всё. Это, конечно, если ты будешь использовать массивы.

Ну как бы я... Ээээ... Клоню к тому, что каждый блок имеет свой id, чтоли... То есть если разрушить блок земли - разрушится только ОН, а не ВСЕ...
Quote (TimKruz)
А давай ты попробуешь сам тут логически расписать то, что уже понял и до чего сам додумался. Тут ведь разные алгоритмы могут быть, нельзя принимать что-то одно как универсальное решение.
Главное сделай свою функцию, выдающую случайные числа, а то стандартная тут не пойдёт. Она непредсказуема.

Пока мои познания ограничиваются тем, что я буду иметь двумерный массив (map[x][y])... Например map[0][0] = 1; - блок земли, а map[0][1] = 0; - воздух (пустота)...
Ещё я понял что генерация мира будет проходить в цикле. Там будут свои ограничения и правила... И будет использоваться функция рандома (например компьютер будет высчитывать: ставить блок выше или ниже?).
Подумываю над тем, чтобы компьютер сначала делал верхний слой (горки и т.п.), затем все, что ниже, заливал землёй. Потом на определенном уровне (он колебаться будет... Ну, представим, что от 30 до 40) будет ставиться блоки камня (земли больше не будет, генератор значение "1" вытеснит на "2") (опять же с рандомным шансом в 80%, 20% - всякие руды (разные). Последний этап генерации - генерирование пещер (удаление внизу блоков и образование "данжев")

Но вот... Хотелось бы от А до Я расписать... Причём от простого к сложному. Так, как надо действовать

Добавлено (26.08.2012, 01:40)
---------------------------------------------
всё ещё жду...
Завтра буду переводить для себя вот это:

Добавлено (26.08.2012, 01:44)
---------------------------------------------

Quote
2) Как достигается генерация такого естественного ландшафта?

В очень ранней версии Minecraft’а я использовал карту высот 2D шумов Перлина , чтобы придать миру форму. Ох, точнее я использовал множество из них. Один для общего подъёма, один для придания неровностей и один для мелких деталей. Для каждого столба из блоков высота вычислялась по формуле (подъём + (неровность*мелкие детали))*64+64. Все подъёмы и неровности были гладкими, на слишком большие добавлялся «шум», и детали были более запутаннее, чем сейчас. Этот метод имеет большое преимущество в плане скорости и в нём 16*16*(количество шумов) сэмплов для генерации в каждом чанке, но проблема была в том, что этот способ скорее был туп. Особенно тупизна видна в том, что нельзя сгенерировать нависающие склоны и арки.

Итак я предпочёл эту систему похожей, сделанной на 3-D шумах Перлина. Вместо проверки по высоте, я установил значение шума на «густоту» и теперь всё, что ниже 0 (нуля) будет воздухом, а всё, что на том же уровне или выше будет землёй. Чтобы убедиться, что дно плоское и без дыр, а верх не плоский я просто добавил высоту (исключая места под водой) в список сэмплов для генерации.

Но, к сожалению, я тут же столкнулся с проблемами производительности и игровой механики. Производительность падала из-за того, что нужно было обработать огромное количество сэмплов, а проблемы с игровой механикой были в том, что не было равнин и пологих холмов. Решением стало переключение сэмплов в более низкое разрешение (8х по горизонтали и 4х по вертикали) и использование линейной интерполяции . Внезапно игра стала генерировать равнины, пологие холмы и большинство единичных летающих блоков пропали.

Текущая формула, которую я использую довольно запутана (и секретна!), но она постепенно эволюционирует (когда я работаю над игрой). И да, она ещё использует 2D карту высот и карты шумов.

xX

Добавлено (26.08.2012, 01:50)
---------------------------------------------
Кажется шум Перлина мне нужен...

Читаю статью, пока всё в тумане. Но там тоже генерация случайных чисел идёт

Сообщение отредактировал Saitei - Воскресенье, 26 Августа 2012, 01:07
TimKruzДата: Воскресенье, 26 Августа 2012, 01:52 | Сообщение # 19
старожил
Сейчас нет на сайте
Quote (Saitei)
Клоню к тому, что каждый блок имеет свой id, чтоли... То есть если разрушить блок земли - разрушится только ОН, а не ВСЕ...

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

Quote (Saitei)
map[x][y]

Не знаю, как там в C++, но в Паскале map[x,y] и map[x][y] - вещи разные, первое - двумерный массив, второе - массив массивов. Наверное, технической разницы никакой, но писать и читать map[x,y] всё-таки удобнее...

Quote (Saitei)
И будет использоваться функция рандома

Ну без рандома обойтись тут никак нельзя и это даже не обсуждается, потому что в любом случае нужны случайные значения...

Quote (Saitei)
представим, что от 30 до 40
Quote (Saitei)
рандомным шансом в 80%, 20%

Лучше настройки шансов где-нибудь записать, константой или из файла считывать, потому что когда алгоритм реализуешь, придётся подгонять все эти коэффициенты, потому что с первого раза точно не определишь, сколько чего и где нужно; ну а бегать по сотням или даже тысячам строк кода в поисках места использования убийственно. Поэтому лучше над коэффициентами сначала вообще не думать - потом подгонишь, сейчас нужно общий алгоритм придумать.


SaiteiДата: Воскресенье, 26 Августа 2012, 01:53 | Сообщение # 20
старожил
Сейчас нет на сайте
TimKruz, но как рендерить-то,отталкиваясь от массива?
  • Страница 1 из 3
  • 1
  • 2
  • 3
  • »
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг