首页 > 解决方案 > 如何让我的 pygade 代码运行得更快?它仅以 4fps 运行

问题描述

我正在尝试在 pygame 中制作一个简单的 2d 游戏,由于某种原因,它只能以 4fps.h 运行,这导致它非常滞后和不稳定。我查看了其他建议 convert() 的问题,但我没有任何图像。有什么办法让它更快??我希望它至少运行 40 fps。我目前正在研究 MacO。到目前为止,这是我的代码:

import math
import sys
import pygame


from pygame.locals import *



pygame.init()
BLACK = (0,0,0)
WHITE = (255,255,255)
GREEN = (0,255,0)
RED = (255,0,0)
BLUE=(0,0,255)
PI = 3.141592653
font = pygame.font.SysFont('Times',12, True,False)
def write_text(text, pos,color):
    hi = font.render(text, True,color)
    screen.blit(hi, pos)
def draw_label_rect(text,color,object):
    pygame.draw.rect(screen, object.color, object.Display_Rect)
    hi =font.render( text, True, color)
    center_x = object.pos[0]+ 1/2*object.width
    center_y =object.pos[1] + 1/2 * object.length
    text_width = hi.get_width()
    text_height = hi.get_height()
    screen.blit(hi, (math.floor(center_x-1/2*text_width),math.floor(center_y-1/2*text_height)))
def draw_image_label_rect_centered(image, color, pos,scale_factor):
    pygame.draw.rect(screen, color,pos)
    image = pygame.image.load(image).convert_alpha()
    width = image.get_width()
    height = image.get_height()
    image2 = pygame.transform.smoothscale(image,(math.floor(width*scale_factor),math.floor(height*scale_factor)))
    new_width = image2.get_width()
    new_height = image2.get_height()

    center_x = pos[0]+ 1/2*pos[2]
    center_y =pos[1] + 1/2 * pos[3]

    screen.blit(image2, (center_x-1/2*new_width, center_y-1/2*new_height))

def draw_image_label_rect_behind(image, color, pos,scale_factor):
    pygame.draw.rect(screen, color,pos)
    image = pygame.image.load(image).convert_alpha()
    width = image.get_width()
    height = image.get_height()
    image2 = pygame.transform.smoothscale(image,(math.floor(width*scale_factor),math.floor(height*scale_factor)))

    center_x = pos[0]+ 1/2*pos[2]
    new_width = image2.get_width()

    screen.blit(image2, (center_x-1/2*new_width, pos[3]+pos[1]+1))


size = (1500, 700)
background = pygame.display.set_mode(size)
screen = pygame.surface.Surface((10000, 10000))

pygame.display.set_caption("HI")

done = False
clock = pygame.time.Clock()
FPS = 120
scroll_y = 0
scroll_x = 0
originalmousex = None
originalmousey = None


Rects= []
Objects = []
class Camera():
    def __init__(self):

        self.x = 5000
        self.y = 5000
        self.distance_x = 750
        self.distance_y = 350
    def move(self,offset_x,offset_y):
        self.x +=offset_x
        self.y +=offset_y
        for i in Objects:
            i.screenpos=(i.pos[0]-self.x+750,i.pos[1]-self.y+350)
            i.virtual_rect = pygame.Rect(i.screenpos[0],i.screenpos[1],i.width,i.length)

    def zoom_in(self):
        self.distance_x = math.floor(self.distance_x * 0.95)
        self.distance_y = math.floor( self.distance_y * 0.95)
    def zoom_out(self):
        self.distance_x = math.floor(self.distance_x * 1.05)
        self.distance_y = math.floor(self.distance_y * 1.05)

    def subsurfacing(self):
        self.camera_surface = screen.subsurface((self.x- self.distance_x,self.y - self.distance_y,2*self.distance_x,2*self.distance_y))

        background.blit(pygame.transform.smoothscale(self.camera_surface,(1500,700)),(0,0))


main_camera = Camera()

