Столкновение не увеличивает счет и не удаляет снаряды [закрыто]

avatar
de_l3ns
8 мая 2021 в 16:36
53
2
-1

Итак, в настоящее время у меня есть класс врагов, который использует группы спрайтов, и класс снарядов, который не использует группы спрайтов.

Я проверяю столкновение моих снарядов с врагами в группе спрайтов. Если враг поражен, вражеский спрайт удаляется, счет увеличивается, а пуля удаляется с экрана. На данный момент удаляется только вражеский спрайт.

Класс снаряда:

class Projectile():
    def __init__(self, x, y, width, height, speed, damage, image):
        # Variables for the player attacks (ranged)
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.speed = speed
        self.damage = damage
        self.image = image
        self.rect = self.image.get_rect()

    def draw(self, window):
        window.blit(self.image, (self.x, self.y))

    def checkCollision(self, bullet, enemy):
        col = pygame.sprite.spritecollide(bullet, enemy, True)
        if col == True:
            return True

Класс врага

class Enemy(pygame.sprite.Sprite):

    def __init__(self, width, height, mov_speed):
        # Variables for the various enemies
        pygame.sprite.Sprite.__init__(self)
        self.width = width
        self.height = height
        self.mov_speed = mov_speed
        self.image = speedboat_sprite
        self.rect = self.image.get_rect()
        self.rect.x = random.randint(64, 734)
        self.rect.y = random.randrange(-1000, -100)
        self.hitbox = (
        self.rect.x + 22, self.rect.y + 15, 19, 45)  # Dimensions of the hitbox to make it close to the model
        self.end_reached = False
        self.alive = True

    def update(self):
        # This function lets the enemy go forward until the end of the screen
        max_distance = 800 - self.height
        if self.rect.y < max_distance:
            self.rect.y += self.mov_speed

        if self.rect.y >= max_distance:
            self.end_reached = True
            self.kill()

Код в игровом цикле, который не работает:

# Game logic here
game = True
whale = Player(334, 650, 128, 128)  # Spawns the Player at the start of the game in the middle of the screen
speedboat_locations = (125, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800)
speedboats = pygame.sprite.Group()
pirate_boss = Boss(1, 1, 256, 256, 1, 50)
beams = []
cooldown = 0
wave_1 = 5
lives = 3
score = 0

while game:

    for event in pygame.event.get():  # this for-loop makes sure the game exits when clicking x
        if event.type == pygame.QUIT:
            game = False

    # Collision of attacks
    for beam in beams:
        hit = beam.checkCollision(beam, speedboats)
        if hit == True:
            score += 25
            beams.pop(beams.index(beam))

        if beam.y > 0:
            beam.y -= beam.speed  # This makes sure the bullet moves forward as long as it is not of the screen
            beam.rect.center = (beam.x, beam.y)
        else:
            beams.pop(beams.index(beam))  # If the bullet goes of the screen it gets removed from the list

Полный код:

import pygame
import random

# Initialize game window here
pygame.init()

# Variables for the game window
window = pygame.display.set_mode((800, 800))
pygame.display.set_caption('Sea Invaders')
clock = pygame.time.Clock()  # Adds the clock for spawn timers
message_font = pygame.font.SysFont('Calibri', 36)

# Sprites, background and music
background = pygame.image.load('Background.jpg')
whale_sprite = pygame.image.load('Whale.png')
speedboat_sprite = pygame.image.load('Speedboat.png')
beam_sprite = pygame.image.load('Beam.png')
life_sprite = pygame.image.load('Life.png')
pirate_boss_sprite_right = pygame.image.load('Pirateboss_right.png')


# Classes
class Player():

    def __init__(self, x, y, width, height):
        # Variables for the Whale go here
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.mov_speed = 5
        self.hitbox = (self.x, self.y, self.width, self.height)

    def draw(self, window):
        # This function draws the whale using the sprite and the defined location in the class parameters
        window.blit(whale_sprite, (self.x, self.y))
        self.hitbox = (self.x, self.y, self.width, self.height)
        # pygame.draw.rect(window, (255, 0, 0), self.hitbox, 2) # Hitbox check


class Enemy(pygame.sprite.Sprite):

    def __init__(self, width, height, mov_speed):
        # Variables for the various enemies
        pygame.sprite.Sprite.__init__(self)
        self.width = width
        self.height = height
        self.mov_speed = mov_speed
        self.image = speedboat_sprite
        self.rect = self.image.get_rect()
        self.rect.x = random.randint(64, 734)
        self.rect.y = random.randrange(-1000, -100)
        self.hitbox = (
        self.rect.x + 22, self.rect.y + 15, 19, 45)  # Dimensions of the hitbox to make it close to the model
        self.end_reached = False
        self.alive = True

    def update(self):
        # This function lets the enemy go forward until the end of the screen
        max_distance = 800 - self.height
        if self.rect.y < max_distance:
            self.rect.y += self.mov_speed

        if self.rect.y >= max_distance:
            self.end_reached = True
            self.kill()

    def hit(self):
        self.kill()
        self.alive = False


