Pygame — столкновение пули и врага без спрайта или классов

#python #pygame #collision-detection #collision #bullet

#python #pygame #обнаружение столкновения #столкновение #пуля

Вопрос:

возникла проблема с выяснением, как работать с обнаружением столкновения между пулей и врагом. Враг сам по себе является классом, однако пули не являются частью класса. Я не могу использовать spritecollide встроенную функцию, потому что я не использовал sprite.Sprite .

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

    import pygame
    import math, random, sys, pygame.mixer, time
    from pygame.locals import *
    pygame.mixer.pre_init(44100, -16, 2, 2048)
    pygame.mixer.init()
    pygame.init()
    jump = False
    jump_offset = 0
    jump_height = 250

    #Defining colours
    BLACK = (   0,   0,   0)
    WHITE = ( 255, 255, 255)
    BLUE = ( 0, 0, 255)

    k = pygame.key.get_pressed()

    #Window Settings
    w = 1280
    h = 720 
    half_w = w /2
    half_h = h /2
    AREA = w*h

    #Initialising the window
    display = pygame.display.set_mode((w,h))
    pygame.display.set_caption("Cattleman") 
    Clock = pygame.time.Clock()
    FPS = 600

    bullets = []
    bulletSprite = pygame.image.load("Bullet1R.png").convert_alpha()
    bulletSprite = pygame.transform.scale(bulletSprite, (20,10))
    shot = pygame.mixer.Sound("pew1.wav")

    global scroll
    scroll = 0
    class Enemy(pygame.sprite.Sprite):
            def __init__(self,x,y,img,):
                    pygame.sprite.Sprite.__init__(self)
                    self.image = pygame.image.load("Enemy.png").convert_alpha()
                    self.image = pygame.transform.scale(self.image,(120,120))
                    self.rect = self.image.get_rect()

                    self.rect.x = x
                    self.rect.y = y
                    self.counter = 0

            def move(self):           
                    speed = 2
                    display.blit(self.image,(self.rect.x,self.rect.y))
                    if self.counter >= 0 and self.counter <= 300: #counter more then 0 but less than distance 
                           self.rect.x  = speed   scroll
                    elif self.counter >= 300 and self.counter <= 600:
                            self.rect.x  = scroll
                    elif self.counter >= 600 and self.counter <= 900: #counter is greater than distance but less than double the distance.
                           self.rect.x -= speed - scroll
                    elif self.counter >= 900 and self.counter <= 1200:
                            self.rect.x  = scroll
                    else:
                           self.counter = 0
                    self.counter  = 1 

    def do_jumping():
            global jump_height
            global jump
            global jump_offset
            if jump:
                    jump_offset  = 6

                    if jump_offset >= jump_height:
                            jump = False
            elif jump_offset > 0 and jump == False:
                    jump_offset -= 6

    #------------------------MAIN PROGRAM LOOP------------------------#
    def game_loop():
        global jump
        global scroll
        background = pygame.image.load("background.png").convert()
        backgroundWidth, backgroundHeight = background.get_rect().size

        stageWidth = backgroundWidth #sets the area which the player can move in
        stagePosX = 0 #Records position of stage as the player moves

        startScrollPosX = half_w

        circleRadius = 25
        circlePosX = circleRadius

        playerPosX = circleRadius
        playerPosY = 602
        playerVelocityX = 0

        playersprite = pygame.image.load("player_spriteR2.png").convert_alpha()
        playersprite = pygame.transform.scale(playersprite, (130,130))
        playerMaxHealth = 100

        next_bullet_time = 0 #Prevents multiple bullets spawning at once.
        bullet_delay = 300 # 0.3 seconds
        direction = True
        gameX = 1000
        enemy = Enemy(210,515,"Enemy.png")
        enemy2 = Enemy(1505,515,"Enemy.png")
        k = pygame.key.get_pressed()

        while True:

            current_time = pygame.time.get_ticks()
            do_jumping()
            for event in pygame.event.get():
                    k = pygame.key.get_pressed()

            if k[K_RIGHT]:
                playerVelocityX = 3 #Moves the player right
                playersprite = pygame.image.load("player_spriteR2.png").convert_alpha()
                playersprite = pygame.transform.scale(playersprite, (130,130))
                direction = True
            if k[K_LEFT]:
                playerVelocityX = -3 #Moves the player left
                playersprite = pygame.image.load("player_spriteL2.png").convert_alpha()
                playersprite = pygame.transform.scale(playersprite, (130,130))
                direction = False
            if k[K_UP] and jump == False and jump_offset == 0:
                    jump = True
            if not k[K_RIGHT] and not k[K_LEFT]:
                    playerVelocityX = 0 #If no input detected, the player does not move
            if k[K_SPACE]:
                    if current_time > next_bullet_time:
                            shot.play()
                            next_bullet_time = current_time   bullet_delay
                            if not direction:
                                bullets.append([circlePosX-90, playerPosY-20 - jump_offset, -6 ])
                            else:
                                bullets.append([circlePosX 30, playerPosY-20 - jump_offset, 6])

            enemy_list = pygame.sprite.Group()
            enemy_list.add(enemy)
            enemy_list.add(enemy2)

            playerPosX  = playerVelocityX
            scroll = 0
            if playerPosX > stageWidth - circleRadius-25: playerPosX = stageWidth - circleRadius-25
            if playerPosX < circleRadius 55:playerPosX = circleRadius 55
            if playerPosX < startScrollPosX: circlePosX = playerPosX
            elif playerPosX > stageWidth - startScrollPosX: circlePosX = playerPosX - stageWidth   w
            else:
                circlePosX = startScrollPosX
                stagePosX  = -playerVelocityX
                scroll = -playerVelocityX

            for b in range(len(bullets)):
                bullets[b][0]  = bullets[b][2]

            width = display.get_width()
            for b in [b for b in bullets if b[0] < 0 or b[0] > width]:
                    bullets.remove(b)

            rel_x = stagePosX % backgroundWidth
            display.blit(background,(rel_x - backgroundWidth, 0))
            if rel_x < w:
                    display.blit(background, (rel_x, 0))

            for bullet in bullets:
                    display.blit(bulletSprite, pygame.Rect(bullet[0], bullet[1], 0, 0))

            display.blit(playersprite, (int(circlePosX-80),playerPosY-100 - jump_offset))

            for e in enemy_list:
                    e.move()

            pygame.display.update()
            Clock.tick(FPS)
            display.fill(BLACK)
    game_loop()
  

