Как реализовать мягкие краевые области с частицами

13

Моя игра создана с использованием Phaser, но сам вопрос не зависит от движка.

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

введите описание изображения здесь

Твердый край выглядит плохо. Я хотел бы улучшить ситуацию, выполнив две вещи: 1. Сделайте так, чтобы область заливки многоугольника имела мягкий край и сливался с фоном. 2. Сделайте так, чтобы некоторые осколки вышли из области многоугольника, чтобы они не были разрезаны посередине, и у области не было прямой линии

например (макет):

введите описание изображения здесь

Я думаю, что 1 можно достичь с помощью размытия многоугольника, но я не уверен, что делать с 2.

Как бы вы пошли на реализацию этого?

OpherV
источник
2
Это выглядит потрясающе. Могу ли я получить ссылку на вашу игру, пожалуйста? :)
ashes999
@GameAlchemist Вот изображение плитки i.imgur.com/y54CeQ9.png
OpherV
@ ashes999 Это все еще в стадии разработки. Я обязательно
опубликую
Обратите внимание, что это прозрачный PNG с белыми объектами. Если вы просматриваете его на белом фоне (как это часто бывает при открытии картинки в браузере), вы ничего не увидите
OpherV
@OpherV это было бы здорово. Пожалуйста, просто отредактируйте свой вопрос и
опубликуйте

Ответы:

2

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

Визуализируйте ваши частицы в форме многоугольника на текстуре RenderTexture. Обязательно используйте присадки, смешивающиеся с частицами. Частицы внутри многоугольника будут плавно сливаться друг с другом, в то время как частицы снаружи дадут желаемый мягкий край. (Пример этого эффекта можно посмотреть в этом видео на YouTube: Видео аддитивных частиц Теперь визуализируйте RenderTexture на главном экране, и все готово. RenderTexture необходима, чтобы частицы не смешивались с вашим фоном.

Вы можете попробовать поместить треугольники непосредственно на текстуру частицы и посмотреть, как это работает. В противном случае визуализируйте их поверх вашего «супа из частиц» как отдельный слой.

Создан быстрый макет в обновленном jsfiddle, который выглядит следующим образом. демонстрация Обновленную демонстрацию можно найти здесь.

2. Каждая частица имеет скорость и происхождение. Когда ваш игрок касается многоугольника, вы изменяете скорость каждой частицы пропорционально скорости игрока. Чем дальше частица от вашего игрока, тем меньше на нее влияет скорость игроков.

Формула для расчета скорости частиц будет выглядеть примерно так:

//player.velocity and particle.velocity are vectors 
//k is a factor to enhance or weaken the influence of players velocity
var distanceToPlayer = (player.position - particle.position).length();
particle.velocity = particle.velocity + ((k * player.velocity) + particle.velocity) * (1/distanceToPlayer);

Чтобы вычислить положение частицы, вы положили это в свой метод обновления:

var speedY = -(springConstant * (particle.position.y - particle.origin.y)) - (dampingFactor * particle.velocity.y);
var speedX = -(springConstant * (particle.position.x - particle.origin.x)) - (dampingFactor * particle.velocity.x);

particle.position.y = particle.position.y + speedY;
particle.position.x = particle.position.x + speedX;

particle.velocity.x = particle.velocity.x + speedX;
particle.velocity.y = particle.velocity.y + speedY;

Это должно дать вам «жидкость», где каждая частица вращается вокруг своего источника, когда игрок размешивает жидкость. SpringConstant изменяет, насколько частица отклоняется от своего начала, а коэффициент демпфирования - как быстро частица останавливается. Возможно, вам придется настроить код, поскольку он является модифицированной версией 1d-симуляции, которую я использую в своей игре.

Теперь с демо: Демо Просто настройте 3 константы в верхней части, пока жидкость не будет вести себя так, как вы этого хотите.

zilluss
источник
Это действительно интересная идея, чтобы решить # 1! Мне это нравится. Как бы вы предложили реализовать движение \ интервал треугольника?
OpherV
1
Я отредактировал оригинальное сообщение, чтобы ответить на вопрос № 2.
zilluss
добавлена ​​небольшая демонстрация эффекта частиц. Я думаю, что вы могли бы получить желаемый эффект с небольшой настройкой.
Zilluss
Я закончил тем, что использовал ваше решение, оно ближе всего к тому результату, которого я стремился достичь. Благодарность! Однако один вопрос - как бы я ограничил упругость в ваших примерах, чтобы действительно легкие движения не заставляли частицы прыгать на такие огромные расстояния?
OpherV
Вы можете поиграть с помощью фактора демпфирования и SpringConstant. Сильное демпфирование позволит частицам быстрее отдыхать. Чем ниже пружина, тем ниже скорость частиц. К сожалению, оба значения позволяют супу частиц чувствовать себя более вязким. Таким образом, вместо этого, когда ваш игрок касается частицы, вы можете зафиксировать максимальную скорость, которую игрок добавляет к этой частице, например :icle.velocity.x = зажим (maxVelocity, -maxVelocity ,icle.velocity.x + ((playerInfluenceFactor * deltaVelocityX) ) +icle.velocity.x) * (1 / distanceToPlayer)); для зажима см .: stackoverflow.com/a/11409944
zilluss
4

