Как я могу проверить, следует ли линия, нарисованная игроком, по пути?


8

Я хочу нарисовать невидимый путь, по которому должен следовать пользователь. Я сохранил этот путь в виде точек. Когда игрок рисует линию, как я могу проверить, следует ли он по пути, который я сохранил?

Вот пример для отслеживания буквы А.

пример трассировки

if((traitSprite.getX()<=Invisible.X  && traitSprite.getX()>=Invisible.X )){...}

( traitSpriteэто спрайт.)


Как вы храните путь, которым должна следовать нарисованная линия игрока? Это то, что спрайт?
Анко

нет, это точки, которые я ввел вручную. это плохая идея, но я думаю, что использование «Vector2» будет эффективным решением, но я не знаю, как его использовать.
Android

Ответы:


12

Вот векторное решение. Я не пробовал, но концептуально это выглядит нормально.

теория

Я полагаю, вы сохранили форму в виде отрезков. Вот буква А, представленная тремя отрезками.

отрезки, представляющие букву

Я предположил, что пути на чертеже пользователя хранятся в виде списков точек.

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

«раздутые» отрезки нарисованный пользователем путь вверху буквы с полями ошибок

Однако одного этого недостаточно. Мы также должны проверить покрытие : покрывает ли пользовательский рисунок большую часть фигуры. Эти рисунки плохие, потому что, хотя они вписываются в поле ошибки, они пропускают некоторую часть буквы:

плохие рисунки

Если мы проверим обе эти вещи, мы можем приблизиться, если рисунок игрока хорош.

Реализация

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

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

проверка покрытия по векторной проекции

Чтобы спроецировать вектор aна другой вектор b, выполните

projection = dotProduct(a, b) / lengthSquared(b) * b

где dotProductвычисляет скалярное произведение двух векторов и lengthSquaredкак оно звучит. По сути, это находит скалярное значение того, сколько aидет в bнаправлении и умножается bна это, чтобы получить вектор в том же направлении. ( Учебное пособие A по обнаружению столкновений Metanet Software имеет хорошую визуализацию этого в Приложении A § проекция .)

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

На изображении выше, путь будет охватывать около половины сегмента. Вы можете выбрать любое значение допуска, которое вы хотите.

Ограничения

Изогнутые буквы

Сегменты линий неидеальны: многие буквы изогнуты! Как вы представляете «P» или «O»?

Вы можете использовать много отрезков (возможно, с большей погрешностью).

буква P аппроксимируется отрезками буква О, аппроксимированная отрезками

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

Несоответствия

Чрезмерно ослабленные границы допуска для расстояния от линий и покрытия письма могут иметь непреднамеренные последствия.

Например, игрок, возможно, пытался нарисовать здесь «Н».

буква H ошибочно распознается как буква A

Петли и перекрытия

зацикливание и перекрытие (возможно) распознанной буквы

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

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

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

отклонение петель и перекрытий

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

Непредсказуемо авантюрные игроки

Игрок может нарисовать что-то странное, что все еще проходит .

trolololol

Хотя это можно назвать функцией! :)


спасибо, что вы предлагаете не рисовать за пределами письма?
Android

@Android Оранжевые "поля ошибок" для этого. Вы можете отказаться от линии , которые выходят за пределы их: как это , например.
Анко

Я хочу сделать букву SpriteBatch, тогда единственная область, в которой я могу нарисовать, - это спрайт-партия, которая может принимать форму A или B, X .... это возможно? если это как я могу сделать текстуру, как SpriteBatch? и спасибо заранее.
Android

2

Я предлагаю сделать кисть игроков краской видимой (или невидимой) 2D-плоскости. Различайте нарисованное пользователем изображение с происхождением (желаемый силуэт или 2d модель). Если вы хотите повысить точность, сделайте направляющие линии и кисть более узкими, чтобы оставить больше места для ошибок, сделайте кисть и дизайн более толстыми.

В противном случае вы могли бы измерить расстояние каждого (x, y) пользователя, нажимающего / касающегося от сплайна, вычисляя расстояние от точки до сегмента. Затем вы можете усреднить расстояния, чтобы составить меру точности и эффективности. Потребуется больше работы, чтобы получить значимую меру завершения и понять, насколько эффективно пользователь выполнил.


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

Если вы просто заставите кисть игроков применить толстую монохромную пиксельную массу к 2-й плоскости, вы можете запустить процесс в фоновом режиме, который проверяет, сколько пикселей находится внутри силуэта, а сколько - снаружи. Это может легко привести к% успеха, где процент заполнения шаблона - это одна интересная статистика, а другой - сколько% находится за пределами модели. Если вы проверяете расстояние между подсегментами, это не очень понятно, насколько точна работа пользователей.


1

Лучшее решение вообще не использовать графику, делай это с математикой!

Вы можете легко понять, насколько каждая точка (нарисованная пользователем) находится далеко от сегмента /programming/849211/shortest-distance-between-a-point-and-a-line-segment

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


спасибо, а что за буквы типа "C", "O"? ... между точками нет фиксированного расстояния ..
Android

Вы можете сделать «C» и «O» из 6-8 отрезков, как и другие, но математика будет немного отличаться в смысле измерения ошибок
Алексей Шестаков
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.