Почему мой спрайтер движется быстрее, когда я двигаю мышь?

17

Я пытаюсь разработать простую игру, созданную с помощью Pygame (библиотека Python).

У меня есть spriteобъект, playerи я перемещаю его с помощью клавиш со стрелками. Если я не двигаю мышь, спрайт движется нормально, но когда я двигаю мышь, спрайт движется быстрее (например, х2 или х3). playerОбъект находится внутри charsGroupвар.

Я запускал игру в W7 и в Ubuntu. То же самое происходит в обеих ОС.

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

Вот update()метод playerобъекта:

def update(self):

    for event in pygame.event.get():
        key = pygame.key.get_pressed()
        mouseX, mouseY = pygame.mouse.get_pos()
        if event.type == pygame.MOUSEBUTTONDOWN:
            self.bulletsGroup.add(Bullet(pygame.image.load("bullet.png"),
                                          self.rect.x + (self.image.get_width()/2),
                                           self.rect.y + (self.image.get_height()/2),
                                            mouseX, mouseY, 50, 50))

        if key[pygame.K_RIGHT]:
            if not self.checkCollision():
                self.rect.x += 10
            else:
                self.rect.x -= 10
        if key[pygame.K_LEFT]:
            if not self.checkCollision():
                self.rect.x -= 10
            else:
                self.rect.x += 10
        if key[pygame.K_UP]:
            if not self.checkCollision():
                self.rect.y -= 10
            else:
                self.rect.y += 10
        if key[pygame.K_DOWN]:
            if not self.checkCollision():
                self.rect.y += 10
            else:
                self.rect.y -= 10

А вот цикл while:

while True:

    if PLAYER.healthBase <= 0:
        GAMEOVER = True

    if not GAMEOVER:
        mapTilesGroup.draw(SCREEN)
        charsGroup.update()
        charsGroup.draw(SCREEN)
        npcsGroup.update()
        npcsGroup.draw(SCREEN)
        drawBullets()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

    if GAMEOVER:
        myfont = pygame.font.SysFont("monospace", 30)
        label = myfont.render("GAME OVER!", 1, (255, 255, 0))
        SCREEN.blit(label, (400, 300))

    freq.tick(0)

    pygame.display.flip() 

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

DrumNbass
источник
5
Точная ошибка действительно существует во многих приложениях. Попробуйте перетащить выделение в большой документ и переместить курсор от края. Обычно прокручивается край программы и медленно выбирается больше документа. Если вы перемещаете мышь из стороны в сторону, она обычно будет прокручиваться намного быстрее, поскольку скорость их прокрутки привязана к их циклу событий, а движения X повторно вызывают цикл событий.
Бен Джексон
2
@ BenJackson Я считаю, что это полезная ошибка, когда прокрутка ужасно медленная с самого начала.
user253751
1
Это не связано с вашей ошибкой, но я бы порекомендовал один раз загрузить изображение и сохранить его в объекте. BULLET_IMAGE = pygame.image.load("bullet.png")а затем позжеself.bulletsGroup.add(Bullet(BULLET_IMAGE...
DJMcMayhem
@DJMcMayhem Вы совершенно правы, я сделал это с остальными изображениями, но я пропустил сделать это с этим .. спасибо! :)
Drumnbass

Ответы:

42

tl; dr не смешивайте цикл событий с циклом игры .

Когда вы двигаете мышью, игра получает множество pygame.MOUSEMOTIONсобытий. Вы на самом деле не используете эти события для обновления вашей позиции мыши, хотя вы получаете текущее состояние мыши, используя pygame.mouse.get_pos(). Это неэффективно, но это не проблема.

Проблема в том, что вы обновляете позицию игрока внутри цикла событий !

Вот что должно произойти:

game loop:
    event loop # get key presses, mouse moves etc.)
    if key pressed in the event loop:
        move the player

Вот что делает ваш код:

game loop:
    event loop:
        if key pressed:
            move the player

При перемещении мыши цикл обработки будет выполняться много раз за кадр. Но когда вы проверяете, какие клавиши нажаты pygame.key.get_pressed(), они остаются нажатыми , пока вы не отпустите, некоторое время спустя. Таким образом, поскольку ваш цикл событий проходит через события перемещения мыши, он будет повторно применять движения игрока несколько раз.

Решение простое: вывести игрока за пределы цикла событий.

congusbongus
источник
1
Благодарность! Теперь это работает отлично, и, вероятно, я никогда не осознавал, что происходит! Кстати, почему вы говорите, что pygame.mouse.get_pos()это неэффективно? Какие у меня есть альтернативы?
Drumnbass
Привет @ congusbongus, не могли бы вы объяснить мне это? Благодарю.
Drumnbass
@Drumnbass pygame.mouse.get_pos()получает последнюю позицию мыши, независимо от очереди событий, поэтому нет необходимости помещать ее в цикл событий. Альтернативой может быть обработка каждого pygame.MOUSEMOTIONсамостоятельно, но если вам не нужно каждое событие (например, вы пишете программу рисования), подойдет последняя позиция.
congusbongus
3

Вот еще несколько мыслей, чтобы дополнить существующий ответ .

В Gaffer On Games есть отличная статья об игровых циклах, на которую есть ссылки повсюду.

Ваш игровой цикл должен иметь разные независимые этапы: Input, Update, Render.

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

HgMerk
источник