Python 如何让我的大炮在pygame中持续开火

Python 如何让我的大炮在pygame中持续开火,python,python-3.x,pygame,Python,Python 3.x,Pygame,在我的游戏中,我可以在玩家的位置放置加农炮。我能发射一次大炮,但不能重复多次发射过程。我希望子弹在移动一定距离并重复射击过程后,能重置为初始值。我在下面附上我的全部代码以及放置大炮的部分。谢谢你的帮助 import pygame import random import math pygame.font.init() width = 900 height = 600 screen = pygame.display.set_mode([width, height]) walkRight =

在我的游戏中,我可以在玩家的位置放置加农炮。我能发射一次大炮,但不能重复多次发射过程。我希望子弹在移动一定距离并重复射击过程后,能重置为初始值。我在下面附上我的全部代码以及放置大炮的部分。谢谢你的帮助

import pygame
import random
import math

pygame.font.init()

width = 900
height = 600

screen = pygame.display.set_mode([width, height])

walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'),
             pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'),
             pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]

walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load('L3.png'),
            pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'),
            pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]

char = pygame.image.load('standing.png')
bomb_pic = pygame.transform.scale(pygame.image.load('bomb.png'), (20, 20))
bomb_explosion = pygame.transform.scale(pygame.image.load('explosion1.png'), (40, 40))

pics = [bomb_pic, bomb_explosion]
shop = pygame.transform.scale(pygame.image.load("shop.png"), (60, 60))
boss = pygame.image.load("enemyboss.png")

player = [walkLeft, walkRight, char]

enemy_Left = [pygame.image.load('L1E.png'), pygame.image.load('L2E.png'), pygame.image.load('L3E.png'),
              pygame.image.load('L4E.png'), pygame.image.load('L5E.png'), pygame.image.load('L6E.png'),
              pygame.image.load('L7E.png'), pygame.image.load('L8E.png'), pygame.image.load('L9E.png')]
enemy_pic = pygame.image.load('L1E.png')

boss = pygame.image.load('pixel_monster.png')
cannon = pygame.image.load('tank_cannon.png')
bullet = pygame.image.load('bullet.png')

position = [60, 60]
x = 50  # same as position
y = 50  # same as position
width = 40
height = 60
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
down = False
up = False
walkCount = 0
run_once = False

enemy_list = []

clock = pygame.time.Clock()
FPS = 60

font = pygame.font.Font('freesansbold.ttf', 32)
font_large = pygame.font.Font('freesansbold.ttf', 45)
items_font = pygame.font.Font('freesansbold.ttf', 16)
font_small = pygame.font.Font('freesansbold.ttf', 18)
font_tiny = pygame.font.Font('freesansbold.ttf', 13)
font_verytiny =pygame.font.Font('freesansbold.ttf', 9)

bombs = []
explosions = []

bag = {'bomb': 0, 'heal': 0, 'cannon': 0}

health = 100
base_health = 150
normal_enemies = []
kills = 0
cannon_list = []
bullet_list = []


class Button():
    def __init__(self, color, x, y, width, height, text=''):
        self.color = color
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.text = text

    def draw(self, win, outline=None):

        # Call this method to draw the button on the screen
        if outline:
            pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)

        pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)

        if self.text != '':
            font = pygame.font.SysFont('comicsans', 20)
            text = font.render(self.text, 1, (0, 0, 0))
            win.blit(text, (
                self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))


def shop_run():
    bright_green = (0, 255, 0)
    green = (0, 200, 0)

    shop_bomb = Button((0, 200, 0), 820, 150, 70, 20, text="Bomb_b")
    shop_bomb.draw(screen)

    shop_heal = Button((0, 200, 0), 820, 120, 70, 20, text="Heal_h")
    shop_heal.draw(screen)

    shop_cannon = Button((0, 200, 0), 820, 180, 70, 20, text="Cannon_c")
    shop_cannon.draw(screen)


