Pygame删除对象。

3

我需要帮助删除一个对象,而不是覆盖或其他操作。目前我的代码如下:

def detect_collision(player_pos, enemy_pos):
    p_x = player_pos[0]
    p_y = player_pos[1]

    e_x = enemy_pos[0]
    e_y = enemy_pos[1]

    if (e_x >= p_x and e_x < (p_x + player_size)) or (p_x >= e_x and p_x < (e_x+enemy_size)):
        if (e_y >= p_y and e_y < (p_y + player_size)) or (p_y >= e_y and p_y < (e_y+enemy_size)):
            return True
    return False

def bullets():
    b_x = player_pos[0]
    b_y = player_pos[1]
    keep_going = True
    pygame.draw.rect(screen, TEAL, (b_x, b_y, 15, 50))
    while keep_going:
        b_y += 75
        if detect_collision(player_pos, enemy_pos):
            # deleting part here

这里是我的玩家和敌人的区别:

enemy_size = 50
enemy_pos = [random.randint(0,WIDTH-enemy_size), 0]
enemy_list = [enemy_pos]


def drop_enemies(enemy_list):
    delay = random.random()
    if len(enemy_list) < 10 and delay < 0.1:
        x_pos = random.randint(0,WIDTH-enemy_size)
        y_pos = 0
        enemy_list.append([x_pos, y_pos])

def draw_enemies(enemy_list):
    for enemy_pos in enemy_list:
        pygame.draw.rect(screen, RED, (enemy_pos[0], enemy_pos[1], 
        enemy_size, enemy_size))

def update_enemy_positions(enemy_list, score):
    for idx, enemy_pos in enumerate(enemy_list):
        if enemy_pos[1] >= 0 and enemy_pos[1] < HEIGHT:
            enemy_pos[1] += SPEED
        else:
            enemy_list.pop(idx)
            score += 1
     return score

播放器部分:

player_size = 50
player_pos = [WIDTH/2, HEIGHT-2*player_size]

pygame.draw.rect(screen, TEAL, (player_pos[0], player_pos[1], player_size, 
player_size))

1
除了“删除一个对象”之外,您能否更具体一些?是要从游戏中移除还是从内存中删除?为了得到好的答案,您需要提供所需结果的详细描述。 - Kingsley
我假设从“删除,_不覆盖_或其他事情”(并从用户名中得到提示)可以推断出它是指“从游戏中移除”。 - msanford
我想要删除我创建的子弹和敌人,只是为了明确起见,但你可以只删除子弹,因为你不知道敌人是如何定义的。 - Kromydas
删除指从屏幕上永久移除它,但仍然可以制作该对象的克隆。 - Kromydas
3
Pygame不能这样删除屏幕对象,需要在其上绘制新内容来覆盖原来的对象。对于游戏来说,通常会有一个主循环,每个周期重新绘制整个场景(每秒钟会发生多次)。 - Mike67
显示剩余3条评论
4个回答

2
解决您的问题的最佳方法是学习如何在pygame中使用Sprite对象。与Group对象一起,它们可以立即完成您想要的操作。
简而言之,您的“敌人”应该是某个Sprite子类的实例,并将其添加到Group的一个实例中(而不是构建自己的enemy_list)。当您想让敌人死亡时,可以调用它的kill()方法,这会将其从Group中删除。这有助于从游戏中删除它,因为您应该使用Group对象上的方法来更新和绘制它包含的所有精灵(但不包括已被杀死的精灵)。

0

研究Sprites和SpriteGroups有助于跟踪游戏中的实体。它们内置了许多功能,可以使事情变得更容易。

这里有一个演示,它将精灵分组,并删除与鼠标指针发生碰撞的精灵:

import random
import pygame

screen_width, screen_height = 640, 480

def get_random_position():
    """return a random (x,y) position in the screen"""
    return (
        random.randint(0, screen_width - 1),  # randint includes both endpoints.
        random.randint(0, screen_height - 1),
    )

color_list = ["red", "orange", "yellow", "green", "cyan", "blue", "blueviolet"]
colors = [pygame.color.Color(c) for c in color_list]