class Boss():
    def __init__(self, x, y, width, height, mov_speed, hitpoints):
        # Variables for the boss objects
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.mov_speed = mov_speed
        self.hitpoints = hitpoints
        self.hitbox = (self.x + 30, self.y + 50, 225, 160)  # Dimensions of the hitbox to make it close to the model
        self.alive = True
        self.end_reached = False

    def draw(self, window):
        if self.alive:
            window.blit(pirate_boss_sprite_right, (self.x, self.y))
            self.hitbox = (self.x + 30, self.y + 50, 225, 160)
            pygame.draw.rect(window, (255, 0, 0),
                             (self.x + ((self.width / 2) - (self.hitpoints / 2)), self.y + 220, 50, 10))
            pygame.draw.rect(window, (0, 255, 0),
                             (self.x + ((self.width / 2) - (self.hitpoints / 2)), self.y + 220, self.hitpoints, 10))

            # pygame.draw.rect(window, (255, 0, 0), self.hitbox, 2)  # hitbox check

    def move(self):
        max_distance = 800 - self.height
        if self.x < (800 + self.width):
            self.x += self.mov_speed

        else:
            self.y += 100
            self.x = -51

        if self.y >= max_distance:
            self.alive = False
            self.end_reached = True

    def hit(self):
        print('hit')
        if self.hitpoints <= 0:
            self.alive = False


class Projectile():
    def __init__(self, x, y, width, height, speed, damage, image):
        # Variables for the player attacks (ranged)
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.speed = speed
        self.damage = damage
        self.image = image
        self.rect = self.image.get_rect()

    def draw(self, window):
        window.blit(self.image, (self.x, self.y))

    def checkCollision(self, bullet, enemy):

        bullet.rect.x = int(self.x)
        bullet.rect.y = int(self.y)

        return pygame.sprite.spritecollide(bullet, enemy, True)




class Hud():
    def __init__(self, x, y, sprite):
        self.x = x
        self.y = y
        self.sprite = sprite

    def draw(self, window):
        window.blit(self.sprite, (self.x, self.y))


# Methods
def redrawGameWindow():
    window.blit(background, (0, 0))  # Loads in the background
    whale.draw(window)  # Draws the Whale in the game
    scoreboard = message_font.render(str(score), True, (255, 255, 255))
    window.blit(scoreboard, (700, 760))

    x_life = 0

    for life in range(lives):
        life = Hud(x_life, 760, life_sprite)
        x_life += 25
        life.draw(window)

    if lives == 0:
        text = f'Game over! Your score: {score}.'
        game_over = message_font.render(text, True, (0, 0, 0))
        window.blit(game_over, (200, 200))

    if score >= 75:
        pirate_boss.draw(window)
        pirate_boss.move()

    speedboats.draw(window)
    speedboats.update()

    for fired_beam in beams:
        fired_beam.draw(window)
    pygame.display.update()  # This updates the above changes to the game window


# Game logic here
game = True
whale = Player(334, 650, 128, 128)  # Spawns the Player at the start of the game in the middle of the screen
speedboat_locations = (125, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800)
speedboats = pygame.sprite.Group()
pirate_boss = Boss(1, 1, 256, 256, 1, 50)
beams = []
cooldown = 0
wave_1 = 5
lives = 3
score = 0

