Я работаю над простой 2D-стратегией в реальном времени с использованием XNA. Прямо сейчас я достиг точки, когда мне нужно иметь возможность щелкнуть спрайт для единицы или здания и иметь возможность ссылаться на объект, связанный с этим спрайтом. Из исследований, которые я провел за последние три дня, я нашел много ссылок на то, как делать «Выбор мыши» в 3D, которые, похоже, не применимы к моей ситуации. Я понимаю, что еще один способ сделать это - просто иметь массив всех «выбираемых» объектов в мире, и когда игрок нажимает на спрайт, он проверяет местоположение мыши по отношению к местоположениям всех объектов в массиве. проблема, с которой я столкнулся при таком подходе, заключается в том, что он станет довольно медленным, если количество юнитов и зданий вырастет до больших чисел. (это также не кажется очень элегантным), так что я мог бы сделать это другими способами. (Обратите внимание, что я также работал над идеями использования хэш-таблицы для связывания объекта с местоположением спрайта и использования двумерного массива, где каждое местоположение в массиве представляет один пиксель в мире. неуклюжие способы делать вещи.)
Выбор мыши XNA 2D
Ответы (3)
Для сотен единиц достаточно просто выполнить линейный поиск O(n) по всем единицам в мире, если области щелчка представляют собой круги или прямоугольники. Тем более, что это будет один раз за клик, а не один раз за кадр.
Если ваши единицы не являются круглыми или прямоугольными, сначала проверьте ограничивающий круг или прямоугольник, и если это пройдет, проверьте более сложную ограничивающую форму.
Для более подробного ответа вот мой ответ на аналогичный вопрос о разделении пространства. Там я упоминаю сетки с сегментами и деревья квадрантов как потенциальные структуры для оптимизации производительности.
Но вы никогда не должны оптимизировать производительность, пока не протестируете и на самом деле не столкнетесь с проблемой производительности!
Если у вас есть класс, который управляет объектами drawabel, у вас может быть статический int, который вы увеличиваете каждый раз, когда создаете новый объект, и сохраняете старый как локальный экземпляр Color в объекте drawabel. Затем вы можете использовать преобразователь типов .Net, чтобы преобразовать его в массивы до свидания и обратно, не помню его имени, и я разговариваю по телефону в поезде, поэтому не могу проверить вас, я боюсь.
Когда вы строите цвет из массива байтов, просто не забудьте максимизировать альфа-канал, и если вы получите слишком много объектов, вы можете выйти за пределы индексов, которые вы можете использовать. снова потребуйте новые цвета с 0:0:0:255, так как, надеюсь, некоторые старые больше не используются: P
Не уверен, что я имел большой смысл, но так как я в поезде, это все, что я могу вам сказать, извините :)
Вы можете использовать идеальный выбор пикселей, который очень хорошо масштабируется для огромного количества объектов (и имеет преимущество в том, что он идеален для пикселей).
По сути, вы визуализируете свою сцену, используя уникальный цвет для каждого объекта. Затем вы разрешаете задний буфер в текстуру и возвращаете данные текстуры, наконец, вы можете просто проверить пиксель под мышью и узнать, на каком объекте находится мышь.
Вы можете быть умны с информацией, которую вы возвращаете, вы можете запросить только один пиксель, над которым находится мышь.
Color[] pixel = new Color[1];
texture.GetData(pixel, mousePosition.Y * texture.Width + mousePosition.x, 1);
//pixel[0] == colour of the item the mouse is over. You can now look this up in a dictionary<Color, item>
Вы должны быть осторожны, чтобы не остановить конвейер, делая это (заставляя ЦП ждать, пока ГП отобразит что-то). Лучший способ сделать это — переключиться между двумя целями рендеринга и всегда получать данные из цели рендеринга, которую вы использовали в последнем кадре, это означает, что данные устарели на один кадр, но ни у одного человека нет достаточно быстрой реакции, чтобы это заметить.
Дополнение в ответ на ваш комментарий.
Чтобы присвоить уникальный цвет каждому объекту, просто увеличьте байт для каждого объекта. Когда этот байт переполняется, увеличьте другой, а когда этот байт переполняется, увеличьте другой; Затем вы можете использовать эти три байта как красный, зеленый и синий. Помните, чтобы поддерживать альфу на максимальном значении, вы не хотите видеть сквозь объекты!
Чтобы решить проблему, задний буфер немного изменен в XNA4. Теперь вы должны отрендерить в rendertarget и разрешить это. Сделать это довольно просто, и это описано Шоном Харгривзом здесь