Как реализовать столкновение стен, когда стены представляют собой одну группу, а мои спрайты находятся в другой

#python #pygame

#python #pygame

Вопрос:

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

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

 class characters(pygame.sprite.Sprite):
    def __init__(self, colour, width, height):
        super().__init__()
        self.colour = colour
        self.width = width
        self.height = height
        self.image = pygame.Surface([self.width, self.height])
        self.image.fill(white)
        self.image.set_colorkey(white)
        self.rect = self.image.get_rect() 
        pygame.draw.circle(self.image, self.colour, [int(self.width/2), int(self.height/2)], int(self.width/2))

    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 moveRandom(self, pixels, clockrate, count, xdirection, ydirection):
        self.rect.x  = pixels * xdirection
        self.rect.y  = pixels * ydirection
        #print(self.rect.x,self.rect.y)

    def wallCollide(self):
        x = self.rect.x
        for xpos in [-5,5]:
            self.rect.x  = xpos
            if pygame.sprite.spritecollide(self, wallSet, False, pygame.sprite.collide_rect):
                self.rect.x -= xpos
            else:
                self.rect.x = x
        y = self.rect.y
        for ypos in [-5,5]:
            self.rect.y  = ypos
            if pygame.sprite.spritecollide(self, wallSet, False, pygame.sprite.collide_rect):
                self.rect.y -= ypos
            else:
                self.rect.y = y
  

Я попытался использовать маску в классе wall ниже, не думаю, что это работает.

 class walls(pygame.sprite.Sprite):
    def __init__(self, x, y, width, height):
        super().__init__()
        self.width  = width
        self.height = height
        self.x      = x
        self.y      = y

        self.image = pygame.Surface([width,height])
        self.image.fill(black)
        #self.image.set_colorkey(black) Using this will make the walls invisible as I have textured walls drawn over
        self.rect = self.image.get_rect(topleft=(self.x, self.y))
        pygame.mask.from_surface(self.image)
  

Я предоставил только одну стену и уменьшил разрешение, так как это намного проще, пока я пишу свой код. Разрешение должно быть 1920 на 1080. Используйте 600 на 650, чтобы увидеть две стены.

 characterSet = pygame.sprite.Group()
player = characters(black, 30, 30)
target = characters(green, 30, 30)
characterSet.add(player, target)

wallSet = pygame.sprite.Group()
Wall1 = walls(288,176, 200,142)
Wall2 = walls(286,427, 201,140)
wallSet.add(Wall1,Wall2)
  

Основной игровой цикл

 while not end:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            end = True

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player.moveLeft(5)
    if keys[pygame.K_RIGHT]:
        player.moveRight(5)
    if keys[pygame.K_UP]:
        player.moveUp(5)
    if keys[pygame.K_DOWN]:
        player.moveDown(5)

    if count%clockrate == 0:
        xdirection = random.choice(direction)
        ydirection = random.choice(direction)
    target.moveRandom(2, clockrate, count, xdirection, ydirection)
    count  = 1

    if pygame.sprite.spritecollide(player, wallSet, False, pygame.sprite.collide_rect):
        player.wallCollide()
    gameDisplay.blit(level1,[0,0])
    wallSet.draw(gameDisplay)
    gameDisplay.blit(innerWalls,[0,0])
    characterSet.draw(gameDisplay)
  

Ответ №1:

Если я правильно понимаю, у вас есть список объектов wall и список объектов character, и вы хотите проверить столкновение между ними всеми. это можно быстро выполнить, выполнив цикл по обоим спискам:

 for wall in WallSet:
    for character in CharacterSet:
        character.checkCollision(wall)
  

checkCollision() Метод может быть очень простым, проверка того, перекрываются ли прямоугольники вокруг ваших объектов, будет просто несколькими операторами if . Если вы хотите, чтобы этот checkCollisions() метод хорошо работал для округленных символов, вам нужно написать что-нибудь более причудливое. Я бы предложил:

  1. Напишите функцию, которая даст точку внутри прямоугольника, которая ближе всего к другой точке (сложная часть! Хотя я уверен, что есть учебные пособия о том, как это сделать в Интернете)

  2. Возьмите эту точку внутри прямоугольника стены и проверьте, достаточно ли она далеко от средней позиции персонажа, чтобы не сталкиваться.

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

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

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