python - 如何限制我的子弹射程?

标签 python pygame sprite

我的游戏有一个可以左右移动和发射子弹的 Sprite 。但是,如果我射出太多子弹(大约 50 颗左右),我的游戏就会开始滞后很多。我的 sprite 不再流畅地移动并且游戏运行不正常。所以我认为这个问题是所有创建的项目符号都继续在我的屏幕之外运行。这就是为什么我想知道如何为我的子弹设置射程限制。一旦超过该限制,它就会消失并退出程序,这样我的游戏就不会滞后了。但是,我对其他建议持开放态度,例如是否有一种方法可以在不设置范围限制的情况下让我的游戏不滞后。我将我的游戏分成 2 个 .py 文件,一个 main.py 和一个 Sprite1.py,我将它们导入到我的 main.py 文件中。 这是我的 Sprite1.py 文件:

import pygame
import sys
import os
import time
from pygame import mixer
from pygame.locals import *

def showStartScreen(surface):
    show = True
    while (show == True):
        background = pygame.image.load(os.path.join('images', 'Starting_scr.png'))
        # rect = surface.get_rect()
        surface.blit(background, (0,0))
        pygame.display.flip()
        for event in pygame.event.get():
            if event.type == pygame.MOUSEBUTTONDOWN:
                show = False

