Как бы вы завершили цикл, как только спрайт коснулся стены?

#python #pygame

#python #pygame

Вопрос:

Итак, я некоторое время пытался это сделать. Я хочу, чтобы основной цикл завершился / игра завершилась, как только player он достиг границы экрана, но, похоже, не могу понять, как я это сделаю. Вот что у меня есть на данный момент:

 import pygame
pygame.init()

class Player(pygame.sprite.Sprite):
    def __init__(self, color):
        super().__init__()
        self.image = pygame.Surface([25, 25])
        self.image.fill(color)
        self.color = color
        self.rect = self.image.get_rect()

    def moveRight(self, pixels):
        if self.rect.x   pixels > 500 - 25:
            self.rect.x = 500 - 25
        self.rect.x  = pixels

    def moveLeft(self, pixels):
        if self.rect.x - pixels < 0:
            self.rect.x = 0
        else:
            self.rect.x -= pixels

    def moveUp(self, pixels):
        if self.rect.y - pixels < 0:
            self.rect.y = 0
        else:
            self.rect.y -= pixels

    def moveDown(self, pixels):
        if self.rect.y   pixels > 500 - 25:
            self.rect.y = 500 - 25
        else:
            self.rect.y  = pixels

# Color
red = (255, 0, 0)
white = (255, 255, 255)

screen = pygame.display.set_mode([500,500])

# Sprite List
sprite_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()

# Player
player = Player(red)
player.rect.x = 250
player.rect.y = 250
sprite_list.add(player)

notDone = True
clock = pygame.time.Clock()

while notDone:
    current_time = pygame.time.get_ticks()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            notDone = False

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] or keys[pygame.K_a]:
        player.moveLeft(3)
    if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
        player.moveRight(3)
    if keys[pygame.K_UP] or keys[pygame.K_w]:
        player.moveUp(3)
    if keys[pygame.K_DOWN] or keys[pygame.K_s]:
        player.moveDown(3)

    screen.fill(white)

    sprite_list.draw(screen)
    pygame.display.flip()

    clock.tick(60)

pygame.quit()
 

В моем примере player спрайт может перемещаться вверх, вниз, влево и вправо. Персонаж также не может перемещаться за границу. Есть ли способ завершить цикл (как если бы игра закончилась), как только спрайт достиг указанной границы?

Ответ №1:

Если вы хотите завершить игру, когда прямая линия игрока коснется края экрана, тогда нет смысла исправлять положение игрока, если игрок выходит за пределы. В любом случае было бы проще использовать Rect.clamp_ip .

Что касается выхода из игры, самый простой способ — поместить ваш основной цикл в функцию и на всякий return случай, если вы захотите выйти.

Чтобы проверить, «покидает» ли прямоугольник (например, игрока) другой прямоугольник (например, прямоугольник экрана), вы можете использовать Rect.contains функцию.

 import pygame


class Player(pygame.sprite.Sprite):
    def __init__(self, color):
        super().__init__()
        self.image = pygame.Surface([25, 25])
        self.image.fill(color)
        self.rect = self.image.get_rect()

    def moveRight(self, pixels):
        self.rect.x  = pixels

    def moveLeft(self, pixels):
        self.rect.x -= pixels

    def moveUp(self, pixels):
        self.rect.y -= pixels

    def moveDown(self, pixels):
        self.rect.y  = pixels

def main():
    pygame.init()
    screen = pygame.display.set_mode([500,500])

    # Sprite List
    sprite_list = pygame.sprite.Group()
    block_list = pygame.sprite.Group()

    # Player
    player = Player('red')
    player.rect.x = 250
    player.rect.y = 250
    sprite_list.add(player)

    clock = pygame.time.Clock()

    while True:
        current_time = pygame.time.get_ticks()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return

        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            player.moveLeft(3)
        if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            player.moveRight(3)
        if keys[pygame.K_UP] or keys[pygame.K_w]:
            player.moveUp(3)
        if keys[pygame.K_DOWN] or keys[pygame.K_s]:
            player.moveDown(3)

        if not screen.get_rect().contains(player.rect):
            return

        screen.fill('white')

        sprite_list.draw(screen)
        pygame.display.flip()

        clock.tick(60)

main()
 

Комментарии:

1. Возможно ли это без основного цикла внутри функции? Или это работает только так?