Мои мысли об этих двух моментах:

  1. Вы можете использовать шейдерное размытие, но это будет очень дорого. Вместо этого я бы нарисовал дополнительную границу треугольников, которые постепенно переходят от полупрозрачного в центре к прозрачному по краям, чтобы имитировать «размытие». Я сделал это в моей игре, и она работает довольно хорошо. Вот два скриншота бустера в моей игре.

    введите описание изображения здесь введите описание изображения здесь

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

  2. Я запрограммировал бы систему частиц и заставил бы частицы следовать за многоугольником. При этом вам не нужно беспокоиться о том, что произойдет на краях. Динамика вашей системы частиц обеспечит равномерное распределение частиц внутри многоугольника. Вы можете попытаться заставить ближайшие частицы оттолкнуть друг друга, но сделайте это с большой «массой», чтобы у вас была инерция, и она выглядела гладкой. Чтобы сделать это быстро, есть некоторые возможности, но большой проблемой будет временная сложность механизма толкания друг друга. Если вы заставите каждую частицу толкать каждую другую частицу, у вас будет O (n ^ 2), что не хорошо, если в вашей системе, например, 100 частиц. Хорошее чтение о том, как вы можете оптимизировать, это презентация PixelJunk:http://fumufumu.q-games.com/gdc2010/shooterGDC.pdf

    Более простой подход заключается в соединении каждой частицы с тремя или четырьмя другими частицами при построении системы частиц. Теперь каждой частице нужно будет толкнуть только четыре другие частицы, с которыми она связана. Однако такой подход делает турбулентность в вашей системе частиц невозможной. Но это, похоже, не проблема, поскольку в вашей текущей ситуации используется статическая текстура. Этот подход будет O (n), что здорово.

Мартейн Курто
источник
Благодарность! 1. Мне трудно это визуализировать. Можете ли вы опубликовать макет, как это выглядит \ работает в вашей игре? 2. Интересно! прочтем об этом
OpherV
Спасибо за изображения. Я могу видеть, как это будет работать в форме трубки или линии, но как это будет работать с многоугольником? Разве градиенты треугольников, проецируемых с каждой стороны, не выстроятся в линию хорошо?
OpherV
Сделай так, чтобы они хорошо сидели Это идея. Это включает в себя некоторые математические и вычислительные точки пересечения и т. Д. Вы также можете разделить границу и сгладить ее. Тонны возможностей.
Мартин Курто
3

При прочтении вашего поста у меня возникла следующая идея:
• создать набор плиток, которые вы будете использовать для своих областей.
• визуализировать многоугольник области на небольшом временном холсте с разрешением плитки (например: если плитки имеют размер 16X16, рендеринг с более низким разрешением (16X, 16X)).
• использовать этот временный холст, чтобы решить, будет ли он отображать листы или нет на основном холсте:
если на холсте с низким разрешением установлена ​​точка, нарисуйте «случайный» лист на главном холсте. если точка является просто соседом заданной точки, нарисуйте «случайную» плитку с меньшей непрозрачностью (чтобы сделать переход) на главном холсте.

Я боялся, что снижение разрешения создаст эффект блока, но даже с плитками 20X20 это выглядит довольно хорошо:

введите описание изображения здесь

Шаги для этого: взять свой полигон:
введите описание изображения здесь

