You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame开发射击功能时子弹无法向上、向左发射问题求助

问题描述

我是Pygame初学者,正尝试制作一个持枪的小人物角色,但子弹无法向上或向左发射,向右、向下的子弹移动逻辑完全正常,始终无法定位问题根源。

原代码
import pygame
pygame.init()

gameScreen = pygame.display.set_mode()
pygame.display.set_caption('solo attempt')

clock = pygame.time.Clock()

class player(object):
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.vel = 8
        self.facing = 1
    
    def draw(self, gameScreen):
        pygame.draw.rect(gameScreen, (255, 0, 0), (self.x, self.y, self.width, self.height))

class gun(object):
    def __init__(self, startx, starty):
        self.startx = startx
        self.starty = starty
        self.endx = self.startx
        self.endy = self.starty
        self.up = False
        self.down = False
        self.left = False
        self.right = False

    
    def draw(self, gameScreen):
        pygame.draw.line(gameScreen, (0, 0, 255), (self.startx, self.starty), (self.endx, self.endy))

class bulletThing(object):
    def __init__(self, x, y, radius):
        self.x = x
        self.y = y
        self.radius = radius
        self.verticalVel = 12 * vertical
        self.horizontalVel = 12 * horizontal

        print(self.verticalVel, self.horizontalVel)
    
    def draw(self, gameScreen):
        pygame.draw.circle(gameScreen, (0, 255, 0), (self.x, self.y), self.radius)

#updates screen
def drawScreen(gameScreen):
    gameScreen.fill((0, 0, 0))
    player.draw(gameScreen)
    gun.draw(gameScreen)
    for bullet in bullets:
        bullet.draw(gameScreen)
    pygame.display.update()

#create player and gun and bullets list
player = player(50, 50, 64, 64)
gun = gun(player.x + (player.width / 2), player.y + (player.height / 2))
bullets = []

vertical = 0
horizontal = 1

shootLoop = 0
dimensions = gameScreen.get_size()

#main loop
running = True
while running:
    clock.tick(30)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    
    #shot delay
    if shootLoop > 0:
        shootLoop += 1
    if shootLoop > 3:
        shootLoop = 0

    #bullet movement
    for bullet in bullets:
        if bullet.x < dimensions[0] and bullet.x > 0:
            bullet.x += bullet.horizontalVel
        else:
            bullets.pop(bullets.index(bullet))

        if bullet.y < dimensions[1] and bullet.y > 0:
            bullet.y += bullet.verticalVel
        else:
            bullets.pop(bullets.index(bullet))


    keys = pygame.key.get_pressed()

    #move left
    if keys[pygame.K_a]:
        if player.x > 0:
            player.x -= player.vel
        if gun.startx > 0 + player.width / 2:
            gun.startx -= player.vel
            gun.endx -= player.vel

    #move right
    if keys[pygame.K_d]:
        if player.x < dimensions[0] - player.width:
            player.x += player.vel
        if gun.startx < dimensions[0] - player.width / 2:
            gun.startx += player.vel
            gun.endx += player.vel

    #move up
    if keys[pygame.K_w]:
        if player.y > 0 + player.height / 2:
            player.y -= player.vel
        if gun.starty > 0:
            gun.starty -= player.vel
            gun.endy -= player.vel

    #move down
    if keys[pygame.K_s]:
        if player.y < dimensions[1] - player.height:
            player.y += player.vel
        if gun.starty < dimensions[1] - player.height / 2:
            gun.starty += player.vel
            gun.endy += player.vel