class Player(pygame.sprite.Sprite):
    def __init__(self, all_sprites):
        pygame.sprite.Sprite.__init__(self)
        self.movex = 0
        self.movey = 0
        self.frame = 0
        self.images = []
        self.imagesleft = []
        self.imagesright = []
        self.direction = "right"
        # self.rect = self.image.get_rect(center=pos)
        self.alpha = (0,0,0)
        self.ani = 4 # animation cycles
        self.all_sprites = all_sprites
        self.add(self.all_sprites)
        self.bullet_timer = .1

        for i in range(1,5):
            img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
            img.convert_alpha()
            img.set_colorkey(self.alpha)
            self.imagesright.append(img)
            self.image = self.imagesright[0]
            self.rect  = self.image.get_rect()

        for i in range(1,5):
            img = pygame.image.load(os.path.join('images','hero' + str(i) + '.png')).convert()
            img = pygame.transform.flip(img, True, False)
            img.convert_alpha()
            img.set_colorkey(self.alpha)
            self.imagesleft.append(img)
            self.image = self.imagesleft[0]
            self.rect  = self.image.get_rect()

    def control(self,x,y):
        '''
        control player movement
        '''
        self.movex += x
        self.movey -= y

    def update(self, dt):
        '''
        Update sprite position
        '''
        self.rect.x = self.rect.x + self.movex
        self.rect.y = self.rect.y + self.movey

        # moving left
        if self.movex < 0:
            self.frame += 1
            if self.frame > 3*self.ani:
                self.frame = 0
            self.image = self.imagesleft[self.frame//self.ani]
            self.direction = "left"

        # moving right
        if self.movex > 0:
            self.frame += 1
            if self.frame > 3*self.ani:
                self.frame = 0
            self.image = self.imagesright[self.frame//self.ani]
            self.direction = "right"

        # self.rect.center = pygame.mouse.get_pos()


        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE]:
            self.bullet_timer -= dt  # Subtract the time since the last tick.
        if self.bullet_timer <= 0:
            self.bullet_timer = 0  # Bullet ready.
            if keys:  # Left mouse button.
                # Create a new bullet instance and add it to the groups.
                if self.direction == "right":
                    Bullet([self.rect.x + self.image.get_width(), self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
                else:
                    Bullet([self.rect.x, self.rect.y + self.image.get_height()/2], self.direction, self.all_sprites)
                self.bullet_timer = .1  # Reset the timer.

class Bullet(pygame.sprite.Sprite):

    def __init__(self, pos, direction, *sprite_groups):
        super().__init__(*sprite_groups)

        self.image = pygame.image.load(os.path.join('images','fireball.png'))
        self.rect  = self.image.get_rect()
        self.sound = pygame.mixer.music.play()
        self.pos = pygame.math.Vector2(pos)
        self.vel = pygame.math.Vector2(750, 0)
        self.direction = direction

    def update(self, dt):
        # Add the velocity to the position vector to move the sprite
        if self.direction == "right":
            #self.vel = pygame.math.Vector2(750, 0)
            self.image = pygame.image.load(os.path.join('images','fireball.png'))
            self.rect  = self.image.get_rect()
            self.pos += self.vel * dt
        else:
            #self.vel = pygame.math.Vector2(-750, 0)
            BULLET_IMG = pygame.image.load(os.path.join('images','fireball.png'))
            self.image = pygame.transform.flip(BULLET_IMG, True, False)
            self.rect  = self.image.get_rect()
            self.pos -= self.vel * dt

        #print(self.pos)
        self.rect.center = self.pos  # Update the rect pos.
        if self.rect.bottom <= 0:
            self.kill()

这是我的 main.py 文件:


import pygame
import os
import sys
import time
from pygame import mixer
import Sprite1

'''
Setup
'''
pygame.init()
width = 960
height = 720
fps = 40        # frame rate
#ani = 4        # animation cycles
clock = pygame.time.Clock()
pygame.display.set_caption('B.S.G.!!!')
surface = pygame.display.set_mode((width, height))
#pygame.mixer.music.load('.\\sounds\\Fairy.mp3')
#pygame.mixer.music.play(-1, 0.0)

pygame.mixer.music.load('.\\sounds\\Fireball.wav')

#direction = "right"

all_sprites = pygame.sprite.Group()
player = Sprite1.Player(all_sprites)

player.rect.x = 50
player.rect.y = 500

steps = 10      # how fast to move

Sprite1.showStartScreen(surface)

'''
Main loop
'''
main = True

while main == True:

    background = pygame.image.load(os.path.join('images', 'Bg.png'))
    surface.blit(background, (0,0))


    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
            main = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT or event.key == ord('a'):
                player.control(-steps,0)
                #direction = "left"
            if event.key == pygame.K_RIGHT or event.key == ord('d'):
                player.control(steps,0)
                #direction = "right"
            if event.key == pygame.K_UP or event.key == ord('w'):
                player.rect.y -= 100
                #player.rect.y -= 10
                #player.movey == 10
                #player.movey == -10
                #time.sleep(1)
                #player.control(0,-steps)

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT or event.key == ord('a'):
                player.control(steps,0)
                #direction = "left"
            if event.key == pygame.K_RIGHT or event.key == ord('d'):
                player.control(-steps,0)
                #direction = "right"
            if event.key == pygame.K_UP or event.key == ord('w'):
                player.rect.y += 100
                #player.movey == -10
            if event.key == ord('q'):
                pygame.quit()
                sys.exit()
                main = False

    # dt = time since last tick in milliseconds.
    dt = clock.tick(60) / 1000
    all_sprites.update(dt)
    player.update(dt)
    all_sprites.draw(surface) #refresh player position
    pygame.display.flip()

P.S.:不要介意我的 sprite 是如何跳跃的,我现在只是这样写的。我会让他稍后在重力作用下真正跳跃。提前致谢。

最佳答案

您已经在顶部检查子弹是否离开屏幕:

if self.rect.bottom <= 0:
    self.kill()

你可以把它改成

if not pygame.display.get_surface().get_rect().colliderect(self.rect):
    self.kill()

杀死根本不在屏幕上的 Sprite 。

但你的问题其实是这样的:

def update(self, dt):
    # Add the velocity to the position vector to move the sprite
    if self.direction == "right":
        #self.vel = pygame.math.Vector2(750, 0)
        self.image = pygame.image.load(os.path.join('images','fireball.png'))
        self.rect  = self.image.get_rect()
        self.pos += self.vel * dt
    else:
        #self.vel = pygame.math.Vector2(-750, 0)
        BULLET_IMG = pygame.image.load(os.path.join('images','fireball.png'))
        self.image = pygame.transform.flip(BULLET_IMG, True, False)
        self.rect  = self.image.get_rect()
        self.pos -= self.vel * dt
    ...

此处您正在加载 fireball.png Bullet 的每个实例一次图像类(class) 每一帧。你的目标是 60 fps,所以当有 50 Bullet例如,您尝试每秒从磁盘加载文件 300 次。

相反,您应该在启动时加载图像一次

它可能是这样的:

class Bullet(pygame.sprite.Sprite):

    IMAGE = None
    FLIPPED_IMAGE = None

    def __init__(self, pos, direction, *sprite_groups):
        super().__init__(*sprite_groups)

        # cache images
        if not Bullet.IMAGE:
            Bullet.IMAGE = pygame.image.load(os.path.join('images','fireball.png'))
            Bullet.FLIPPED_IMAGE = pygame.transform.flip(Bullet.IMAGE, True, False)

        if direction == "right":
            self.vel = pygame.math.Vector2(750, 0)
            self.image = Bullet.IMAGE 
        else:
            self.vel = pygame.math.Vector2(-750, 0)
            self.image = Bullet.FLIPPED_IMAGE 

        # suspicious... Should use the Sound class instead
        # self.sound = pygame.mixer.music.play()
        self.pos = pygame.math.Vector2(pos)
        self.rect  = self.image.get_rect(center=pos)

    def update(self, dt):
        # Add the velocity to the position vector to move the sprite
        self.pos += self.vel * dt
        self.rect.center = self.pos  # Update the rect pos.
        if not pygame.display.get_surface().get_rect().colliderect(self.rect):
            self.kill()

此外,您应该只使用 pygame.mixer.music.play()用于播放背景音乐(因为使用 music.play() 一次只能播放一个文件)。对于音效,最好使用 Sound class .

关于python - 如何限制我的子弹射程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62641717/

相关文章:

android - 创建 Android Sprite 需要什么软件?

python - 为什么我的 ctypes 使用 64 位 python 长尺寸为 4 而不是尺寸 8?

python - 为什么我的 PyArrayObject* 数据​​被截断?

python - 为什么无法在 pygame 中输入任何内容?

rotation - Monogame - Sprite 不围绕原点旋转

reactjs - 如何通过一劳永逸地重新渲染来修复图像闪烁?

Python 3d 图 - 以轴为中心

python - 将 pandas.Series 直方图保存到文件

python - 为按钮设置动画

python - pygame 窗口不会保持全屏