Почему мой клон pacMan, созданный в java, иногда отстает? - PullRequest
3 голосов
/ 29 сентября 2011

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

Диспетчер ресурсов показывает такое же использование процессора (только около 50%) / использование памяти.Aswell FPS, кажется, постоянно составляет около 200 через лаги и в периоды, когда он работает хорошо.

Кто-нибудь знает, что это может быть?

Есть ли какая-то информация, которую я мог бы опуститьбыть полезным?

edit - я основываю движение на таймере, это плохо?Я опубликую соответствующий код движения ниже. Есть ли хороший способ разместить весь код здесь?

Timer movement = new Timer(20, new ActionListener()//500 is time in milliseconds between
      //calls to actionPerformed as far as I know.
    {
        public void actionPerformed(ActionEvent arg0) 
        {
            if(movingUp == true)
            {
                moveUp();
            }
            else if(movingDown == true)
            {
                moveDown();
            }
            else if(movingRight == true)
            {
                moveRight();
            }
            else if(movingLeft == true)
            {
                moveLeft();
            }

        }

    });


public void moveUp()
    {
        yPos -= 1;
        this.rect.y -= 1;
    }

public void setDirUp()
    {
        movingUp = true;
        movingDown = false;
        movingRight = false;
        movingLeft = false;
    }

в основном классе в открытом ключе voidPressed:

if(keyCode == KeyEvent.VK_W)
        {
            if(pacMan.isUpHittingWall == false)
            {
                pacMan.setDirUp();

                pacMan.isDownHittingWall = false;
                pacMan.isRightHittingWall = false;
                pacMan.isLeftHittingWall = false;
            }

        }

edit 2-Спасибо за помощь, ребята.Сейчас у меня есть движение, использующее системное время, и оно, похоже, решило проблему, потому что я реализовал его сначала только для pacman, а призраки все еще были медленными.Теперь есть проблема, когда движение вправо и вниз намного медленнее, чем движение влево или вверх. Единственное отличие, которое я вижу, состоит в том, что вправо и вниз - это сложение, а влево и вверх - вычитание.Что я могу сделать по этому поводу?

Обновленный код приведен ниже.

//updated movement code
public void moveUp(long timePassed)
    {
        yPos -= vy * timePassed;
        this.rect.y -= vy * timePassed;
    }

    public void moveDown(long timePassed)
    {
        yPos += vy * timePassed;
        this.rect.y += vy * timePassed;
    }

    public void moveRight(long timePassed)
    {
        xPos += vx * timePassed;
        this.rect.x += vx * timePassed;
    }

    public void moveLeft(long timePassed)
    {
        xPos -= vx * timePassed;
        this.rect.x -= vx * timePassed;
    }


//I passed timePassed through a globalInputObject because my input is handled in public //void keyPressed(KeyEvent e) and I didnt know how else to get timePassed in to the //movement method

//Here is the code in gameLoop()
                 globalInputObject.isPacManMovingUp(timePassed);
             globalInputObject.isPacManMovingDown(timePassed);
             globalInputObject.isPacManMovingRight(timePassed);
         globalInputObject.isPacManMovingLeft(timePassed);




//This is inside the GlobalInputObject
public void isPacManMovingUp(long timePassed)
    {
        if(pacMan.movingUp == true)
        {
            pacMan.moveUp(timePassed);
        }
    }

    public void isPacManMovingDown(long timePassed)
    {
        if(pacMan.movingDown == true)
        {
            pacMan.moveDown(timePassed);
        }
    }

    public void isPacManMovingRight(long timePassed)
    {
        if(pacMan.movingRight == true)
        {
            pacMan.moveRight(timePassed);
        }
    }

    public void isPacManMovingLeft(long timePassed)
    {
        if(pacMan.movingLeft == true)
        {
            pacMan.moveLeft(timePassed);
        }
    }

Ответы [ 3 ]

2 голосов
/ 30 сентября 2011

Как я и опасался, вы основываете расстояние, перемещенное на отрезке времени от Таймера.Вы не должны делать это, поскольку все таймеры могут быть переменными и ненадежными, особенно с небольшими временными порциями.Лучше основывать движение на разнице в системном времени.Так что да, используйте Timer или что-то еще для запуска своего «игрового цикла», но узнайте положение и скорость спрайта, используя удвоения, и рассчитайте расстояние для перемещения на основе вектора скорости (математический вектор, а не вектор Java) * разницы в системном времени.Таким образом, если таймер задерживается, скажем, сборкой мусора, что увеличивает временной интервал, то пройденное расстояние будет соответственно больше и будет выглядеть более плавным.

2 голосов
/ 30 сентября 2011

Вместо того, чтобы всегда перемещать pacman на постоянное расстояние (появляется 1 пиксель) при каждом запуске таймера, вы должны:

  1. Установите таймер на максимально возможную скорость (например, один раз в каждую миллисекунду или меньше). Редактировать: Если вы установите слишком быстро, игра может в конечном итоге работать медленнее, вам придется экспериментировать.
  2. Подсчитайте, сколько времени прошло между каждым кадром, используя системные часы и переместите pacman на величину, пропорциональную этому.

Выполнение вышеизложенного будет означать, что если система «запаздывает», она будет просто показывать меньше кадров в секунду, вместо того, чтобы фактически перемещать все медленнее.

1 голос
/ 30 сентября 2011

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

loop:
    process collision detection
    process animation (alters geometry of game objects)
    process input (more on this later)
    any other game specific logic
    render screen

ваш процесс ввода может быть что-то вроде этого

if (globalInputObject.movingUp==true) {
   hero.y -= 10;
}
if (globalInputObject.movingDown==true) {
   hero.y += 10;
}
if (globalInputObject.movingLeft==true) {
   hero.x -= 10;
}
if (globalInputObject.movingRight==true) {
   hero.x += 10;
}

и ваш обработчик ввода будет выглядеть примерно так:

public void actionPerformed(ActionEvent evt) {
    if (evt.button==UP_BUTTON) {
        globalInputObject.movingUp=true;
    }
    if (evt.button==DOWN_BUTTON) {
        globalInputObject.movingDown=true;
    }
    if (evt.button==LEFT_BUTTON) {
        globalInputObject.movingLeft=true;
    }
    if (evt.button==RIGHT_BUTTON) {
        globalInputObject.movingRight=true;
    }

}

В основном обработка, которую вы выполняете в своих «дополнительных» потоках (входной поток), минимальна и поэтому не мешает вашему основному потоку. Кроме того, этот метод позволяет легко поддерживать несколько направлений одновременно (т. Е. UP + RIGHT = диагональ).

Только в супер высококлассных играх может быть несколько потоков (если они вообще нужны). Работа с синхронизацией в игре плохо влияет на производительность.

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