class PowerUp(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        width, height = 64, 32
        self.color = random.choice(colors)
        self.image = pygame.Surface([width, height])
        self.image.fill(self.color)
        # Fetch the rectangle object that has the dimensions of the image
        self.rect = self.image.get_rect()
        # then move to a random position
        self.update()

    def update(self):
        # move to a random position
        self.rect.center = get_random_position()

if __name__ == "__main__":
    pygame.init()
    screen = pygame.display.set_mode((screen_width, screen_height))
    pygame.display.set_caption("Sprite Group Collision Demo")
    clock = pygame.time.Clock()  # for limiting FPS
    FPS = 60
    exit_demo = False

    # create a sprite group to track the power ups.
    power_ups = pygame.sprite.Group()
    for _ in range(10):
        power_ups.add(PowerUp())  # create a new power up and add it to the group.

    # main loop
    while not exit_demo:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                exit_demo = True
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    exit_demo = True
                elif event.key == pygame.K_SPACE:
                    power_ups.update()
            elif event.type == pygame.MOUSEBUTTONUP:
                for _ in range(10):
                    power_ups.add(PowerUp())

        # Update State: check for collisions
        for p in power_ups:
            if p.rect.collidepoint(pygame.mouse.get_pos()):
                power_ups.remove(p)
        # draw background
        screen.fill(pygame.Color("black"))  # use black background
        # draw sprites
        power_ups.draw(screen)
        # update screen
        pygame.display.update()
        clock.tick(FPS)
    pygame.quit()
    quit()

点击鼠标按钮会创建更多的精灵,按下空格键会随机它们的位置。
子弹精灵的update()方法将通过其速度调整精灵的位置,例如:self.rect.x += SPEED,您需要在每个游戏循环中调用子弹精灵组的.update()方法。

0

好的,所以你有一个敌人位置列表enemy_list。这是一个不错的开始。我没有看到bullet_list,所以我会假设一次只有一个子弹,在b_xb_y处。

因此,这个程序的主循环可能看起来像:

### Main Loop
while not game_over:
    
    # handle user input

    # move the player
    # move the bullet (if any)
    # move the enemies

    # if there's a bullet, did it hit an enemy?
       # remove enemy hit from enemy_list

    # Did an enemy in enemy_list, hit the player?
       # do game-over

    # clear the screen
    # paint the player 
    # paint the bullet (if any)
    # paint every enemy in enemy_list

敌人碰撞和列表删除可能看起来像下面这样。(我尽可能地匹配了您的代码外观。)

# if a bullet is on-screen (non 0,0), see if it hits an enemy
if ( b_x != 0 and b_y != 0 ):
    hit_enemy_idx = None
    for idx, enemy_pos in enumerate( enemy_list ):
        # check for collision
        if detect_collision( ( b_x, b_y ), enemy_pos ):
            hit_enemy = idx      # note the enemy index
            b_x, b_y  = 0, 0     # erase the bullet
            break                # exit the loop when hit found

    # If the bullet hit an enemy, remove from list
    if hit_enemy_idx != None:
        del( enemy_list[ hit_enemy_idx ] )      # delete hit enemy from list

我们遍历敌人列表,检查是否发生碰撞。一旦发生碰撞,它会保存被击中的敌人的索引并停止循环。

下一步是从列表中删除敌人。我已经将此写在了一个单独的块中,而不是放在循环中的break之前。这是因为当您在迭代过程中更改列表时,可能会出现意外的结果。在这种特殊情况下,这样做是可以的,但对于初学者来说要谨慎。


0
我假设屏幕上一次只有一个子弹,因为您没有提到子弹列表。您可能通过按空格或其他方式创建子弹,这里我将不予考虑。在您的bullets()函数中需要考虑的一件事是,您正在同一函数中进行移动、绘制和检查碰撞。请注意,让一个函数只做一件事情总是一个好主意。
def draw_bullet():
    move_bullet()
    pygame.draw.rect(screen, TEAL, (b_x, b_y, 15, 50))
def move_bullet():
    if b_y < HEIGHT:
        b_y += 75
    else:
        create_bullet = False # explained below

因此,要创建一个子弹,您应该有一个布尔变量create_bullet。所以:

# mainloop
if user hits spacebar (or the key used to create bullet) : 
     create_bullet = true
     b_x = player_pos[0] # initialise bullet
     b_y = player_pos[1]
if create_bullet:
    draw_bullet()
if detect_collision((b_x, b_y), enemy_pos): 
    # assuming b_x, b_y are global variable or something, so that they are actually defined and equal to bullet's x and y pos
    # if bullet and enemy collide, remove them both
    enemy_list.remove(enemy)
    create_bullet = False
if detect_collision(player_pos, enemy_pos): 
    # reset player pos, or whatever you want to do

你说你想要删除它而不仅仅是覆盖它。然而,pygame生成“移动/视频”屏幕的方式就是不断地覆盖绘制。例如:玩家在(10, 10)处被绘制,然后在(20, 10)处被绘制,这样看起来就像玩家移动了。但是,这个过程非常快,所以你看不到他“消失”和“重新出现”。所以以上代码的作用如下。

当按下空格键时,它通过将子弹的x和y值设置为当前玩家位置并将create_bullet = true来“创建”子弹。然后,在主循环的每次迭代中,如果create_bullet为true,则移动并绘制子弹。如果子弹移动到屏幕外或与敌人碰撞,则create_bullet = False,因此它将停止绘制,并在下一个主循环迭代中,子弹将被背景覆盖并“消失”。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接