while game:

    for event in pygame.event.get():  # this for-loop makes sure the game exits when clicking x
        if event.type == pygame.QUIT:
            game = False

    # Life check
    for speedboat in speedboats:
        if speedboat.end_reached:  # if this is true we subtract a life
            lives -= 1  # We subtract lives with the enemies that reached the end

        if not speedboat.alive:
            speedboats.remove(speedboat)

    if pirate_boss.end_reached:
        lives = 0

    # Basic cooldown for the projectiles of the player
    if cooldown > 0:
        cooldown += 1
    if cooldown > 50:
        cooldown = 0

    # Collision of attacks
    for beam in beams:
        hit = beam.checkCollision(beam, speedboats)
        if hit == True:
            score += 25
            beams.pop(beams.index(beam))
        if pirate_boss.alive:
            if beam.y - beam.width < pirate_boss.hitbox[1] + pirate_boss.hitbox[3] and beam.y + beam.width > \
                    pirate_boss.hitbox[1]:
                if beam.x + beam.height > pirate_boss.hitbox[0] and beam.x - beam.height < pirate_boss.hitbox[0] + \
                        pirate_boss.hitbox[2]:
                    pirate_boss.hitpoints -= beam.damage
                    beams.pop(beams.index(beam))
                    pirate_boss.hit()

        if beam.y > 0:
            beam.y -= beam.speed  # This makes sure the bullet moves forward as long as it is not of the screen
            beam.rect.center = (beam.x, beam.y)
        else:
            beams.pop(beams.index(beam))  # If the bullet goes of the screen it gets removed from the list

    # --- PLAYER CONTROLS ---
    keys = pygame.key.get_pressed()

    if keys[pygame.K_LEFT] and whale.x > whale.mov_speed:
        # Makes sure the whale can move left
        # and prevents the whale from exiting the screen
        whale.x = whale.x - whale.mov_speed

    if keys[pygame.K_RIGHT] and whale.x < 800 - whale.mov_speed - whale.width:
        # Makes sure the whale can move right
        # and prevents the whale from exiting the screen
        whale.x = whale.x + whale.mov_speed

    if keys[pygame.K_SPACE] and cooldown == 0:
        # This block of code takes care of the beam-projectile the player can shoot
        if len(beams) < 3:
            beams.append(
                Projectile(round(whale.x + (whale.width // 2) - (32 // 2)), round(whale.y - (32 // 2)), 32, 32, 2,
                           10, beam_sprite))
            # The beam gets spawned at the whale X/Y Coordinate. To make the beam appear in the middle and at the
            # nose we add half the sprites width - half the width of the projectile to the for the x coordinate
            # and we use the y coordinate - half the length of the projectile to make the attack spawn at the top
        cooldown = 1

    # --- ENEMY SPAWNING ---
    # This block of code spawns the first wave of enemies
    for n in range(wave_1):
        speedboats.add(Enemy(64, 64, 1))
        wave_1 -= 1

    redrawGameWindow()

pygame.quit()
Источник
Prune
8 мая 2021 в 17:19
0

Укажите ожидаемое значение. См. MRE — минимальный воспроизводимый пример. Покажите, где промежуточные результаты отличаются от ожидаемых. Мы должны иметь возможность вставить один блок вашего кода в файл, запустить его и воспроизвести вашу проблему. Это также позволяет нам тестировать любые предложения в вашем контексте.

Prune
8 мая 2021 в 17:19
0

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

Prune
8 мая 2021 в 17:21
0

Я делаю замечаю, что есть по крайней мере два места, где луч удаляется, и только одно, где обновляется оценка. Вам нужно проследить их — в том числе проследить счет. Поскольку ваш код неполный, также возможно, что вы делаете увеличение оценки, но затем теряете значение из-за ошибки области видимости. Опять же, обратитесь к рекомендациям MRE.

de_l3ns
9 мая 2021 в 09:32
0

@Prune Извиняюсь! Я решил, что вставил необходимые биты, теперь я разместил свой полный код. Все мои классы были нарисованы вручную, но я столкнулся с проблемой, что я не мог удалить свои спрайты с помощью обычного класса, из-за чего игра зависала после x количества порожденных врагов. Теперь я изменил свой класс Enemy, чтобы использовать группы спрайтов, чтобы я мог убивать свои спрайты после выполнения определенных условий. Проблема, с которой я сталкиваюсь, заключается в том, что луч не удаляется, а счет не увеличивается при столкновении с катером.

Ответы (2)

avatar
Rabbid76
8 мая 2021 в 19:04
0

pygame.sprite.spritecollide использует атрибут rect объектов для обнаружения столкновения. Однако положение носка объекта Projectile сохраняется не в rect, а в атрибутах x и y.

Перед запуском теста на столкновение обновите позицию атрибутаrect с помощью атрибутов x и y:

class Projectile():
    # [...]

    def checkCollision(self, enemy):

        self.rect.x = int(self.x)
        self.rect.y = int(self.y)

        return any(pygame.sprite.spritecollide(self, enemy, True))
for beam in beams[:]:
    if beam.checkCollision(speedboats):
        score += 25
        beams.pop(beams.index(beam))

Дополнительно рекомендую прочитать Как удалить элементы из списка во время итерации?.

de_l3ns
9 мая 2021 в 19:13
1

Спасибо @Rabbid76 Моя IDE выдает мне предупреждение в последней строке. после замены на себя. В нем говорится, что ожидаемый тип Sprite, вместо этого получил Projectile.

avatar
marienbad
8 мая 2021 в 17:17
0

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

pygame.sprite.groupcollide(beams, speedboats, True, True)

Что удалит оба из соответствующих групп.