воскресенье, 4 октября 2015 г.
Статус воксельного движка
Похоже, пока я размечтался о крутых особенностях физически обоснованной игровой механики в воксельных мирах, я недооценивал проблемы производительности при отображении мира игроку. Начнем по-порядку.
Я уже говорил раньше, что для более быстрого рендера блоков на экране, их пришлось собрать в группы, которые обычно называют чанками и рисовать уже чанки. Дальнейшие опыты показали, что довольно тупым и неэффективным путем Майнкрафта у меня идти не получается. Дело в том, что конечность высоты мира в Майнкрафте позволяет там считать чанком целый столбец мира высотой в 256 блоков, что, конечно, позволяет рисовать намного меньше поверхностей этих самых блоков изначально. Поэтому, тупо загрузить N * N * N чанков вокруг игрока оказалось жутко неэффективной затеей. Еще более неэффективным ее делала большая разница в представлении блоков. В Майнкрафте у блока просто есть одно число, которое полностью описывает "материал" и "положение" блока, скажем, его ориентацию, если она важна. Или это же число используется для запаковки множества похожих типов блоков, например, разноцветных блоков шерсти или глины. Понятное дело, это изначально показалось мне слишком жестким и мне захотелось расширить число свойств блоков, сразу позволив хранить целые списки разных значений. Конечно, это сразу же значит, что, во-первых, блоки занимают больше памяти, во-вторых, передаются по сети дольше. Так что вместо каких-то двух байт на тип блока, у меня получается все довольно толстым. С учетом того, что Майнкрафт и дальше немного оптимизирует эту часть протокола в последних версиях, они, наверное. о чем-то догадываются. Я об этом догадался не сразу, так что время доставки чанка с сервера на клиент оказалось великоватым, и даже если рендеринг успевает хорошо рисовать кучу поверхностей, обеспечить приемлемый радиус отрисовки уже становится трудным, потому что, мать их, чанки с сервера приходят долго. А то что они занимают сокет передачей, лишает некоторой плавности синхронизацию движения игрока в клиенте и сервере. В общем, время передачи чанков на клиент оказывается очень критичным (или нужно изобретать протокол вроде FTP, который бы использовал отдельное соединение для данных чанков). Значит, сообщения должны быть короче, а чанк придется разбить на части при передаче.
Но это еще не вся проблема. В сервере придется понятие "чанк" реализовать тоже, чтобы оптимизировать поиск и отправку всех блоков из запрошенного чанка. Раньше, когда он не мог оперировать таким понятием, ему приходилось вычислять, какие блоки из каких мест нужно вычитывать и последовательно их выдергивать. Я подозреваю, что это слишком медленно.
Но наилучшее решение, которое я нашел для этой проблемы, это оптимизировать число чанков, которые нужно загружать с сервера. Правда, эта часть до сих пор работает очень нестабильно. Работает это так: сначала вокруг игрока загружается минимальная область, скажем, 4х4 чанка. Далее, в текущей реализации, вокруг этой области клиент проверяет, видно ли каждый соседний, еще не загруженный чанк, разыскивая пересечения лучей от углов чанка до игрока и проверяя, сталкивается ли он с непрозрачным блоком внутри такого чанка. Однако, это, видимо, недостаточно точная проверка, потому как игроку не обязательно видеть углы, чтобы видеть кусок какой-то поверхности. И здесь интересно подумать, как сделать это лучше. Но уже так можно не загружать большое количество лишних данных с сервера. Возможно, если эту методику скрестить с понижением уровня детализации для дальних чанков, может быть возможным значительно увеличить дистанцию, на которой можно что-то разглядеть.
Печально в этом всём то, что постоянно приходится переписывать большие куски кода повсюду, так что даже нормальное, приемлемое по производительности, рисование одного типа блоков, похоже, будет возможным еще не скоро. А хотелось бы все-таки заняться чем-то более веселым, например, тем же движением игрока и обнаружением его столкновений с блоками.
суббота, 3 октября 2015 г.
Про электронные сигареты
Не хотел торопиться об этом говорить, но, похоже, после двух недель такого существования я набрал немного опыта. Не все знают, но я курю уже 11 лет и в последнее время меня это стало понемногу напрягать, потому что курить я стал по две, а иногда и больше, пачки в день, и с прошлой попытки бросить стало только хуже. Так что, совершенно случайно заметив, как выглядит и работает современная электронная сигарета, я приобрел себе одну неплохую из тех, что можно посоветовать начинающим - Kanger EVOD Mega. Также, по незнанию, я взял пару разных жидкостей для нее, обе с 6 миллиграммами никотина на 1 миллилитр. Этого, правда, оказывается мало для того, кто курил много, но уже в первые дни обычные сигареты стали интересовать меня намного меньше и я почти не возвращался к ним, выкуривая где-то десяток в день. Спустя несколько дней, в течение которых я немного погуглил, изучил тему и оказалось, что мне стоило выбрать что-то намного более крепкое, и после перехода на 18 мг курить мне не хочется совсем, а один запах дыма вызывает неприятную реакцию. Но о реакции позже. :)
Сразу я обратил внимание, что у вновь начинающих наблюдается какая-то болезнь ньюфага, когда они восторжено начинают рассказывать и пропихивать идею перехода на парилки с курилок. Оно и понятно, потому что впечатлений куча. Первое начинается тогда, когда небольшое количество угарного газа, образующегося при горении, уходит из крови и позволяет транспортировать больше кислорода. От этого, в первую очередь, начинает наблюдаться покалывание конечностей, как бывает, если на них долго лежали и вдруг встали и дали крови нормально циркулировать. Это вызывает необычайное желание бегать, прыгать и рассказывать, как же это круто, парить эти новые штуки. Кроме того, попытки курить вызывают недоумение, потому что вкус и запах дыма уже не так интересны. Но все еще может оставаться тяга к сигарете, потому что в дыме не только никотин вызывает привыкание (гугление позволило узнать, что там еще с десяток веществ, которые имеют тот же эффект). Кроме того, никотин всасывается медленнее и не сразу попадает туда, куда нужно, чтобы тяга пропала моментально, как это бывает при курении.
Потом, правда, эйфория проходит. Где-то через неделю у меня полностью пропал вкус жидкости при парении и это вызвало новый позыв гугла об этой проблеме. Оказалось, это обычное дело и оно проходит само собой. На мое счастье, вкус пропал не полностью, так что еду и напитки я мог нормально воспринимать. Бывает хуже. Прошло это дня через три.
В остальном, тело испытывает симптомы обычного отказа от курения, включая бессонницу и сонливость одновременно, проблемы с пищеварением и все то прочее, что обычно бывает, включая обострение хронического бронхита на пару дней, повышенное выделение мокроты и насморк. Последнее у меня к настоящему моменту прошло. Теперь все кажется вполне обычным делом, однако напрягает возможная реакция окружающих на такую штуковину и связанная с этим проблема парить на ходу.
Однако, особо хочется отметить то, какую реакцию теперь вызывает запах дыма обычных сигарет. Причем, эта реакция намного слабее, если это дым сигары или трубки, например. Этот запах стал жутко раздражать. Я стал замечать этот запах повсюду и даже просто идти по улице стало неприятно, так как число курящих, оказывается, очень велико и они повсюду, они разного пола и возраста. И их запах распространяется на десятки метров вокруг. Так я осознал, насколько антисоциальным было мое прошлое поведение. По сравнению с этим парение, конечно, куда менее раздражает окружающих, так как запаха почти нет и он не такой противный, а иногда даже приятный.
В общем, если кто-то не может бросить курить обычными способами, рекомендую попробовать вот так. Во-первых, даже если после этого не удастся бросить и парить, это, вроде-бы, не так вредно, во-вторых, вполне вероятно, что путем понижения содержания никотина, можно будет и плавно от него отказаться, чтобы бросить совсем. Ну и для меня, в моей стране, это относительно более дешевый способ получения дозы никотина (правда это зависит от марки используемых расходников и частоты прошлого курения).
вторник, 1 сентября 2015 г.
Внезапный ступор от ssh, su, nohup и &
Сегодня одна вещь заставила поломать голову.
Допустим, у нас есть сервер, на котором есть какой-то шелл-скрипт, который хотят выполнять вот так:
$ ssh user@host sudo ./test.sh
Скрипт, например, содержит строку вида
su -c 'nohup daemon &'
Для проверки концепции я применяю sleep 100, но это не имеет значения:
#!/bin/bash
set -x
su -c 'nohup sleep 100 2>&1 > /dev/null &' root
exit 0
Логично для обычного обывателя предположить, что при выполнении скрипта он запустит некоторую команду, отвяжет ее от терминала и выйдет. Если запустить его из обычного терминала. так и произойдет:
Допустим, у нас есть сервер, на котором есть какой-то шелл-скрипт, который хотят выполнять вот так:
$ ssh user@host sudo ./test.sh
Скрипт, например, содержит строку вида
su -c 'nohup daemon &'
Для проверки концепции я применяю sleep 100, но это не имеет значения:
#!/bin/bash
set -x
su -c 'nohup sleep 100 2>&1 > /dev/null &' root
exit 0
Логично для обычного обывателя предположить, что при выполнении скрипта он запустит некоторую команду, отвяжет ее от терминала и выйдет. Если запустить его из обычного терминала. так и произойдет:
среда, 19 августа 2015 г.
Про Unit-тестирование
Так уж сложилось, что я до этого времени писал довольно-таки много кода в разных мелких и не очень проектах, кусках проектов и прочего и нигде по-настоящему не применял такую штуку как юнит-тестирование. А уж тем более Test-Driven Development. Но для своего воксельного движка я решил попробовать хоть и не TDD, но хотя-бы тестирование разных методов классов. И даже некоторых классов целиком.
Сказать, что это не понравилось, я не могу. По-своему, это, конечно, требует иногда и дополнительных абстракций, которые кажутся совсем ненужными для нормалного, работающего кода, но зато это экономит время. Не так, чтобы прямо экономит время вообще, потому что оно также тратится и на написание и отладку тестов, но зато это позволяет потом в достаточной мере быть уверенным, что "баг где-то в другом месте". Сейчас я применяю тесты, в основном, для того, чтобы убедиться, что у меня правильно посылаются и парсятся отдельные сообщения между клиентом и сервером, или, например, что основные классы с объектами игрового мира правильно определяют координаты и не вылазят за пределы массивов при этом. Удобно то, что это можно сделать без компиляции и запуска всего проекта, включая отдельно сервер и клиент, что занимает, конечно, намного больше времени, чем нажатие Ctrl-F6 в IDE. Также это позволяет убедиться, что ничего не сломалось, после рефакторинга кода.
Конечно, мне даже хотелось сделать какое-то более тщательное покрытие тестами, хотя-бы половины кода, но я пока остановился на наиболее сложных частях кода и тех частях, где уже находились баги (или были сомнения. что они работают правильно). Но пока я пытался прикрутить анализ покрытия тестами, я узнал, что нормально работающий плагин для Maven, который работает с Java7/Java8 сейчас трудно. Emma не умеет 7-ю версию и выше, JaCoCo глючит и не работает, как мне показалось из списка рассылки, с проектами из множества модулей (а мой именно такой). Однако, я все-таки нашел, что Cobertura, во-первых, работает, во-вторых, все-таки встраивается в Netbeans, хотя добиться общего отчета по всем модулям я пока не смог. А еще оно иногда глючит и не работает.
В общем, штука полезная, хотя я к модным мейнстримным вещам всегда отношусь как-то с прохладой. Хотя автоматизация процесса тестирования вещь очевидная :).
вторник, 18 августа 2015 г.
Немного накопленного опыта в работе с трехмерной графикой.
Весьма забавно вышло с кодингом этого воксельного мирка, настолько, что я даже не решался пока что-то писать, а все-таки закончить на каком-то этапе, чтобы остановиться и проанализировать произошедшее.
Переход в 3D оказался неподъемной ношей для моего неопытного организма.
Во-первых, оказалось, что рисовать огромную кучу отдельных кубиков - неподъемная ноша для графического движка JMonkeyEngine. Да и, думаю, для любого другого. Поэтому все нормальные люди превращают кубики в большие наборы, которые называются в Майнкрафте "чанками". Это позволяет еще до рендеринга преобразовать массив кубиков в массив вершин, решить, какие стороны кубиков, в принципе, можно увидеть, преобразовать это в некий объект и загрузить для дальнейшей обработки шейдерами. Поэтому пришлось от "отдельных блоков" отказаться на этапе загрузки всего, что увидит игрок и вместо этого реализовать некоторый "менеджер чанков" и "чанки". Первый нужен для того, чтобы хранить и находить чанки вокруг игрока, решать, что их нет, запрашивать у сервера и удалять из памяти, когда они стали не нужны (игрок ушел за пределы "видимости", скажем). Второй, собственно, занимается хранением отдельных блоков и преобразованием их набора в "mesh", то есть некоторый объемный объект, который содержит несколько VBO, то есть массивов вершин, координат текстур и других данных для обработки в видеокарте.
Вот после их полной загрузки их, в принципе, можно и обновлять отдельными событиями вроде "удалить блок", "добавить блок", "изменить блок". Но тут тоже не все так гладко. В выбранном мной для простоты начинаний JMonkeyEngine3, да и, я думаю, где угодно еще, один Mesh не может содержать множества разных материалов. То есть, на него, в принципе, можно натягивать много разных текстур, используя атлас и натягивая на разные треугольники разные куски этого атласа, но сделать его часть прозрачной, а часть непрозрачной, например, уже сложнее. Все дело, видимо, в том что он целиком обрабатывается одним и тем же набором шейдерных программ. Чтобы это решить, нужно еще крепко подумать.
Первый вариант - выделять из чанка отдельно прозрачные и непрозрачные блоки, например и делать из них два разных "меша", Увеличивает количество VBO, потенциально снижая производительность рендера, зато делать с ними можно что угодно. Второй - считать весь чанк прозрачным и управлять прозрачностью отдельных блоков с помощью альфа-канала текстуры. До этого я еще не дошел и предстоит еще разобраться, какой позволит добиться правильного эффекта.
В общем, из-за перехода от отдельных блоков к чанкам, пришлось еще и реализовать загрузку чанков целиком с сервера. Конечно, это родилось не сразу, а только после того, как я заметил, что стабильной работы при наполнении чанков отдельными блоками не удается достичь, да и загрузка происходит долго (ну, хотя-бы потому что в каждом блоке передаются еще и его координаты, и после приема нужно еще найти чанк, куда его записать и место в чанке, что значительно повышает оверхед). Так что передавая просто набор блоков без координат, зная только координаты одного угла чанка, должно быть намного дешевле, да и потом просто назначить одному из полей чанка массив данных - всего одно присваивание.
Как только эта штука будет способна быстро нарисовать хотя-бы длинное плоское полюшко-поле и позволять перемещаться над ним с подгрузкой/выгрузкой, я считаю, что можно будет это считать какой-то определенной вехой и загрузить код на GitHub после некоторой чистки. Сейчас она это уже умеет, но медленно и с некоторыми багами. Но умеет.
И приступить тогда к решению следующих задач, из коих есть что выбрать.
- Как я уже говорил, мир состоит не из тупо блоков, а из каких-то веществ в каком-то состоянии. Значит, нужно думать, где и как сохранить этот набор веществ и правила, по которым они отображаются. Прозрачные они или нет, какие у них текстуры и все такое прочее. Потом нужно научиться это рендерить. Также важно, может ли игрок двигаться внутри блоков, или должен "сталкиваться" с их границей. Сейчас он просто пролетает сквозь них, это по-своему удобно для отладки одних вещей. но неудобно для отладки других. Значит, и на сервере и на клиенте нужно обнаруживать столкновения и запрещать дальнейшее движение.
- Следующая проблема, это, конечно, тики сервера. Сейчас я их отключил совсем. Нужно их возродить и что-то обрабатывать. Так как блоки пока стали статичными, обрабатывать их нет смысла. Одним из важных параметров мира, как правило, является энергия, например, тепловая энергия. Ее хранение и перенос. Это непростая проблема и интересно она начинает работать только если блоки разные, в том числе, по поведению. Например, нагревающийся газ расширяется. Нагревающаяся вода испаряется.
- Это значит, что без какой-то физической модели, кроме тепловой, обойтись нельзя. Нужно вводить какие-то понятия, во-первых, силы и давления (расширяющися газ), гравитации, импульса, массы, наконец. Появление таких вещей, как гравитации, заставляет задуматься над тем, могут ли двигаться блоки и какие правила при этом действуют. Очевидно, как минимум нетвердые блоки должны двигаться. Или, скажем, не сами блоки, а их содержимое. Пока я не столкнулся еще с проблемами производительности, я бы все-таки попробовал подумать, можно ли реализовать конечную воду, которая течет в соответствии с действием гравитации, пусть даже без "просачивания" в пористые/проницаемые вещества.
- Но все эти вещи трудно смотреть и отлаживать без возможности для игрока ставить и убирать любые блоки. То есть, нужен какой-то "админский" или "божественный" режим, похожий на креатив в Майнкрафте. Для этого нужно, конечно же, реализовать не только такие мелочи как "узнать, в какой блок сейчас смотрит игрок и в какую его плоскость", но и некоторый GUI для выбора, какой вид блока поставить. Возможно, еще какой-то UI для того, чтобы понять, что перед тобой есть.
- Для дальнейшей отладки очень удобно было бы все-таки заиметь текстовую консоль с командами на сервере и на клиенте. И какой-то инструмент для "замера параметров" блока с помощью наведения на него, так как нет смысла передавать все параметры каждого блока и некоторые стоит все-таки передавать по запросу.
- Также ясно, что наличие движения требует синхронизации того, что игрок видит на экране и того, что сервер посчитал у себя. Игрок должен видеть это плавно, сервер должен делать это быстро (потому что игроков может быть более одного), так что это интересная задача, даже если думать только о движении самого игрока. Сейчас, для простоты, игрок просто передает вектор своего относительного движения на каждый апдейт (по сути - фрейм) внутри клиента, что накладно, так как это сотни-тысячи сообщений в секунду. С учетом того, что двигает игрока, на самом деле, сервер, отвечая ему новыми координатами. можно прикинуть, насколько это неоптимально. Конечно, когда FPS начнет проседать, автоматически решится и эта проблема, но зачем надеяться, что ты сделаешь слайд-шоу? :)
- Ну и конечно, за всем этим следует работа над первым этапом генерации мира, на основе самого простого трехмерного шума. Почему так? Да потому что для всех остальных фич все намного сложнее и оно требует хотя-бы их наличия. Не хотелось бы иметь мир, который после генерации и загрузки в память вдруг оказывается нестабильным по действующим законам и требует еще кучу времени, чтобы устаканиться (такое можно иногда в Майнкрафте заметить, когда вдруг в новозагруженных чанках все осыпается и начинает течь с потолка поток лавы).
четверг, 6 августа 2015 г.
Штатуш апдейт
Пока выдалась по-странному свободная минутка, хочу рассказать про
большой фейл с управлением приоритетами. Дело в том, что эта фигня с
кубическим изменяющимя миром, похоже, вызвала у меня страшную
зависимость, и мне хочется без остановки писать код. В связи с чем
появились, похоже, проблемы со всем остальным, отклонения от привычных
распорядков и это, в свою очередь, вызывает стресс. Не делайте так.
Следуйте планам, ибо ущерб всей другой деятельности рано или поздно
начинает сказываться в виде давления на психику, раздражения, депрессии.
Хотя, конечно, как некоторые говорят, это приносит дополнительный опыт, связанный с программированием и геймдевом, это не повод бросать другие проекты. Да и, к тому же, если бы у меня действительно получалось все писать в том темпе, в котором хочется, наверняка все было иначе. Но пока что у меня все перешло, сначала, к безудержному рефакторингу всего, разбиванию на кучу модулей, написание "инфраструктуры" для загрузки и запуска всего и, конечно, в этом всем немало багов появляется, которые не всегда удается быстро и легко вылавливать.
Чтобы решить проблему забрасывания всего остального, пришлось для этого проекта выделить отдельный контекст, чтобы не было лишнего соблазна вместо других вещей заниматься только этой.
В общем, на прошлой неделе я забросил почти все кроме работы и всякой самоучебы и до поздней ночи писал, отлаживал и опять писал. Чем все кончилось, я уже немного открыл в предыдущем посте. С тех пор изменилось мало, единственное, что я начал делать - все-таки добавил блокам понятия "фазового состояния", то есть "пустой, газ, жидкость или твердый", перешел в три измерения, удивился, как все стало намного медленнее из-за 3D. То есть, я уже по-настоящему перешел, со всеми вытекающими в виде увеличения числа итераций по блокам на глубину мира. Здесь, конечно, возник вопрос "что считать глубиной" и вообще, как сделать из такого параметра как "радиус" эту глубину, да так, чтобы мир оставался в виде куба из кубов, а не из параллелепипедов (для удобства). Лучшим решением, как мне показалось, будет вообще забить на "радиус" на этапе выделения блоков и просто считать все за пределами твердой части и атмосферы "пустым". Тем более что радиус, конечно же, намного меньше, чем половина длины окружности, и кроме него в нее укладывается и высота условного верхнего слоя "атмосферы", что лежит в районе линии Кармана, которая находится очень близко над поверхностью, если сравнить с радиусом самой планеты. А чтобы по пустым местам серверу не тикать, просто знать, что там ничего нет и не делать этого.
Конечно, в таком представлении сферического тела как параллелепипеда есть недостатки, но ими можно просто пренебречь для простоты (все-таки это не симулятор). Первый недостаток в том, что нарезка после развертки делает блоки растянутыми у центра шара и "сжатыми" у его краев. То есть, кубометр блока вмещает только долю кубометра реального шара, если говорить о чем-то возле центра планеты, и наоборот, если посмотреть где-то далеко от него.
Также пошла работа над клиент-серверным протоколом, и задуманная изначально модульность (то есть, возможность что-то выключить или добавить путем простого подкидывания файла с кодом), конечно, сразу потребовала синхронизации информации о том, что есть у сервера и клиента, так что на это тоже ушли часы работы. Зато я ожидаю упрощение процесса разработки в будущем, так как вместо ковыряния достаточно малого по объему кода сервера или клиента все ограничится только написанием очередного модуля, который будет дергаться клиентом, сервером, генератором мира и чем угодно еще, если оно требуется, и, конечно, содержать ресурсы вроде текстур. То есть, это возможность делать моды прямо из коробки.
Насчет того, почему блоков захотелось добавить пустых, в виде газов, жидкостей и твердого - сначала мне показалось, что было бы неплохо все-таки поиграть с возможностью плавить и испарять все что угодно, со всеми вытекающими интересностями, вроде того, что вода должна бы таять и замерзать не потому что это "холодный биом", а потому что холодно. Но, конечно, блок не должен, по-идее, сразу переходить весь в какое-то состояние (моментальное испарение на солнце кубометра воды? не, вы чо!), и об этом еще предстоит размышление. Для чего это нужно? Ну хотя-бы чтобы поиграться с настоящим "круговоротом воды", когда она появляется в атмосфере в результате нагрева водоемов, а потом выпадает в виде осадков. Правда, для этого нужна еще одна "фича" в виде состава блока. То есть, воздух это воздух, а не водяной пар, поэтому кроме обычного "воздуха" там должна быть вода, и должна пониматься такая вещь как относительная "влажность". Хотя, скорее, это должно было бы быть какое-то более широкое понятие, которое бы позволяло делать это с любым веществом (и можно было бы варить самогонку в гигантском самогонном аппарате). Но это вызывает одну опасность - стоит просто представить, сколько места в памяти и на диске может занимать один блок, у которого так много аттрибутов. И сколько времени может занимать итерация по ним. И чтобы экономить, нужно будет очень сильно снижать точность вычислений и хранимых значений. Но все-таки "химический состав блока" весьма интересная возможность, особенно если это игра про шахты и копание. Я говорю про ухудшение воздуха в замкнутых пространствах и возможность там тупо задохнуться, и эта возможность весьма важна. Да и грунтовые воды должны быть, все-таки, не в виде вкраплений наполненных водой пещер, а вытекать прямо из не слишком плотных стен. Наверное. Хотя до них еще нужно кучу всего понаписать.
В общем, похоже, нельзя считать блоки только твердыми или только жидкими. В твердых блоках может быть жидкость и она оттуда может вытечь или испариться. В атмосфере может быть водяной пар. В воде может растворяться воздух. Так что, в будущем, похоже придется вместо твердости или жидкости пойти в сторону просто "состава блока", имея в виду наличие нескольких компонентов в разном фазовом состоянии. А рендерить и извлекать основную часть поведения уже от того компонента, который преобладает. Попутно, конечно, подумав, как эти данные хранить компактно, не выделяя под каждый компонент кучу байт.
Да, еще "твердость", она же может быть разной. Это может быть цельный плотный кусок чего-то, а ведь еще "твердыми" свойствами может обладать какая-нибудь щебенка или песок. У такого рода вещей, конечно, свои особенности поведения должны быть. Не так как в Майнкрафте "должно падать вниз", а несколько более продвинуто, потому что, все-таки, мне бы хотелось подумать, как сделать так, чтобы падать вниз должно было все что угодно (и тут должны поныть любители парящих в воздухе островов). В общем, в будущем предстоит раздумье, как эффективно впихнуть в один блок все его свойства и особенности поведения. А потом - как быть и с рукотворными блоками тоже.
Но, надо двигаться постепенно, ведь это прототип. Что-то постоянно меняется и переделывается, выкидывается. Не пойдет такой подход - буду искать другой. Но количество хотелок, конечно, зашкаливает. Обычно это плохо кончается, судя по опыту летсплеев. :)
Хотя, конечно, как некоторые говорят, это приносит дополнительный опыт, связанный с программированием и геймдевом, это не повод бросать другие проекты. Да и, к тому же, если бы у меня действительно получалось все писать в том темпе, в котором хочется, наверняка все было иначе. Но пока что у меня все перешло, сначала, к безудержному рефакторингу всего, разбиванию на кучу модулей, написание "инфраструктуры" для загрузки и запуска всего и, конечно, в этом всем немало багов появляется, которые не всегда удается быстро и легко вылавливать.
Чтобы решить проблему забрасывания всего остального, пришлось для этого проекта выделить отдельный контекст, чтобы не было лишнего соблазна вместо других вещей заниматься только этой.
В общем, на прошлой неделе я забросил почти все кроме работы и всякой самоучебы и до поздней ночи писал, отлаживал и опять писал. Чем все кончилось, я уже немного открыл в предыдущем посте. С тех пор изменилось мало, единственное, что я начал делать - все-таки добавил блокам понятия "фазового состояния", то есть "пустой, газ, жидкость или твердый", перешел в три измерения, удивился, как все стало намного медленнее из-за 3D. То есть, я уже по-настоящему перешел, со всеми вытекающими в виде увеличения числа итераций по блокам на глубину мира. Здесь, конечно, возник вопрос "что считать глубиной" и вообще, как сделать из такого параметра как "радиус" эту глубину, да так, чтобы мир оставался в виде куба из кубов, а не из параллелепипедов (для удобства). Лучшим решением, как мне показалось, будет вообще забить на "радиус" на этапе выделения блоков и просто считать все за пределами твердой части и атмосферы "пустым". Тем более что радиус, конечно же, намного меньше, чем половина длины окружности, и кроме него в нее укладывается и высота условного верхнего слоя "атмосферы", что лежит в районе линии Кармана, которая находится очень близко над поверхностью, если сравнить с радиусом самой планеты. А чтобы по пустым местам серверу не тикать, просто знать, что там ничего нет и не делать этого.
Конечно, в таком представлении сферического тела как параллелепипеда есть недостатки, но ими можно просто пренебречь для простоты (все-таки это не симулятор). Первый недостаток в том, что нарезка после развертки делает блоки растянутыми у центра шара и "сжатыми" у его краев. То есть, кубометр блока вмещает только долю кубометра реального шара, если говорить о чем-то возле центра планеты, и наоборот, если посмотреть где-то далеко от него.
Также пошла работа над клиент-серверным протоколом, и задуманная изначально модульность (то есть, возможность что-то выключить или добавить путем простого подкидывания файла с кодом), конечно, сразу потребовала синхронизации информации о том, что есть у сервера и клиента, так что на это тоже ушли часы работы. Зато я ожидаю упрощение процесса разработки в будущем, так как вместо ковыряния достаточно малого по объему кода сервера или клиента все ограничится только написанием очередного модуля, который будет дергаться клиентом, сервером, генератором мира и чем угодно еще, если оно требуется, и, конечно, содержать ресурсы вроде текстур. То есть, это возможность делать моды прямо из коробки.
Насчет того, почему блоков захотелось добавить пустых, в виде газов, жидкостей и твердого - сначала мне показалось, что было бы неплохо все-таки поиграть с возможностью плавить и испарять все что угодно, со всеми вытекающими интересностями, вроде того, что вода должна бы таять и замерзать не потому что это "холодный биом", а потому что холодно. Но, конечно, блок не должен, по-идее, сразу переходить весь в какое-то состояние (моментальное испарение на солнце кубометра воды? не, вы чо!), и об этом еще предстоит размышление. Для чего это нужно? Ну хотя-бы чтобы поиграться с настоящим "круговоротом воды", когда она появляется в атмосфере в результате нагрева водоемов, а потом выпадает в виде осадков. Правда, для этого нужна еще одна "фича" в виде состава блока. То есть, воздух это воздух, а не водяной пар, поэтому кроме обычного "воздуха" там должна быть вода, и должна пониматься такая вещь как относительная "влажность". Хотя, скорее, это должно было бы быть какое-то более широкое понятие, которое бы позволяло делать это с любым веществом (и можно было бы варить самогонку в гигантском самогонном аппарате). Но это вызывает одну опасность - стоит просто представить, сколько места в памяти и на диске может занимать один блок, у которого так много аттрибутов. И сколько времени может занимать итерация по ним. И чтобы экономить, нужно будет очень сильно снижать точность вычислений и хранимых значений. Но все-таки "химический состав блока" весьма интересная возможность, особенно если это игра про шахты и копание. Я говорю про ухудшение воздуха в замкнутых пространствах и возможность там тупо задохнуться, и эта возможность весьма важна. Да и грунтовые воды должны быть, все-таки, не в виде вкраплений наполненных водой пещер, а вытекать прямо из не слишком плотных стен. Наверное. Хотя до них еще нужно кучу всего понаписать.
В общем, похоже, нельзя считать блоки только твердыми или только жидкими. В твердых блоках может быть жидкость и она оттуда может вытечь или испариться. В атмосфере может быть водяной пар. В воде может растворяться воздух. Так что, в будущем, похоже придется вместо твердости или жидкости пойти в сторону просто "состава блока", имея в виду наличие нескольких компонентов в разном фазовом состоянии. А рендерить и извлекать основную часть поведения уже от того компонента, который преобладает. Попутно, конечно, подумав, как эти данные хранить компактно, не выделяя под каждый компонент кучу байт.
Да, еще "твердость", она же может быть разной. Это может быть цельный плотный кусок чего-то, а ведь еще "твердыми" свойствами может обладать какая-нибудь щебенка или песок. У такого рода вещей, конечно, свои особенности поведения должны быть. Не так как в Майнкрафте "должно падать вниз", а несколько более продвинуто, потому что, все-таки, мне бы хотелось подумать, как сделать так, чтобы падать вниз должно было все что угодно (и тут должны поныть любители парящих в воздухе островов). В общем, в будущем предстоит раздумье, как эффективно впихнуть в один блок все его свойства и особенности поведения. А потом - как быть и с рукотворными блоками тоже.
Но, надо двигаться постепенно, ведь это прототип. Что-то постоянно меняется и переделывается, выкидывается. Не пойдет такой подход - буду искать другой. Но количество хотелок, конечно, зашкаливает. Обычно это плохо кончается, судя по опыту летсплеев. :)
суббота, 1 августа 2015 г.
Не, не выйдет ничего
Итак, я окончательно закопался со своим "невероятно изменчивым миром".
Напомню, что изначальная идея состоит в том, чтобы сделать что-то похожее на Майнкрафт, но отличающееся от него тем, что мир не является чем-то статичным, а изменяется так, что создается ощущение, будто ты находишься в таком месте, где все имеет свои последствия и изменения в одном месте так или иначе немного, но влияют на все остальное. Как - вопрос количества "законов" в этой природе.
Начал я, как было рассказано ранее, с двухмерной плоскости, которая представляла собой некую не очень точную (в силу растянутости у полюсов) развертку поверхности круглой планеты. Плоскость была разбита на квадраты 16х8 с очень хитрой целью. Дело в том, что для меня показалось важным смоделировать так же поток энергии от ближайшей звезды, но, конечно, не абсолютно точно, так как это точно не успевало бы обрабатываться с той скоростью, которая нужна. А вот 16х8 показалось идеальным размером. Дело в том, что одно полушарие, которое освещено сейчас, таким образом сотоит из 8х8 блоков, и они точно делятся на две части в любом направлении. И здесь можно найти зону, в которую лучи падают почти перпендикулярно, то есть, экватор, в котором сейчас полдень и приходит больше всего энергии, места, где солнце уже не в зените или, если смотреть с экватора в сторону полюса, более "тропический" климат. И, конечно, полярные шапки, куда ее поступает меньше всего. Далее я считаю, что блоки, в которых никого нет в данный момент, можно не "уточнять". То есть, достаточно обработать 16х8 блоков, но.
На планете кто-то есть, кто может ее наблюдать и трогать своими грязными руками. Это игроки. Изначально предполагается, что можно уметь в мультиплеер. То есть, точек, в которых может кто-то быть, много.
Чтобы зоны вокруг игроков "уточнить", применялся простой алгоритм пересечения круга (некоего радиуса восприятия игроком) и квадрата, то есть "блока". В случае пересечения считалось, что игрок "чувствует" блок и алгоритм рекурсивно спускался глубже, на уровень своей структуры 8х8, проверяя каждый внутренний блок на предмет пересечения уже с кругом радиусом в 8 раз меньше. Так достигалось постепенное увеличение точности при приближении к игроку. В минимальном радиусе обрабатываются уже конкретные единичные блоки. Все выглядит офигенно просто, но. Рост количества вычислений с ростом числа игроков, которые находятся далеко друг от друга - линейный. Однако, есть плюс - алгоритм обхода "тиками" сервера, как мне кажется, довольно легко рассыпается по отдельным потокам, лишь с учетом блокировок, которые неизбежны при влиянии соседнего блока на текущий обрабатываемый.
Для тестирования производительности применялся довольно-таки простой, но, в то же время, очень нужный изначально алгоритм постепенного "сглаживания" некоего значения между блоками. Нужный он потому, что он неплохо изображает из себя, например, растекание кубометра воды по плоскости, хотя он и предельно упрощен. Также на нем я заткнулся в одну задачу, которая также принципиально важна вообще для идеи.
Задача следующая, состоит из двух частей:
1) Игрок удаляется от блока, из-за чего точность в этом месте должна снизиться. Необходимо "свернуть" всю информацию, которая обрабатывалась перед этим с высоким разрешением в виде, скажем 8х8 блков, в одно значение, которое сохранится теперь в одном "верхнем" блоке, так, чтобы после ее обработки можно было выполнить вторую часть.
2) Игрок возвращается. Нужно снова увеличить разрешение, сделав из одного значения снова 8х8. При этом должно быть максимально достигнуто ощущение, что все обрабатывалось как раньше.
Скажу сразу, наскоком изобрести "правдоподобное" не удалось.
Далее попытался перейти в 3D, для более удобного рассматривания результатов. То что делалалось на плоскости, стало сложнее. Хотя я не сделал все структуры трехмерными (и рисовал просто "пластинку" верхнего словя), и даже не перешел к поиску способа впихнуть все вышеописанное в трехмерность, у меня уже возникла проблема, как передать клиенту только то, что он и правда может увидеть. То есть, нужен рейтрейсинг/рейкастинг или какой угодно еще алгоритм. Причем, видимо, он должен работать на сервере, чтобы не гонять лишние данные по сети. Либо, второй вариант, нужно найти все, что обрабатывалось из-за него сервером и передать всю эту кучу блоков-подблоков, а он уже пусть там сам разбирается. Тут, кстати, несколько решений пришло в голову, начиная с простого обхода некоторой зоны вокруг игрока с загрузкой только того, что "обработано", до запихивания ссылок на каждый обрабатываемый блок прямо в объект игрока для передачи прямо сейчас (он кажется проще и делает меньше дополнительных "обходов"). Оба варианта, скажем так, будут "тестироваться". Пока что тестируется второй. Однако, все равно не ясно пока, как просто и дешево потом в клиенте избавляться от "невидимого", а также более "крупных" блоков при получении мелких.
Но, в целом, создается впечатление, что со всем таким не справится даже топовое железо.
Напомню, что изначальная идея состоит в том, чтобы сделать что-то похожее на Майнкрафт, но отличающееся от него тем, что мир не является чем-то статичным, а изменяется так, что создается ощущение, будто ты находишься в таком месте, где все имеет свои последствия и изменения в одном месте так или иначе немного, но влияют на все остальное. Как - вопрос количества "законов" в этой природе.
Начал я, как было рассказано ранее, с двухмерной плоскости, которая представляла собой некую не очень точную (в силу растянутости у полюсов) развертку поверхности круглой планеты. Плоскость была разбита на квадраты 16х8 с очень хитрой целью. Дело в том, что для меня показалось важным смоделировать так же поток энергии от ближайшей звезды, но, конечно, не абсолютно точно, так как это точно не успевало бы обрабатываться с той скоростью, которая нужна. А вот 16х8 показалось идеальным размером. Дело в том, что одно полушарие, которое освещено сейчас, таким образом сотоит из 8х8 блоков, и они точно делятся на две части в любом направлении. И здесь можно найти зону, в которую лучи падают почти перпендикулярно, то есть, экватор, в котором сейчас полдень и приходит больше всего энергии, места, где солнце уже не в зените или, если смотреть с экватора в сторону полюса, более "тропический" климат. И, конечно, полярные шапки, куда ее поступает меньше всего. Далее я считаю, что блоки, в которых никого нет в данный момент, можно не "уточнять". То есть, достаточно обработать 16х8 блоков, но.
На планете кто-то есть, кто может ее наблюдать и трогать своими грязными руками. Это игроки. Изначально предполагается, что можно уметь в мультиплеер. То есть, точек, в которых может кто-то быть, много.
Чтобы зоны вокруг игроков "уточнить", применялся простой алгоритм пересечения круга (некоего радиуса восприятия игроком) и квадрата, то есть "блока". В случае пересечения считалось, что игрок "чувствует" блок и алгоритм рекурсивно спускался глубже, на уровень своей структуры 8х8, проверяя каждый внутренний блок на предмет пересечения уже с кругом радиусом в 8 раз меньше. Так достигалось постепенное увеличение точности при приближении к игроку. В минимальном радиусе обрабатываются уже конкретные единичные блоки. Все выглядит офигенно просто, но. Рост количества вычислений с ростом числа игроков, которые находятся далеко друг от друга - линейный. Однако, есть плюс - алгоритм обхода "тиками" сервера, как мне кажется, довольно легко рассыпается по отдельным потокам, лишь с учетом блокировок, которые неизбежны при влиянии соседнего блока на текущий обрабатываемый.
Для тестирования производительности применялся довольно-таки простой, но, в то же время, очень нужный изначально алгоритм постепенного "сглаживания" некоего значения между блоками. Нужный он потому, что он неплохо изображает из себя, например, растекание кубометра воды по плоскости, хотя он и предельно упрощен. Также на нем я заткнулся в одну задачу, которая также принципиально важна вообще для идеи.
Задача следующая, состоит из двух частей:
1) Игрок удаляется от блока, из-за чего точность в этом месте должна снизиться. Необходимо "свернуть" всю информацию, которая обрабатывалась перед этим с высоким разрешением в виде, скажем 8х8 блков, в одно значение, которое сохранится теперь в одном "верхнем" блоке, так, чтобы после ее обработки можно было выполнить вторую часть.
2) Игрок возвращается. Нужно снова увеличить разрешение, сделав из одного значения снова 8х8. При этом должно быть максимально достигнуто ощущение, что все обрабатывалось как раньше.
Скажу сразу, наскоком изобрести "правдоподобное" не удалось.
Далее попытался перейти в 3D, для более удобного рассматривания результатов. То что делалалось на плоскости, стало сложнее. Хотя я не сделал все структуры трехмерными (и рисовал просто "пластинку" верхнего словя), и даже не перешел к поиску способа впихнуть все вышеописанное в трехмерность, у меня уже возникла проблема, как передать клиенту только то, что он и правда может увидеть. То есть, нужен рейтрейсинг/рейкастинг или какой угодно еще алгоритм. Причем, видимо, он должен работать на сервере, чтобы не гонять лишние данные по сети. Либо, второй вариант, нужно найти все, что обрабатывалось из-за него сервером и передать всю эту кучу блоков-подблоков, а он уже пусть там сам разбирается. Тут, кстати, несколько решений пришло в голову, начиная с простого обхода некоторой зоны вокруг игрока с загрузкой только того, что "обработано", до запихивания ссылок на каждый обрабатываемый блок прямо в объект игрока для передачи прямо сейчас (он кажется проще и делает меньше дополнительных "обходов"). Оба варианта, скажем так, будут "тестироваться". Пока что тестируется второй. Однако, все равно не ясно пока, как просто и дешево потом в клиенте избавляться от "невидимого", а также более "крупных" блоков при получении мелких.
Но, в целом, создается впечатление, что со всем таким не справится даже топовое железо.
Подписаться на:
Сообщения (Atom)