python - 如何用空格键射击子弹?

标签 python pygame

这是我的代码:

import pygame, os

os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()

win = pygame.display
d = win.set_mode((1200, 600))

class player:
    def __init__(self, x, y, height, width):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.speed = 2

    def draw(self):
        pygame.draw.rect(d, (0, 0, 0), (self.x, self.y, self.width, self.height))

    def move_left(self):
        self.x -= self.speed

    def move_right(self):
        self.x += self.speed


class bullet:
    def __init__(self):
        self.radius = 10
        self.speed = 20


    def shoot(self):
        x = p.x
        y = p.y
        self.shooting = True
        while self.shooting:
            d.fill((98, 98, 98))
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()

            y -= self.speed
            pygame.draw.circle(d, (255, 0, 0), (x, y), self.radius)
            pygame.time.Clock().tick(100)
            win.update()

            if y <= 0:
                self.shooting = False


b = bullet()
p = player(600, 500, 50, 30)
while True:
    d.fill((98, 98, 98))
    p.draw()
    for event in pygame.event.get():
        pass

    if event.type == pygame.KEYDOWN:
        if event.key == pygame.K_SPACE:
            b.shoot()
        if event.key == pygame.K_LEFT:
            p.move_left()
        if event.key == pygame.K_RIGHT:
            p.move_right()

    win.update()

这是我经过几次尝试和错误后想出来的,但确实没有效果。首先,当我按空格键时,播放器消失。我想这很明显,因为我有不同的射击和玩家循环,但我不知道如何绕过它并在同一个循环中实现射击和玩家。

我遇到的第二个问题是破坏 while self.shooting: 循环。当 y 达到某个点时,我尝试通过这样做来打破它:

 if y <= 0:
     self.shooting = False

但这并没有破坏。相反,它会重新开始循环。

我遇到的另一个奇怪的问题是,每次我移动鼠标(稍快)或同时按下一堆按钮时,它都会破坏 while self.shooting 循环。

最佳答案

发射子弹的一般方法是将子弹的位置存储在列表(bullet_list)中。当子弹发射时,将子弹的起始位置 ([start_x, start_y]) 添加到列表中。起始位置是发射子弹的物体(玩家或敌人)的位置。使用 for 循环遍历列表中的所有项目符号。移动循环中每个项目符号的位置。从离开屏幕的列表中删除项目符号 (bullet_list.remove(bullet_pos))。因此,必须运行列表的副本 (bullet_list[:])(请参阅 How to remove items from a list while iterating? )。使用另一个 for 循环来 blit 屏幕上剩余的项目符号:

bullet_list = []

while run == True:
    # [...]

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                bullet_list.append([start_x, start_y])

    for bullet_pos in bullet_list[:]:
        bullet_pos[0] += move_bullet_x
        bullet_pos[1] += move_bullet_y
        if not screen.get_rect().colliderect(bullet_image.get_rect(center = bullet_pos))
            bullet_list.remove(bullet_pos)

    # [...]

    for bullet_pos in bullet_list[:]
        screen.blit(bullet_image, bullet_image.get_rect(center = bullet_pos))

    # [...]

另请参阅Shoot bullet .

<小时/>

请注意,类名通常应使用 CapWords 约定。 (参见Style Guide for Python Code - Class names)
这意味着它必须是 PlayerBullet 而不是 playerbullet

您有一个应用程序循环,因此请使用它。所有对象都在每个帧的主应用程序循环中不断更新和绘制。

Bullet不需要任何循环。构造函数必须具有位置参数(xy)。此外,它还需要一种改变位置的方法和一种绘制子弹的方法:

class Bullet:
    def __init__(self, x, y):
        self.radius = 10
        self.speed = 10
        self.x = x
        self.y = y

    def update(self):
        self.y -= self.speed#

    def draw(self):
        pygame.draw.circle(d, (255, 0, 0), (self.x, self.y), self.radius)

使用项目符号列表。按下 空格 时创建一个新项目符号。在每帧中移动项目符号(更新)remove如果子弹射出窗外,则为子弹。在每一帧中绘制剩余的子弹:

bullets = []

# [...]
while run:

    for event in pygame.event.get():
        # [...]
        if event.type ==  pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                bullets.append(Bullet(p.x+p.width//2, p.y))

    # [...]
    for b in bullets:
        b.update()
        if b.y < 0:
            bullets.remove(b)

    # [...]
    for b in bullets:
        b.draw()

进一步使用pygame.key.get_pressed()用于获取每一帧中关键点的状态并更新玩家的位置:

while run:

    # [...]

    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        p.move_left()
    if keys[pygame.K_RIGHT]:
        p.move_right()

完整示例:

import pygame, os

os.environ["SDL_VIDEO_CENTERED"] = "1"
pygame.init()

win = pygame.display
d = win.set_mode((1200, 600))
clock = pygame.time.Clock()

class Player:
    def __init__(self, x, y, height, width):
        self.x = x
        self.y = y
        self.height = height
        self.width = width
        self.speed = 2

    def draw(self):
        pygame.draw.rect(d, (0, 0, 0), (self.x, self.y, self.width, self.height))

    def move_left(self):
        self.x -= self.speed

    def move_right(self):
        self.x += self.speed


class Bullet:
    def __init__(self, x, y):
        self.radius = 10
        self.speed = 10
        self.x = x
        self.y = y

    def update(self):
        self.y -= self.speed#
    
    def draw(self):
        pygame.draw.circle(d, (255, 0, 0), (self.x, self.y), self.radius)


bullets = []
p = Player(600, 500, 50, 30) 

run = True
while run:
    clock.tick(100)
        
    # handel events
    for event in pygame.event.get():
        if event.type ==  pygame.QUIT:
            run = False
        if event.type ==  pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                bullets.append(Bullet(p.x+p.width//2, p.y))

    # update objects
    keys = pygame.key.get_pressed()        
    if keys[pygame.K_LEFT]:
        p.move_left()
    if keys[pygame.K_RIGHT]:
        p.move_right()
    for b in bullets:
        b.update()
        if b.y < 0:
            bullets.remove(b)

    # clear display
    d.fill((98, 98, 98))

    # draw scene
    for b in bullets:
        b.draw()
    p.draw()

    # update display
    win.update()

关于python - 如何用空格键射击子弹?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59687250/

相关文章:

python - 如何在 python 中使用二进制搜索算法(不实现任何函数)搜索数字

python - 基于Python中的键聚合字典列表上的值

python - pygame.error : file not a windows. bmp 文件(看过其他类似的问题,但到目前为止没有成功)

python - 您如何检测属于 pygame 中 Sprite 类的 2 个表面对象之间的碰撞?

python - 在 Python 的嵌套函数中使用全局变量

python - 未绘制矩形

python - 获取 Pandas 的错误消息/异常的值

python - Pygame:如何生成随机出现和掉落的东西?

python - Raspberry Pi 自动启动程序

python - 我如何获得所有连接?