Я хочу нарисовать невидимый путь, по которому должен следовать пользователь. Я сохранил этот путь в виде точек. Когда игрок рисует линию, как я могу проверить, следует ли он по пути, который я сохранил?
Вот пример для отслеживания буквы А.
if((traitSprite.getX()<=Invisible.X && traitSprite.getX()>=Invisible.X )){...}
( traitSprite
это спрайт.)
libgdx
algorithm
vector
hand-drawn
Android
источник
источник
Ответы:
Вот векторное решение. Я не пробовал, но концептуально это выглядит нормально.
теория
Я полагаю, вы сохранили форму в виде отрезков. Вот буква А, представленная тремя отрезками.
Я предположил, что пути на чертеже пользователя хранятся в виде списков точек.
Мы можем «раздувать» эти отрезки, чтобы допустить допустимый предел погрешности при проверке на близость : находится ли нарисованный пользователем путь рядом с правильным пределом погрешности линий.
Однако одного этого недостаточно. Мы также должны проверить покрытие : покрывает ли пользовательский рисунок большую часть фигуры. Эти рисунки плохие, потому что, хотя они вписываются в поле ошибки, они пропускают некоторую часть буквы:
Если мы проверим обе эти вещи, мы можем приблизиться, если рисунок игрока хорош.
Реализация
Проверять близость означает только для каждой точки пути пользователя, находить расстояние между этой и каждой линией, составляющей букву, брать самую низкую и проверять, что она меньше допустимой погрешности.
Проверка покрытия более сложна, но вы можете получить очень хорошее приближение с векторной математикой, если для каждого отрезка линии вы найдете ближайший нарисованный пользователем путь (зеленый) и спроецируйте его части (темно-зеленый) на этот отрезок (черный), затем проверьте, насколько хорошо проецируемые векторы (синие) покрывают его:
Чтобы спроецировать вектор
a
на другой векторb
, выполнитегде
dotProduct
вычисляет скалярное произведение двух векторов иlengthSquared
как оно звучит. По сути, это находит скалярное значение того, сколькоa
идет вb
направлении и умножаетсяb
на это, чтобы получить вектор в том же направлении. ( Учебное пособие A по обнаружению столкновений Metanet Software имеет хорошую визуализацию этого в Приложении A § проекция .)Направление проецируемого вектора может не иметь большого значения. Если вы просто суммируете длины спроецированных векторов и сравниваете их с общей длиной отрезка, это скажет вам, какая его часть покрыта. (За исключением странных случаев - см. § Ограничения ниже).
На изображении выше, путь будет охватывать около половины сегмента. Вы можете выбрать любое значение допуска, которое вы хотите.
Ограничения
Изогнутые буквы
Сегменты линий неидеальны: многие буквы изогнуты! Как вы представляете «P» или «O»?
Вы можете использовать много отрезков (возможно, с большей погрешностью).
Вы также могли бы начать использовать кривые Безье вместо линий для более тесной подгонки, но обратите внимание , что найти ближайшую точку на Безье является гораздо более сложным, как и многие другие операции измерения.
Несоответствия
Чрезмерно ослабленные границы допуска для расстояния от линий и покрытия письма могут иметь непреднамеренные последствия.
Например, игрок, возможно, пытался нарисовать здесь «Н».
Петли и перекрытия
Петли или перекрытия на нарисованном игроком пути могут привести к тому, что некоторые части рисунка будут засчитаны дважды при проецировании их на ближайший отрезок.
Эту проблему можно обойти, выполнив более сложную обработку проецируемых векторов, возможно, сохранив точно, где будет находиться проецируемый вектор (сохраните также направление проекции и ближайшую точку на отрезке линии к точке на нарисованной игроком линии) , а затем отвергая новые, которые перекрывают его.
Если игрок нарисовал один путь, и он был обработан, начиная с конца, отмеченного синим кружком, зеленые части этого пути будут приняты, а красные отклонены, потому что их проекция будет перекрываться с некоторыми деталями, обработанными ранее.
Реализация имеет много технических тонкостей, которые, вероятно, принадлежат другому вопросу.
Непредсказуемо авантюрные игроки
Игрок может нарисовать что-то странное, что все еще проходит .
Хотя это можно назвать функцией! :)
источник
Я предлагаю сделать кисть игроков краской видимой (или невидимой) 2D-плоскости. Различайте нарисованное пользователем изображение с происхождением (желаемый силуэт или 2d модель). Если вы хотите повысить точность, сделайте направляющие линии и кисть более узкими, чтобы оставить больше места для ошибок, сделайте кисть и дизайн более толстыми.
В противном случае вы могли бы измерить расстояние каждого (x, y) пользователя, нажимающего / касающегося от сплайна, вычисляя расстояние от точки до сегмента. Затем вы можете усреднить расстояния, чтобы составить меру точности и эффективности. Потребуется больше работы, чтобы получить значимую меру завершения и понять, насколько эффективно пользователь выполнил.
Внимание: я предлагаю не делать этого (проверять непосредственно, следует ли линия по пути). Возможно, это плохая идея. Кажется, вы хотите, чтобы пользователь заполнил силуэт. Сам путь представляет собой (скелетный) сплайн, представляющий силуэт.
Если вы просто заставите кисть игроков применить толстую монохромную пиксельную массу к 2-й плоскости, вы можете запустить процесс в фоновом режиме, который проверяет, сколько пикселей находится внутри силуэта, а сколько - снаружи. Это может легко привести к% успеха, где процент заполнения шаблона - это одна интересная статистика, а другой - сколько% находится за пределами модели. Если вы проверяете расстояние между подсегментами, это не очень понятно, насколько точна работа пользователей.
источник
Лучшее решение вообще не использовать графику, делай это с математикой!
Вы можете легко понять, насколько каждая точка (нарисованная пользователем) находится далеко от сегмента /programming/849211/shortest-distance-between-a-point-and-a-line-segment
Что вы можете рассчитать среднюю ошибку, поэтому измерьте, насколько пользователь прав.
источник