2. Для использования return вам придется использовать функцию. Конечно, есть и другие способы прервать основной цикл, например, вы устанавливаете флаг, вызываете sys.exit или quit и т. Д. Но я предпочитаю способ функции / возврата, потому что он работает с вложенными циклами, гарантирует, что после обработки событий ничего плохого не произойдет (распространенная ошибка, которую вы ежедневно видите на SO, заключается в том, что люди звонят pygame.quit() , а затем вызывают другие функции pygame после этого), и делает именно то, что он должен делать (завершение основного цикла) безвыход из всего приложения. Но, в конце концов, это зависит от вас.

3. Проблема в том, что когда игра «завершается», экран не закрывается. Вместо этого экран полностью зависает, и я ничего не могу сделать, кроме выхода через окно оболочки. (Я использую Python IDLE для этого кода) Это должно произойти?

4. О, неважно. Если я добавлю pygame.quit() перед return функцией, игра завершится без проблем. Спасибо за вашу помощь.

5. Обычно вам не нужно вызывать pygame.quit() ; ЗА исключением случаев использования IDLE . Я не знаю почему, и я обычно не использую IDLE.

Ответ №2:

Методы move * Player класса должны возвращать логическое значение, указывающее, попал ли игрок в стену. Возврат True , если игрок попадает в стену, False в противном случае:

 class Player(pygame.sprite.Sprite):
    # [...]

    def moveRight(self, pixels):
        if self.rect.x   pixels > 500 - 25:
            self.rect.x = 500 - 25
            return True
        self.rect.x  = pixels
        return False

    def moveLeft(self, pixels):
        if self.rect.x - pixels < 0:
            self.rect.x = 0
            return True
        self.rect.x -= pixels
        return False

    def moveUp(self, pixels):
        if self.rect.y - pixels < 0:
            self.rect.y = 0
            return True
        self.rect.y -= pixels
        return False

    def moveDown(self, pixels):
        if self.rect.y   pixels > 500 - 25:
            self.rect.y = 500 - 25
            return True
        self.rect.y  = pixels
        return False
 

Оцените возвращаемое значение в цикле приложения и установите notDone = False , касается ли проигрыватель стены:

 while notDone:
    # [...]

    hit = False
   
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] or keys[pygame.K_a]:
        hit = player.moveLeft(3)
    if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
        hit = player.moveRight(3)
    if keys[pygame.K_UP] or keys[pygame.K_w]:
        hit = player.moveUp(3)
    if keys[pygame.K_DOWN] or keys[pygame.K_s]:
        hit = player.moveDown(3)
    
    if hit:
        notDone = False

    # [...]
 

Полный пример

 import pygame
pygame.init()

class Player(pygame.sprite.Sprite):
    def __init__(self, color):
        super().__init__()
        self.image = pygame.Surface([25, 25])
        self.image.fill(color)
        self.color = color
        self.rect = self.image.get_rect()

    def moveRight(self, pixels):
        if self.rect.x   pixels > 500 - 25:
            self.rect.x = 500 - 25
            return True
        self.rect.x  = pixels
        return False

    def moveLeft(self, pixels):
        if self.rect.x - pixels < 0:
            self.rect.x = 0
            return True
        self.rect.x -= pixels
        return False

    def moveUp(self, pixels):
        if self.rect.y - pixels < 0:
            self.rect.y = 0
            return True
        self.rect.y -= pixels
        return False

    def moveDown(self, pixels):
        if self.rect.y   pixels > 500 - 25:
            self.rect.y = 500 - 25
            return True
        self.rect.y  = pixels
        return False

# Color
red = (255, 0, 0)
white = (255, 255, 255)

screen = pygame.display.set_mode([500,500])

# Sprite List
sprite_list = pygame.sprite.Group()
block_list = pygame.sprite.Group()

# Player
player = Player(red)
player.rect.x = 250
player.rect.y = 250
sprite_list.add(player)

notDone = True
clock = pygame.time.Clock()

while notDone:
    current_time = pygame.time.get_ticks()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            notDone = False

    hit = False
   
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] or keys[pygame.K_a]:
        hit = player.moveLeft(3)
    if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
        hit = player.moveRight(3)
    if keys[pygame.K_UP] or keys[pygame.K_w]:
        hit = player.moveUp(3)
    if keys[pygame.K_DOWN] or keys[pygame.K_s]:
        hit = player.moveDown(3)
    
    if hit:
        notDone = False

    screen.fill(white)

    sprite_list.draw(screen)
    pygame.display.flip()

    clock.tick(60)

pygame.quit()
 

Комментарии:

1. Я не знаю, что я делаю не так, но по какой-то причине, когда мой проигрыватель достигает границы, он по-прежнему не возвращает true .

2. @Видимо, я добавил полный пример кода к ответу. Пример протестирован и работает нормально.