#top "gun"'s for visuals
    #aim up and left
    if keys[pygame.K_UP] and keys[pygame.K_LEFT]:
        gun.endy = gun.starty
        gun.endy -= 64
        gun.endx = gun.startx
        gun.endx -= 64

        gun.up = True
        gun.down = False
        gun.left = True
        gun.right = False

    #aim up and right
    elif keys[pygame.K_UP] and keys[pygame.K_RIGHT]:
        gun.endy = gun.starty
        gun.endy -= 64
        gun.endx = gun.startx
        gun.endx += 64

        gun.up = True
        gun.down = False
        gun.left = False
        gun.right = True

    #aim down and left
    elif keys[pygame.K_DOWN] and keys[pygame.K_LEFT]:
        gun.endy = gun.starty
        gun.endy += 64
        gun.endx = gun.startx
        gun.endx -= 64

        gun.up = False
        gun.down = True
        gun.left = True
        gun.right = False

    # aim down and right
    elif keys[pygame.K_DOWN] and keys[pygame.K_RIGHT]:
        gun.endy = gun.starty
        gun.endy += 64
        gun.endx = gun.startx
        gun.endx += 64

        gun.up = False
        gun.down = True
        gun.left = False
        gun.right = True

    #aim up
    elif keys[pygame.K_UP]:
        gun.endx = gun.startx
        gun.endy = gun.starty
        gun.endy -= 64

        gun.up = True
        gun.down = False
        gun.left = False
        gun.right = False

    #aim down
    elif keys[pygame.K_DOWN]:
        gun.endx = gun.startx
        gun.endy = gun.starty
        gun.endy += 64

        gun.up = False
        gun.down = True
        gun.left = False
        gun.right = False

    #aim left
    elif keys[pygame.K_LEFT]:
        gun.endy = gun.starty
        gun.endx = gun.startx
        gun.endx -= 64

        gun.up = False
        gun.down = False
        gun.left = True
        gun.right = False

    #aim right
    elif keys[pygame.K_RIGHT]:
        gun.endy = gun.starty
        gun.endx = gun.startx
        gun.endx += 64
    
        gun.up = False
        gun.down = False
        gun.left = False
        gun.right = True

    #bullet creation
    if keys[pygame.K_SPACE] and shootLoop == 0:
        bullets.append(bulletThing(round(player.x + player.width / 2), round(player.y + player.height / 2), 6))

        #sets bullet movement to up, down, left, or right
        if gun.up:
            vertical = -1
        else:
            vertical = 0
        if gun.down:
            vertical = 1
        else:
            vertical = 0
        if gun.left:
            horizontal = -1
        else:
            horizontal = 0
        if gun.right:
            horizontal = 1
        else:
            horizontal = 0

        shootLoop = 1
    drawScreen(gameScreen)

pygame.quit()
问题原因

代码里有两个核心bug导致子弹无法向左、向上发射:

  1. 赋值顺序错误:创建bulletThing实例的代码在设置vertical/horizontal方向值之前,子弹初始化时读取的是上一帧的方向参数,不是当前瞄准的方向。初始全局变量vertical=0、horizontal=1,默认就是向右的状态。
  2. 方向值被覆盖:四个方向判断都带了else分支重置数值,比如判断gun.up为真把vertical设为-1后,下一个判断gun.down为假,会直接走else把vertical重置为0,向上的速度直接被清零;向左的horizontal值同理,会被后续判断gun.right的else分支重置为0,所以向左、向上的子弹永远没有对应方向的速度。
  3. 额外隐患:遍历子弹列表时直接在原列表调用pop()删除元素,会导致列表索引错位,可能漏判子弹边界。
修复方案
  • 调整射击逻辑的顺序:先计算当前瞄准方向的vertical、horizontal值,再实例化子弹对象。
  • 修正方向赋值逻辑:先把vertical、horizontal初始化为0,再根据对应方向标记赋值,不要用连续的else重置数值,避免参数被覆盖。
  • 遍历子弹时遍历列表副本,避免删除元素导致的索引错误。

修复后的核心逻辑代码参考:

#bullet creation
if keys[pygame.K_SPACE] and shootLoop == 0:
    # 先计算方向值
    vertical, horizontal = 0, 0
    if gun.up:
        vertical = -1
    if gun.down:
        vertical = 1
    if gun.left:
        horizontal = -1
    if gun.right:
        horizontal = 1
    # 方向计算完成后再创建子弹
    bullets.append(bulletThing(round(player.x + player.width / 2), round(player.y + player.height / 2), 6))
    shootLoop = 1

# 子弹移动逻辑修正,遍历列表副本避免索引错误
for bullet in bullets[:]:
    bullet.x += bullet.horizontalVel
    bullet.y += bullet.verticalVel
    # 超出屏幕边界直接删除
    if bullet.x < 0 or bullet.x > dimensions[0] or bullet.y <0 or bullet.y > dimensions[1]:
        bullets.remove(bullet)

内容的提问来源于stack exchange,提问作者randomperson2114

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 09:36:23