class InfantryRect():
    def __init__(self,number, color,formation,pos):
        self.number = number
        self.color = color
        self.formation = formation
        class_formation = self.formation
        self.pos = pos
        self.moving = False
        self.movingto = None
        self.startmovingframe = None
        self.screenpos = (self.pos[0]-main_camera.x+750,self.pos[1]-main_camera.y+350)
        if self.formation == 'line':
            lengthy = 25
            self.Display_Rect = pygame.Rect(self.pos[0],self.pos[1],lengthy*2,(self.number//lengthy)*2)
            self.length = self.Display_Rect.height
            self.width = self.Display_Rect.width
            self.virtual_rect = pygame.Rect(self.screenpos[0],self.screenpos[1],self.width,self.length)
            self.speed = 1


    def display(self):

        if self.formation== 'line':

          pygame.draw.rect(screen,self.color,[self.pos[0],self.pos[1],self.width,self.length])
          hi = font.render(str(self.number),True,(255,225,64))

          center_x = self.pos[0]+ 1/2*self.width
          center_y =self.pos[1] + 1/2 * self.length
          text_width = hi.get_width()
          text_height = hi.get_height()
          screen.blit(hi, (math.floor(center_x-1/2*text_width),math.floor(center_y-1/2*text_height)))
    def movingcreating(self,position):
        self.distance = math.hypot(position[0]-self.virtual_rect.x,position[1]-self.virtual_rect.y)
        if self.distance!=0:
            self.dx = ((position[0]-self.virtual_rect.x)/self.distance)*self.speed
            self.dy = ((position[1]-self.virtual_rect.y)/self.distance)*self.speed

    def move(self,position):


        if self.distance!=0:
            self.pos = (self.pos[0]+self.dx,self.pos[1]+self.dy)
            self.virtual_rect = pygame.Rect(int(self.pos[0]-main_camera.x+750),int(self.pos[1]-main_camera.y+350),self.width,self.length)
            self.Display_Rect = pygame.Rect(int(self.pos[0]),int(self.pos[1]),self.width,self.length)
            self.movingcreating(position)




TestInf = InfantryRect(100,RED,'line',[5000,5000])
Objects.append(TestInf)
count = 0
width = screen.get_width()
length = screen.get_height()
clock = pygame.time.Clock()
z_is_pressed = False
x_is_pressed = False
up_is_pressed = False
down_is_pressed = False
right_is_pressed = False
left_is_pressed = False
mouse_button_holding = False






frames = 0
while not done:

    for event in pygame.event.get():



        if event.type == pygame.QUIT:

            done = True


        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_pos = event.pos

            for i in Objects:

                if i.virtual_rect.collidepoint(mouse_pos):
                    print('Hello')
                    mouse_button_holding = i

                    break
            if mouse_button_holding==False:
                mouse_button_holding = 'scrolling'
                originalmousex = mouse_pos[0]
                originalmousey = mouse_pos[1]

        elif event.type == pygame.MOUSEBUTTONUP:
            if mouse_button_holding!= False and mouse_button_holding!='scrolling':

                mouse_button_holding.movingto = (event.pos[0] -0.5*mouse_button_holding.width-main_camera.x+5000 , event.pos[1]-0.5*mouse_button_holding.length-main_camera.y+5000)
                mouse_button_holding.movingcreating(event.pos)
                mouse_button_holding.moving = True
                mouse_button_holding.startmovingframe = frames
                mouse_button_holding = False
            originalmousex = None
            originalmousey = None
            mouse_button_holding = False






        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_z:
                z_is_pressed = True
            elif event.key ==pygame.K_x:
                x_is_pressed = True
            elif event.key == pygame.K_UP:
                up_is_pressed = True
            elif event.key == pygame.K_DOWN:
                down_is_pressed = True
            elif event.key == pygame.K_RIGHT:
                right_is_pressed = True
            elif event.key == pygame.K_LEFT:
                left_is_pressed = True

        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_z:
                z_is_pressed = False
            elif event.key ==pygame.K_x:
                x_is_pressed = False



    if mouse_button_holding=='scrolling':

        main_camera.move(-(pygame.mouse.get_pos()[0]-originalmousex),-(pygame.mouse.get_pos()[1]-originalmousey))
        originalmousex = pygame.mouse.get_pos()[0]
        originalmousey = pygame.mouse.get_pos()[1]
    if z_is_pressed:

        main_camera.zoom_in()
    if x_is_pressed:
        main_camera.zoom_out()
    background.fill(BLACK)
    screen.fill(BLACK)
    # pygame.draw.line(screen, GREEN, [0, 0], [100, 100], 5)
    #for y_offset in range(0, 100, 10):
        #pygame.draw.line(screen,RED,[0,10+y_offset],[100,110+y_offset],5)
    #draw_label_rect('Hello',RED,[250,250,50,50],WHITE)
    TestInf.display()
    for i in Objects:
        if i.moving:
            i.move(i.movingto)

    main_camera.subsurfacing()
    print(clock.get_fps())
    clock.tick(60)
    pygame.display.update()
    frames+=1

pygame.quit()

标签: pythonpygamepygame-surface

解决方案


主要问题是,screenpygame.Surface一个大小为 10000x10000 的对象。这个表面在每一帧中都会被清除,这就是导致性能影响的原因:

screen = pygame.surface.Surface((10000, 10000))
screen.fill(BLACK)

由于表面的一小部分(次表面)blit位于屏幕上,

   def subsurfacing(self):
       self.camera_surface = screen.subsurface((self.x- self.distance_x,self.y - self.distance_y,2*self.distance_x,2*self.distance_y))
       background.blit(pygame.transform.smoothscale(self.camera_surface,(1500,700)),(0,0))

不必screen在每一帧中清除整个 Surface。只需通过以下方式清除稍后绘制到窗口中的区域pygame.draw.rect

class Camera():

    # [...]

    def clearsubsurface(self, color):
        px = self.x- self.distance_x,self.y - self.distance_y
        py = 2*self.distance_x,2*self.distance_y
        pygame.draw.rect(screen, color, (px, py))
while not done:

    # [...]

    #screen.fill(BLACK)                <--- DELETE
    main_camera.clearsubsurface(BLACK)

    # [...]  

推荐阅读