def walk():
    global walkCount
    global walkcount

    if walkCount + 1 >= 27:
        walkCount = 0

    if left:
        screen.blit(player[0][walkCount // 3], (x, y))
        walkCount += 1

    elif right:
        screen.blit(player[1][walkCount // 3], (x, y))
        walkCount += 1

    elif down:
        screen.blit(player[2], (x, y))
        walkcount = 0

    elif up:
        screen.blit(player[2], (x, y))
        walkcount = 0

    else:
        screen.blit(player[2], (x, y))
        walkCount = 0


def enemy_spawn(number_of_enemies):
    global normal_enemies
    global health
    global base_health
    global kills

    # for random_velocity in range(number_of_enemies):
    player_rect = pygame.Rect(x+20, y+20, 20, 20)
    for ne in range(number_of_enemies):
        random_velocity = random.uniform(0.3, 1.3)
        random_enemy_location_y = random.randrange(170, 470)
        random_enemy_location_x = random.randrange(800, 1000)
        normal_enemies.append([random_enemy_location_x, random_enemy_location_y, random_velocity])
        # print(normal_enemies[ne][0], normal_enemies[ne][1], normal_enemies[ne][2])

    for e in range(number_of_enemies):
        ex, ey, evel = normal_enemies[e]
        screen.blit(enemy_pic, (ex, ey))
        if ex > 75:
            normal_enemies[e][0] -= evel
        else:
            base_health -= 0.02

        normal_enemy_rect = pygame.Rect(ex, ey, 50, 50)

        if player_rect.colliderect(normal_enemy_rect):
            health -= 0.2  

        for j in reversed(range(len(explosions))):
            pos, end_time_2, hurt = explosions[j] 
            explosion_rect = pygame.Rect(pos[0], pos[1], 20, 20)
            if explosion_rect.colliderect(normal_enemy_rect):
                normal_enemies.pop(e) 
                kills += 1   


def redrawGameWindow():
    global walkCount
    global font
    global font_small
    global font_tiny
    global font_verytiny
    global bag
    global items_font
    global enemy_list
    global pics
    global position
    global health
    global base_health
    global run_once
    global explosions
    global bullet_list

    current_time = pygame.time.get_ticks()

    dx = []
    dy = []
    dist = []
    screen.fill([166, 166, 166])

    pygame.draw.rect(screen, (220, 0, 0), (700, 500, 100, 100))
    # for five_enemies in range(5):
    #     random_enemy_location_y = random.randrange(170, 470)
    #     random_enemy_location_x = random.randrange(700, 840)
    #     enemy_list.append([random_enemy_location_x, random_enemy_location_y])

    # for enemies in range(5):
    #     screen.blit(enemy_Left[enemies], enemy_list[enemies])
    #     dx.append(position[0] - enemy_list[enemies][0])
    #     dy.append(position[1] - enemy_list[enemies][1])
    #     dist.append(math.hypot(dx[enemies], dy[enemies]))
    #     dx[enemies], dy[enemies] = dx[enemies] / dist[enemies], dy[enemies] / dist[enemies]

    #     enemy_list[enemies][0] += dx[enemies] * 2
    #     enemy_list[enemies][1] += dy[enemies] * 2


    pygame.draw.rect(screen, (70, 0, 220), (0, 120, 100, 400))  # main base
    pygame.draw.rect(screen, (220, 0, 0), (50, 470, 5, -300))
    pygame.draw.rect(screen, (0, 220, 0), (50, 470, 5, -base_health*2))
    screen.blit(font.render("B", True, (0, 0, 0)), (10, 200 + 40))
    screen.blit(font.render("A", True, (0, 0, 0)), (10, 235 + 40))
    screen.blit(font.render("S", True, (0, 0, 0)), (10, 270 + 40))
    screen.blit(font.render("E", True, (0, 0, 0)), (10, 305 + 40))

    enemy_spawn(5)
    # cannon_balls()


    pygame.draw.rect(screen, (0, 0, 0), (800, 0, 100, 600))
    if x + char.get_width() < 60 and y + char.get_height() < 60:
        shop_run()

    screen.blit(shop, (0, 0))
    screen.blit(font_small.render("Shop", True, (0, 0, 0)), (5, 5))

    pygame.draw.rect(screen, (220, 0, 0), (position[0] - 3, position[1], 50, 5))
    pygame.draw.rect(screen, (0, 220, 0), (position[0] - 3, position[1], health/2, 5))

    screen.blit(font.render("Menu", True, (255, 255, 255)), (805, 10))
    screen.blit(items_font.render("Bombs: " + str(bag["bomb"]), True, (255, 255, 255)), (805, 550))
    screen.blit(items_font.render("Heal: " + str(bag["heal"]), True, (255, 255, 255)), (805, 570))
    screen.blit(items_font.render("Cannon: " + str(bag["cannon"]), True, (255, 255, 255)), (805, 530))

    # screen.blit(bullet, (450, 300))
    # screen.blit(bomb_explosion, (450, 300))
    # screen.blit(boss, (450, 300))

    walk()

    for i in reversed(range(len(bombs))):
        pos, end_time = bombs[i]
        if current_time > end_time:
            end_time_2 = end_time + 5000
            pos2 = (pos[0] - 10, pos[1] - 20)
            explosions.append((pos2, end_time_2, False))
            bombs.pop(i)
        else:
            screen.blit(pics[0], pos)

    for j in reversed(range(len(explosions))):
        pos, end_time_2, hurt = explosions[j]
        if current_time > end_time_2:
            explosions.pop(j)
        else:
            screen.blit(pics[1], pos)

            if not hurt:
                explosion_rect = pygame.Rect(pos[0], pos[1], 20, 20)
                player_rect = pygame.Rect(x+20, y+20, 20, 20)
                if player_rect.colliderect(explosion_rect):
                    explosions[j] = (pos, end_time_2, True)
                    health -= 5
                    # print(health)
    for i in cannon_list:
        screen.blit(cannon, i)
    for j in bullet_list:
        screen.blit(bullet, j)
        j[0] += 3

    screen.blit(font_tiny.render("Health: " + str("{:.2f}".format(health)), True, (255, 255, 255)), (805, 60))
    screen.blit(font_verytiny.render("Base Health: " + str("{:.2f}".format(base_health)), True, (255, 255, 255)), (805, 90))
    screen.blit(font_tiny.render("Kills: " + str(kills), True, (255, 255, 255)), (805, 110))

    pygame.display.update()


def main():
    run = True
    pygame.display.set_caption("bomb-mania")

    global x
    global y
    global width
    global height
    global vel

    global left
    global right
    global down
    global up

    global walkCount

    global bomb_pic

    global font
    global bombs
    global explosions
    global position
    global health

    global kills
    global cannon_list
    global bullet_list

    while run:

        current_time = pygame.time.get_ticks()
        redrawGameWindow()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
                run = False

            shop_rect = pygame.Rect(0, 0, 40, 40)
            player_rect = pygame.Rect(x+20, y+20, 20, 20)

            if player_rect.colliderect(shop_rect):
                buy = pygame.key.get_pressed()
                if buy[pygame.K_b]:
                    bag["bomb"] += 1
                    # print(bag["bomb"])
                if buy[pygame.K_h]:
                    bag["heal"] += 1

                if buy[pygame.K_c] and kills > 3:
                    kills -= 3
                    bag["cannon"] += 1 
                    # print(bag["cannon"])  

            if event.type == pygame.KEYDOWN and not player_rect.colliderect(shop_rect):
                if (event.key == pygame.K_SPACE or event.key == pygame.K_b) and bag["bomb"] >= 1:
                    current_time_2 = pygame.time.get_ticks()
                    pos = x + char.get_width() / 2, y + char.get_height() - 20
                    pos2 = ((x + char.get_width() / 2) - 10), (y + char.get_height() - 30)
                    end_time = current_time + 3000  # 3000 milliseconds = 3 seconds
                    bombs.append((pos, end_time))
                    bag["bomb"] -= 1

                if event.key == pygame.K_h and not player_rect.colliderect(shop_rect) and health < 90 and bag["heal"] >= 1:
                    health += 10
                    bag["heal"] -= 1 

                if event.key == pygame.K_c and not player_rect.colliderect(shop_rect):
                    print("reached")
                    cannon_list.append([x,y])
                    bullet_list.append([x,(y-20)])

        if health <= 0 or base_health <= 0:
            main_menu()
        keys = pygame.key.get_pressed()

        if keys[pygame.K_LEFT] and x > vel - 15:
            x -= vel
            position[0] -= vel
            left = True
            right = False
            down = False
            up = False
            # print(position)

        elif keys[pygame.K_RIGHT] and x < 800 - vel - width:
            x += vel
            position[0] += vel
            left = False
            right = True
            down = False
            up = False
            # print(position)

        elif keys[pygame.K_DOWN] and y < 600 - height:
            y += vel
            position[1] += vel
            left = False
            right = False
            down = True
            up = False
            # print(position)

        elif keys[pygame.K_UP] and y > vel - 15:
            y -= vel
            position[1] -= vel
            left = False
            right = False
            down = False
            up = True
            # print(position)

        else:
            left = False
            right = False
            down = False
            up = False
            walkCount = 0

        clock.tick(FPS)
        pygame.display.flip()

def main_menu():
    global width
    global height
    global health
    global base_health
    global bag
    global position
    global x
    global y 
    global left
    global right
    global down
    global up
    global walkCount
    global normal_enemies
    global explosions
    global bombs
    global enemy_list
    global kills
    global cannon_list


    cannon_list =[]
    kills = 0
    enemy_list = []
    normal_enemies = []
    bombs = []
    explosions = []
    position = [60, 60]
    x = 50  # same as position
    y = 50  # same as position
    left = False
    right = False
    down = False
    up = False
    walkCount = 0

    enemy_vel = 2
    enemy_list = []
    bag["bomb"] = 0
    bag["heal"] =0
    health = 100
    base_health = 150
    pygame.display.set_caption("Main Menu")
    run = True
    bright_green = (0, 255, 0)
    green = (0, 200, 0)
    screen.fill((163, 163, 194))

    while run:
        mouse = pygame.mouse.get_pos()
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
                run = False

            if 400 + 100 > mouse[0] > 400 and 275 + 50 > mouse[1] > 275:
                pygame.draw.rect(screen, bright_green, (400, 275, 100, 50))

                if event.type == pygame.MOUSEBUTTONDOWN:
                    main()
            else:
                pygame.draw.rect(screen, green, (400, 275, 100, 50)) 

            screen.blit(font_large.render("Bomb-Mania", True, (255, 255, 255)), (325, 50)) 
            screen.blit(font.render("Play", True, (0, 0, 0)), (417, 285)) 


        pygame.display.flip() 
        clock.tick(FPS)       

main_menu()
这是重画GameWindow()的一部分

编辑

下面给出了我为跟踪行驶距离所做的更改

for i in cannon_list:
    screen.blit(cannon, i)
for j in bullet_list:
    screen.blit(bullet, (j[0], j[1]))
    j[3] = j[0]
    if j[0] == j[3]:
        j[0] += 3
        j[2] += 3
    if j[2] >= 100:
        j[0] = j[3]
编辑2 我正在实现OOP,请帮我调试

class Cannon():
    global cannon_list
    global bullet_list
    def __init__(self, x, y, track, old_x):
        self.x = x
        self.y = y
        self.track = track
        self.old_x = old_x

    def spawnBullet(self):
        for j in bullet_list:
            self.old_x = j[3]
            self.track = j[2]
            screen.blit(bullet, (j[0], j[1]))

    def moveBullet(self):
        if self.x <= self.track:
            self.x += 3
            self.track += 3

    def resetBullet(self):
        if self.x >= self.track:
            self.x = self.old_x

    def spawnCannon(self):
        for i in cannon_list:
            screen.blit(cannon, i)

你说你想让佳能的子弹飞一段固定的距离,然后再重新点火。你做了什么来达到这个目的

这似乎是导致项目符号移动的代码:

for j in bullet_list:
    screen.blit(bullet, j)
    j[0] += 3
这里没有任何东西在它经过特定距离后阻止它或触发重新发射

您的代码将从面向对象的重构和类的使用中受益匪浅,特别是我建议您将player、敌军、canon.bullet设置为类。它不仅可以清理代码,而且可以更简单地跟踪对象以及每个对象所需的所有各自的状态信息

例如,对于您来说,子弹经过一定距离后重新发射的问题。目前,您保存在子弹上的唯一信息是它的位置。要使它在经过一定距离后停止,您还需要知道它的初始位置或它自发射以来已经移动了多远。要再次发射,您需要如果你只是想从同一个地方重新启动(假设佳能是静止的),你可以知道它是从什么地方发射的,或者可能只是它的初始位置.如果子弹击中了什么东西呢?佳能能否立即重新发射,或者它是否需要等待与没有击中任何东西一样长的时间,并且必须全程飞行?如果以后你想让你的佳能受到速度限制,或者什么的,而不是一次只发射一颗现有的子弹,你需要状态信息佳能中关于发射率和上次发射时间的信息

将元素结构化为对象可以让您将每个对象的每个实例的所有特定状态信息清晰地保存在一起。这使得您可以更简单地在需要时修改行为,因为可以包含与对象相关的逻辑,并且您知道它们都在哪里。随着代码变得越来越大,这一点非常重要d更复杂,但无论如何都是良好的实践

当您请求帮助时,或者如果您要将项目传递给其他人时,它通常也会使其他人更容易查看、理解您的代码

操作后编辑基于评论的修改问题:

您编辑了代码并添加了以下内容:

for j in bullet_list:
    screen.blit(bullet, (j[0], j[1]))
    j[3] = j[0]
    if j[0] == j[3]:
        j[0] += 3
        j[2] += 3
    if j[2] >= 100:
        j[0] = j[3]
这是没有意义的。如果j[0]==j[3]:行将始终为真,因为在它前面的行中,您设置了
j[3]=j[0]
。 我想你要做的是把初始位置和行驶距离的状态信息与x,y位置一起放在列表中,
j[3]
应该是初始位置,
j[2]
是距离?我根本不会这样做,但是……你可以试一下:

bullet_list.append([x,(y+25),0, x])


再次强调,你真的应该使用一个类来完成这个任务,而不是试图将状态作为列表的一部分。

谢谢你的建议。我仍然不太擅长OOP,但我正在练习。为了回答你关于我尝试实现refire过程的问题,我尝试创建一个变量
traveled
,以跟踪差异e我的子弹移动了,但似乎不起作用。我希望能就如何实施我的重新发射提出一些建议。谢谢。@rishi正如我上面所说,你需要知道它移动了多远才能阻止它。你说你保留了一个
移动的
变量,但请记住,每个变量必须是不同的子弹。然后你必须将每颗子弹的移动距离与最大值进行比较。在这一点上,你必须删除该子弹并创建一个新的(从它的起点开始-拍摄这颗子弹的佳能)或者将当前项目符号的位置重置为其起点。这要求您知道射出项目符号的佳能或起点注释继续-这里的要点是,您需要更多与项目符号相关的状态,而不仅仅是其当前位置。这最好通过将其全部放在一个类中来实现。即使您不知道将项目符号的逻辑移到类中(这是个好主意)你至少可以使用一个类实例来保存它的所有状态信息。我已经对我的问题做了一些更改。你可以看一下,让我知道我做错了什么。另外,我打算在我确定我的代码有效后,为我的代码创建类。正如我之前所说,我仍然在学习OOP,并且发现它有点棘手,所以我将一旦我用我所知道的创建了这个游戏,就用类重新创建它。
for j in bullet_list:
    cannonsAndBullets = Cannon(j[0], j[1], j[2], j[0])
    cannonsAndBullets.spawnCannon()
    cannonsAndBullets.spawnBullet()
    cannonsAndBullets.moveBullet()
    cannonsAndBullets.resetBullet()
for j in bullet_list:
    screen.blit(bullet, j)
    j[0] += 3
for j in bullet_list:
    screen.blit(bullet, (j[0], j[1]))
    j[3] = j[0]
    if j[0] == j[3]:
        j[0] += 3
        j[2] += 3
    if j[2] >= 100:
        j[0] = j[3]
bullet_list.append([x,(y+25),0, x])
for j in bullet_list:
    screen.blit(bullet, (j[0], j[1]))
    j[0] += 3
    j[2] += 3
    if j[2] >= 100:
        j[0] = j[3]