Вопрос

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

Возможно, есть ли способ иметь второй прозрачный компонент в игровом окне (JPanel), который не влияет на игровой процесс, но регистрируется, когда мышь покидает внутренний компонент через MouseAdapter.mouseEntered () / mouseExited ()?

boolean mouseOnScreen;
boolean mouseWithinInnerComponent; //is (10 <= mouse.x <= screenWidth - 10) && (10 <= mouse.y <= screenHeight)

if(mouseOnScreen && !mouseWithinInnerComponent)
{
    //do something...
}

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

boolean mouseOnScreen;
boolean mouseWithinTopComponent; //is (0 <= mouse.y <= 10)
boolean mouseWithinBottomComponent; //is (screenHeight - 10 <= mouse.y <= screenHeight)
boolean mouseWithinLeftComponent; //is (0 <= mouse.x <= 10)
boolean mouseWithinRightComponent; //is (screenWidth - 10 <= mouse.x <= screenWidth)

if(mouseOnScreen)
{
    if(!mouseWithinBottomComponent)
    {
        //move view up
    }
    if(!mouseWithinTopComponent)
    {
        //move view down
    }
    if(!mouseWithinLeftComponent)
    {
        //move view right
    }
    if(!mouseWithinRightComponent)
    {
        //move view left
    }
}

Сколько именно накладных расходов существует с MouseMotionListener? Может быть, этот или аналогичный метод будет более эффективным, если обнаружение нужно будет проводить только вдоль границ игрового окна?

ПРИМЕЧАНИЕ. Это будет использоваться в оконном режиме, а также в полноэкранном режиме.

Это было полезно?

Решение

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

Моя реализация состоит из 4 основных частей: области прокрутки, прямоугольных областей, таймера и MouseMotionListener .

Сначала я создал панель с именем AutoScrollPane , которая расширяет JScollPane . Даже если это JScrollPane , вы можете скрыть полосы прокрутки. Это позволяет мне использовать функциональные возможности для перемещения области просмотра на карте или аналогичной ей, как в игре RTS, как вы сказали.

Во-вторых, для областей прокрутки у меня фактически есть 8: n, ne, e, se, s, sw, w и nw (то есть "север", северо-восток "и т. д.) с диагоналями, позволяющими диагональная прокрутка. Я реализую их просто как Rectangle s. Они не прорисованы на экране или чем-то еще - я просто создаю экземпляр 8 прямоугольников в моем классе с соответствующим размером и с координатами, которые соответствуют областям окна. Я на самом деле позволяю изменить размер моего окна, поэтому я изменяю размеры прямоугольников, если это необходимо.

В-третьих, у меня есть таймер, который можно включать и выключать. Когда он включен, каждый «тик» генерирует Runnable . Эта задача Runnable заключается в прокрутке области просмотра панели в соответствующем направлении на определенное расстояние. Каждый Runnable передается в очередь событий Swing.

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

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

Другие советы

Я думаю, что это был Мартин Фаулер, который предположил, что преждевременная оптимизация - корень всего зла в разработке программного обеспечения. Почему бы не попробовать MouseMotionListener и подумать об оптимизации, только если вы обнаружите, что это влияет на производительность игры.

В MouseMotionListener нет ничего плохого. Когда вы читали о накладных расходах, вероятно, это был один конкретный пример

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

Если вы обращаете внимание на то, что вы делаете в своем слушателе, все должно быть в порядке

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top