Есть идеи?

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

1. @Pygasm дает очень хороший ответ ниже. Но если вы приложите усилия к рефакторингу своего кода для использования спрайтов PyGame, это сэкономит вам много времени (и сделает код более чистым) на протяжении всей остальной части вашего проекта.

2. @Kingsley Это. Как только я узнал, как создать работающий фреймворк sprite, сложность, которую я мог выполнять в своих проектах, значительно возросла.

Ответ №1:

Если вы превратите пули в полноценный pygame.Rect() объект, вы сможете затем использовать pygame.Rect.colliderect . Поэтому…

 # Creating a new bullet
bullets.append(pygame.Rect(X, Y, width, height))
  

И затем…

 # Checking if a bullet has collided
for bullet in bullets:
    for enemy in enemy_list:
        if bullet.colliderect(enemy):
            # Do Damage or Killing code
  

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

1. хорошо, это выглядит как хорошая идея, есть шанс, что вы сможете объяснить myPlayerOrEnemy часть?

2. Кроме того, просто вставьте pygame. Исправьте часть и получите эту ошибку: bullets.append(pygame. Rect(circlePosX 30, playerPosY-20 — jump_offset, 6)) Ошибка типа: аргумент должен быть объектом в стиле rect

3. @JackHarrison myPlayerOrEnemy является переменной-заполнителем, поместите туда прямоугольник, с которым вы хотите, чтобы пуля проверяла, не сталкивается ли он. Что касается pygame.Rect() объекта, я ошибся там. Передайте нужные вам аргументы следующим образом: bullets.append(pygame.Rect(X, Y, Width, Height))

4. Круто, что исправлена первая проблема, я заменил myPlayerorEnemy на my enemy_list , чтобы он проверял каждого врага instace и заставлял его печатать сообщение в оболочке: if bullet.colliderect(enemy_list): print("collision detected") но get: Аргумент должен быть объектом в стиле Rect. Я думал, что id уже сделал класс врага прямоугольным?

5. @JackHarrison Проблема в том, что вы используете массив. Я внес правку, чтобы показать, как это исправить.