Обнаружение столкновения замедляет рисование экрана

8

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

Проблема

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

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

Далее, когда я комментирую часть обнаружения столкновений моего физического движка, он возобновляет свое обычное реагирующее поведение.

То, что я думаю, вызывает такое поведение

Примечание: я отказался от этого предположения (см. «Отладочная информация» ниже)

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

Какой-то код

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

PhysicsEngine.updateBeadPositions (float) :

private void updateBeadPositions(float delta){

    //Update all of the beads currently on the board.
    beads = control.getBoard().getValues();

    temp_x = 0.0f;
    temp_y = 0.0f;

    //For each row...
    for(Bead[] row : beads){

        //For each bead...
        for(Bead bead : row){

            //If this bead exists...
            if(bead != null){

                temp_y = (float) (bead.getYCoordinate() * bead.getYVelocity() * delta);

                //If the coordinates are within the bounds of the game
                if(outwithVerticalBounds(temp_y, control.getBoard())){

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    bead.setXCoordinate(temp_x);

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    bead.setYCoordinate(temp_y);
                }
            }
        }
    }

    //If the cannon Bead has been set...
    if(control.getCannon().getReleased() != null){

        //Update the cannon bead
        if(control.getCannon().getReleased().getXVelocity() == PhysicsEngine.VELOCITY_STATIC && control.getCannon().getReleased().getYVelocity() == PhysicsEngine.VELOCITY_STATIC){

            control.getCannon().getReleased().setXCoordinate(control.getCannon().getX());
            control.getCannon().getReleased().setYCoordinate(control.getCannon().getY() - Cannon.PIVOT_Y_OFFSET);
        }
        else{

            temp_x = control.getCannon().getReleased().getXCoordinate() + (control.getCannon().getReleased().getXVelocity() * delta);
            temp_y = control.getCannon().getReleased().getYCoordinate() + (control.getCannon().getReleased().getYVelocity() * delta);

            //TODO: Commented out collision checkers!

            //If the horizontal coordinates are within the bounds of the game
            if(!outwithHorizontalBounds(temp_x, control.getBoard())){

                //If the vertical coordinates are within the bounds of game
                if(!outwithVerticalBounds(temp_y, control.getBoard())){

                    //Set the X coordinate equal to the distance * the time differential (delta).       
                    control.getCannon().getReleased().setXCoordinate(temp_x);

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    control.getCannon().getReleased().setYCoordinate(temp_y);
                }
                //Otherwise...
                else{

                    //Bounds off the wall in the y direction
                    control.getCannon().getReleased().setYVelocity(-1.0f * control.getCannon().getReleased().getYVelocity());
                }
            }
            //Otherwise...
            else{

                //Bounce off the wall in the x direction (flip the x velocity)
                control.getCannon().getReleased().setXVelocity(-1.0f * control.getCannon().getReleased().getXVelocity());
            }
        }
    }
}

Здесь переменные определены как:

  • controlэто ссылка на мой игровой контроллер. Он упаковывает большую часть кода игры.

  • beads является ссылкой на 2D-массив, который содержит бусы на доске в настоящее время (исключая тот, который движется)

  • delta разница во времени между предыдущими вызовами физического движка и текущим вызовом

Смотрите комментарии в коде для любых других объяснений.

PhysicsEngine.outwithHorizontBounds (float, Board) :

private boolean outwithHorizontalBounds(float x, Board board){

    //If the horizontal values are within the bounds...
    if(x > (board.getRight() - bead_radius)){

        return true;
    }

    if(x < (board.getLeft() + bead_radius)){

        return true;
    }

    //Otherwise, it is not.
    return false;
}

Метод outwithVerticalBounds(float, Board)имеет эквивалентную функциональность, но в направлении y.


Мой вопрос

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

Отладочная информация

Последнее обновление: 29 января 2013 г. 16:27 EST

Вот совокупность отладочной информации, которую я получил до сих пор. Я буду обновлять это с течением времени:

  • update()Метод в моем двигателе, занимает, в среднем, только .018 msдля выполнения. Обычно задержка прыгает до 0.020 ms, когда я нажимаю на экран, чтобы освободить шарик.

  • После сравнения времени проведения розыгрышей и обновлений игры оказалось, что я был прав: они происходят одновременно . Таким образом, это не могло быть проблемой, верно?

  • Суть FPSигры примерно одинакова 87(на нижнем уровне) 60 FPS, но этот всплеск не связан с выпуском шарика. У этого нет FPSнедостатков. Это имеет смысл, так как единственная часть, которая увеличивает его сложность после того, как бусинка отпущена, - это update()вызов, рисование все равно происходит как можно быстрее.

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

Дополнительная информация

Вот некоторая дополнительная информация, которая должна помочь вам понять мои обстоятельства:

  • Я тестирую это на Google Nexus 7.

  • На карте довольно много шариков, которые обновляются одновременно (около 30), но только один из них движется.

  • Обычно, после того как шарик начинает двигаться (после начальной задержки и, если он действительно вытягивается), он продолжает двигаться очень плавно.

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

Squagem
источник
Думаете, что ваша отладка, которая показывает обновления физики в соответствии с дро, может быть неточной? Вы делали какие-либо другие профилирования с этим кодом?
MichaelHouse
Я сделал несколько обширных отладок с использованием выводов на консоль (LogCat), однако ничего сложнее этого. Может случиться так, что мои отладочные операторы неверны, я сейчас их рассмотрю.
Squagem
Также интересно, изменяется ли FPS (число кадров в секунду) при добавлении ограничивающего случая, или проблема не связана с тем, насколько быстро работает программа.
Qqwy
Я отредактировал свой вопрос, чтобы ответить на вопросы, которые вы подняли.
Squagem

Ответы:

8

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

Решение

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

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

Я переместил пушку на 50 пикселей выше, и теперь она работает как задумано.


Спасибо всем за помощь! Я бы не попал сюда без твоих вдумчивых предложений.

Squagem
источник
3
+1 за хорошо отформатированный вопрос и +1 за ответ на него самостоятельно
RoughPlace
Ой, забыл об этом вопросе! Спасибо, ребята :)
Squagem