【问题标题】:How can i shoot a bullet with space bar?如何用空格键发射子弹?
【发布时间】:2020-04-28 10:23:03
【问题描述】:

这是我的代码

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 循环。

【问题讨论】:

标签: python pygame


【解决方案1】:

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

使用bullets 的列表。按下 space 时创建一个新项目符号。将每一帧中的子弹 (update) 移动到 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() 来获取每一帧的keys的状态并更新播放器的位置:

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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多