Вопрос-Ответ

How can I shoot a bullet with the space bar?

Как я могу выстрелить пулей с помощью пробела?

Вот мой код:

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 цикл.

Переведено автоматически
Ответ 1

Общий подход к стрельбе пулями заключается в сохранении позиций пуль в списке (bullet_list). Когда пуля выпущена, добавьте начальную позицию пули ([start_x, start_y]) в список. Начальная позиция - это позиция объекта (игрока или врага), который запускает пулю. Используйте for-цикл для перебора всех маркеров в списке. Переместите положение каждого отдельного маркера в цикле. Удалите маркер из списка, который покидает экран (bullet_list.remove(bullet_pos)). По этой причине необходимо выполнить копию списка (bullet_list[:]) (см. Как удалять элементы из списка во время итерации?). Используйте другой 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))

# [...]

Смотрите также Стрелять пулей.


Пожалуйста, обратите внимание, что в именах классов обычно следует использовать соглашение о заглавных словах. (См. Руководство по стилю для имен классов кода Python)
Это означает, что это должно быть Player и Bullet, а не player и bullet

You have an application loop, so use it. All the objects are continuously updated and drawn in the main application loop, in each frame.

The class Bullet do not need any loop. The constructor has to have parameters for the position (x, y). Further it needs on method which changes the position and one which draws the bullet:

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)

Use a list of bullets. Create a new bullet when space is pressed. Move the bullets (update) in every frame an remove a bullet if it is out of the window. Draw the remaining bullets in every frame:

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

Furthermore use pygame.key.get_pressed() use to get the state of the keys in every frame and to update the position of the player:

while run:

# [...]

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

Complete example:

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 pygame