Нарисуйте многоугольник с вашим разрешением плитки: введите описание изображения здесь(!! Да, это красный цвет).

Затем используйте imageData холста низкого разрешения, чтобы решить, рисовать ли плитку или заметку.
Если на холсте с низким разрешением установлен пиксель, это означает, что мы должны нарисовать плитку: выберите «случайный» индекс плитки, чтобы выбрать, какую плитку рисовать. Этот случайный индекс всегда должен быть одинаковым для данной области / плитки.
Если точка пуста, но рядом с заполненной точкой, также нарисуйте плитку, но с полупрозрачностью.

введите описание изображения здесь

Итак, давайте нарисуем плитки:

введите описание изображения здесь

Для многоугольника я просто рисую несколько раз многоугольник, уменьшая его масштаб и увеличивая непрозрачность при каждом прорисовке (можно также использовать globalCompositeOperation «светлее»).

введите описание изображения здесь

Как только вы сложите все, это дает:

введите описание изображения здесь

скрипка здесь:

http://jsfiddle.net/gamealchemist/T7b4Y/

Позвольте мне знать, если это помогает.

GameAlchemist
источник
Спасибо за разработку вашего решения и предоставление кода! Что вы подразумеваете под «Затем используйте imageData холста низкого разрешения, чтобы решить, рисовать ли плитку или заметку». Как вы используете данные маленького изображения, чтобы решить, где \ как нарисовать большое изображение? И используя этот метод, как я могу избежать наложения треугольников, чтобы достичь расстояния, аналогичного моему макету?
OpherV
Я имею в виду, что это полный логический тест: мне нужно заполнить эту плитку? , true или false, определяется тестом низкого разрешения для imageData [(x + y * width) * 4]! = 0, то есть == 'рисовал ли я что-то на нижнем холсте в это место плитки? Затем, если да, я использую некоторую сложную формулу, заполненную простыми числами (getRandomNumber), чтобы перейти от (x, y) к «случайному» индексу плиток, который всегда будет предоставлять одно и то же число для данной области + (x, y). Я не понимаю, как все может перекрываться, если вы правильно определите свой многоугольник, поэтому я не получу ваш второй вопрос.
GameAlchemist
1

Просто идея:

В вашей плитке «кусочки» имеют максимальную ширину около 80 пикселей. Я бы предложил сделать 2 зоны. Вы рисуете свой оригинальный многоугольник и создаете его макет примерно в 80 пикселях от каждого края. Вы тогда тянете свои плитки в больший многоугольник.

Затем, все «кусочки», которые имеют пиксель за пределами внутреннего многоугольника и не имеют пересечения с внутренним многоугольником, который можно заливать, заполняют их прозрачностью.

Это очень высокий уровень, но я решил поделиться этим с вами. Здесь очень много деталей, которые нужно определить.

Грубое изображение для демонстрации:

введите описание изображения здесь

Если бы внутренний черный полигон был оригиналом, вы бы стерли все полигоны с красной точкой.

user46560
источник
Как бы вы проверили пересечение частей, встроенных в изображение плитки с внутренним многоугольником?
OpherV
@OpherV Хм, Вы можете определить, находится ли точка X в многоугольнике, верно? Вы можете перебрать все пиксели во внешнем многоугольнике, и для каждого белого пикселя затопить проверить все пиксели и посмотреть, не лежат ли они во внутреннем / наружном. Это звучит не очень эффективно, но когда у вас есть что-то, вы можете подумать о способах оптимизации?
user46560
Это постобработка, выполняемая на процессоре. Вряд ли оптимизируем по себе. Ваша идея может хорошо работать, если внутренний многоугольник и внешний соединены треугольной полосой. ОП может добавить информацию об атрибуте вершины и пометить каждую вершину как внутри, так и снаружи. Затем в вершинном шейдере непрозрачность / альфа можно линейно интерполировать от менее прозрачного значения до полного непрозрачного.
Теодрон
@teodron Это то, что я пытался сделать в ответе. Это идея высокого уровня, и я на самом деле не разработчик игр. У меня только что была идея.
user46560
@ user46560 да, но таким образом вам вообще не нужно вычислять, какие пиксели находятся в этой межполигональной полосе .. ни на GPU, ни на CPU. Поскольку вы не привыкли к способам разработки игр, как вы говорите, вы заслуживаете +1 за вашу идею :).
Теодрон