Как сделать детектор столкновений в Pygame - PullRequest
0 голосов
/ 15 апреля 2020

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

Это код класса Player:

class player:
    def __init__(self, x, y, width, height, colour):
        self.width = width  # dimensions of player
        self.height = height  # dimensions of player
        self.x = x  # position on the screen
        self.y = y  # position on the screen
        self.colour = colour  # players colour
        self.rect = (x, y, width, height)  # all the players properties in one
        self.speed = 2  # how far/fast you move with each key press
        self.direction = ""

    def draw(self, win):
        pygame.draw.rect(win, self.colour, self.rect)

    def move(self, platforms):
        keys = pygame.key.get_pressed()  # dictionary of keys - values of 0/1

        if keys[pygame.K_LEFT]:  # move left: minus from x position value
            if self.x <= 5:
                pass
            else:
                self.x -= self.speed
                self.direction = "Left"

        elif keys[pygame.K_RIGHT]:  # move right: add to x position value
            if self.x == 785:
                pass
            else:
                self.x += self.speed
                self.direction = "right"

        elif keys[pygame.K_UP]:  # move up: minus from y position value
            if self.y <= 5:
                pass
            else:
                self.y -= self.speed
                self.direction = "up"

        elif keys[pygame.K_DOWN]:  # move down from
            if self.y >= 785:
                pass
            else:
                self.y += self.speed
                self.direction = "down"

    def update(self, platforms, direction):
        self.collision_with_platform(platforms, direction)
        self.rect = (self.x, self.y, self.width, self.height)  # redefine where the player is

        self.update(platforms, self.direction)

Это детектор столкновений:

    def collision_with_platform(self, platforms, direction):
        # evaluates if the player is inside a platform, moving the player to it's edge if so
        for platform in platforms:

            # checks if player's coordinates are inside the platform, for each platform
            if platform.rect.left - 20 < self.x < platform.rect.left + 50:
                if platform.rect.top - 20 < self.y < platform.rect.top + 50:

                    # if moving horizontally
                    if direction == "left" or direction == "right":  # evaluates which side of the platform to move the player to
                        if direction == "left":
                            self.x = platform.rect.left + 10  # move to the right side

                        if direction == "right":
                            self.x = platform.rect.left - 10  # move to the left side

                        # if moving vertically
                    elif direction == "down" or direction == "up":  # evaluates which side of the platform to move the player to
                        if direction == "down":
                            self.y = platform.rect.top - 10  # move to the top side

                        elif direction == "up":
                            self.y_pos = platform.rect.top + 50  # move to the bottom side

Вот как я генерирую платформы:

class Platform:
    # represents a platform which the player can stand on
    def __init__(self, left, top, width, height, colour):
        self.rect = pygame.Rect(left, top, width, height)  # square representing a single platform
        self.colour = colour  # platform's colour


def generate_platforms(probability):
    # generates platforms randomly
    points, platforms = [], []
    # generates a list of all possible platform coordinates
    # format of points : [(0,0), (0,1), (0,2), ..., (1,0), (1,1), (1,2), ...]
    for x in range(0, 600):
        for y in range(0, 600):
            points.append((x, y))

    # randomly selects platforms to create out of list of all possible platforms
    for point in points:
        if random.randint(1, 100) <= probability:  # probability of each individual platform being created
            platforms.append(Platform(point[0] * 50, point[1] * 50, 50, 50, (0, 0, 225)))

    return platforms  # returns the list of generated platforms

Это основная игра l oop:

def main():  # asking server for updates, checking for events
    run = True
    n = Network()
    startPos = read_pos(n.getPos())

    p = player(startPos[0], startPos[1], 10, 10, (255, 0, 0))  # connect, get starting position
    p2 = player(0, 0, 10, 10, (0, 0, 255))
    platforms = generate_platforms(25)

    clock = pygame.time.Clock()

    while run:
        clock.tick(60)

        p2Pos = read_pos(n.send(make_pos((p.x, p.y))))
        p2.x = p2Pos[0]
        p2.y = p2Pos[1]
        p2.update(platforms, p.direction)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:  # quitting condition
                run = False
                pygame.quit()
        p.move(platforms)  # move character based off what keys are being pressed
        redrawWindow(win, p, p2, platforms)

1 Ответ

0 голосов
/ 16 апреля 2020

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

for x in range(0, screen_Width//50):
        for y in range(0, screen_Height//50):
            if random.randint(1, 100) <= probability:  # probability of each individual platform being created
                platforms.append(Platform(x * 50, y * 50, 50, 50, (0, 0, 225)))

Это создает платформы только каждые 50 пикселей, так что ни один не перекрывается. После этого я получил длину 22, намного ниже и все еще выглядит примерно так же. Это значительно ускорит вашу программу. Я получал 1,5 кадра в секунду, но теперь максимальная скорость составляет 60 кадров.

Чтобы исправить ваши столкновения.

Измените прямоугольник игрока на объект-прямоугольник

self.rect = pygame.Rect(x, y, width, height)  # all the players properties in one

и измените прямоугольник при перемещении

 if keys[pygame.K_LEFT]:  # move left: minus from x position value
     if self.x > 5:
         self.x -= self.speed
         self.rect.x -= self.speed
         self.direction = "left" # lowercase l as everything else was lowercase

затем для столкновений:

if self.rect.colliderect(platform.rect):
    if direction == "left":
        self.rect.left = platform.rect.right  # move to the right side

    elif direction == "right":
        self.rect.right = platform.rect.left   # move to the left side

    # if moving vertically
    elif direction == "down":
        self.rect.bottom = platform.rect.top  # move to the top side

    elif direction == "up":
        self.rect.top = platform.rect.bottom  # move to the bottom side    

также В player.update вам не нужно вызывать его снова внутри. Так что именно это будет делать

def update(self, platforms):
    self.collision_with_platform(platforms, self.direction)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...