Python 低帧速率,可能是因为未加速的图形
所以我几个月前开始用pygame创建一个游戏,它的顶视图类似于星际争霸,帝国时代等等。。。我已经写了大约1320行代码来创建我的游戏的基础;然而,我在浏览图片时遇到了帧速率问题,我相信这是因为我不能在pygame中使用加速图形。我目前的方式是在一个表面上提前点显所有的图像,然后在下面创建我整个屏幕的点显图像。有没有更有效的方法,我应该利用 所以我的假设是这将是一个巨大的混乱,我不想浪费你们的时间。基本上,每当我在屏幕大小的表面上闪动时,我的帧速率就会下降约20帧,有没有办法在pygame中避免这种情况Python 低帧速率,可能是因为未加速的图形,python,pygame,pyglet,Python,Pygame,Pyglet,所以我几个月前开始用pygame创建一个游戏,它的顶视图类似于星际争霸,帝国时代等等。。。我已经写了大约1320行代码来创建我的游戏的基础;然而,我在浏览图片时遇到了帧速率问题,我相信这是因为我不能在pygame中使用加速图形。我目前的方式是在一个表面上提前点显所有的图像,然后在下面创建我整个屏幕的点显图像。有没有更有效的方法,我应该利用 所以我的假设是这将是一个巨大的混乱,我不想浪费你们的时间。基本上,每当我在屏幕大小的表面上闪动时,我的帧速率就会下降约20帧,有没有办法在pygame中避免这
##PYGAME INITATE##
import pygame, os
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()
_W,_H = pygame.display.Info().current_w, pygame.display.Info().current_h
flags = pygame.DOUBLEBUF | pygame.HWSURFACE
gameDisplay = pygame.display.set_mode((_W,_H),pygame.FULLSCREEN ) ## CREATES SCREEN YOU DISPLAY ON ##
gameDisplay.fill((0,0,0)) ## FILL COLOR OF SCREEN ##
pygame.display.set_caption("Dope Game") ## SETS NAME ##
gameClock = pygame.time.Clock() ## CLOCK OF THE GAME ##
import math
import os
import random
import copy
SQRT = math.sqrt
PI = math.pi
cos = math.cos
sin = math.sin
## REPEATABLE FUNCTIONS ##
def loadScale(file,command,sizeX,sizeY):
temp = pygame.image.load(file)
tempInfo = temp.get_rect()
tempInfo1,tempInfo2,tempInfo3,tempInfo4 = temp.get_rect()
tempInfo3 = int(tempInfo3)
tempInfo4 = int(tempInfo4)
if (command == "ratio"):
tempInfo3 = tempInfo3*sizeX
tempInfo4 = tempInfo4*sizeY
temp = pygame.transform.scale(temp,(int(tempInfo3),int(tempInfo4) ) )
elif (command == "size"):
temp = pygame.transform.scale(temp, (sizeX,sizeY) )
return(temp)
## NON GAME RELATED CLASSES ##
class EnterFrame():
def __init__(self,frameReset,function,parse,reset):
self.frameReset = frameReset
self.currentFrame = frameReset
self.function = function
self.parse = parse
self.reset = reset
if (self.reset != "onComplete"):
self.reset = (reset-1)
enterFrameTable.append(self)
def step(self,enterFrameTable):
if (self.currentFrame == 0):
self.function(self.parse)
if (self.reset != "onComplete"):
if (self.reset > 0):
self.currentFrame = self.frameReset
self.reset = self.reset-1
else:
enterFrameTable.remove(self)
del self
else:
self.currentFrame = self.frameReset
else:
self.currentFrame = self.currentFrame-1
class PlayerCreation():
def __init__(self):
self.x = _W
self.y = _H
self.view = [1600,1600]
self.viewShift = []
self.viewChangeSpeed = 25
def moveView(self,key):
add = EnterFrame(0,self.moveViewAction,key,"onComplete")
self.viewShift.append([add,key])
def moveViewAction(self,key):
if (key == "up"):
self.view[1] = self.view[1]-self.viewChangeSpeed
Map.recenterView()
if (self.view[1] < 0):
self.view[1] = 0
elif (key == "right"):
self.view[0] = self.view[0]+self.viewChangeSpeed
Map.recenterView()
if (self.view[0] > Map.tileSize*4):
self.view[0] = Map.tileSize*4
elif (key == "down"):
self.view[1] = self.view[1]+self.viewChangeSpeed
Map.recenterView()
if (self.view[1] > Map.tileSize*4):
self.view[1] = Map.tileSize*4
elif (key == "left"):
self.view[0] = self.view[0]-self.viewChangeSpeed
Map.recenterView()
if (self.view[0] < 0):
self.view[0] = 0
def endMoveView(self,key):
for i in range(len(self.viewShift)-1,-1,-1 ):
if (self.viewShift[i][1] == key):
enterFrameTable.remove(self.viewShift[i][0])
del self.viewShift[i]
class ImageCreation():
def __init__(self,name,image,type,hitBox):
self.name = name
self.image = image
self.type = type
self.hitBox = hitBox
self.rect = self.image.get_rect()
if (self.hitBox != "none"):
self.shiftX = hitBox[0][0]
self.shiftY = hitBox[0][1]
for i in range(1,len(hitBox) ):
if (hitBox[i][0] < self.shiftX):
self.shiftX = hitBox[i][0]
if (hitBox[i][1] < self.shiftY):
self.shiftY = hitBox[i][1]
else:
self.shiftX = self.rect[2]/2
self.shiftY = self.rect[3]/2
imageTable.append(self)
def draw(self,x,y):
image = self.image
self.blit = gameDisplay.blit(image,(x,y) )
class MapCreation():
def __init__(self):
self.tileSize = 800
self.size = self.tileSize*10
self.tiles = []
self.loadedTiles = []
self.surface = pygame.Surface([self.tileSize*5,self.tileSize*5], pygame.SRCALPHA, 32)
self.centerTile = [5,5]
self.drawPoint = [(_W-self.tileSize)/2,(_H-self.tileSize)/2]
self.amount = round(self.size/self.tileSize)
backGround = loadScale("Grass.png","size",self.tileSize,self.tileSize)
for i in range(0,self.amount):
for u in range(0,self.amount):
image = copy.copy(backGround)
newTile = Tile(image,[u*self.tileSize,i*self.tileSize])
self.tiles.append(newTile)
info = imageFind("House.png")
tile = self.tiles[55]
imageObject(info,tile,[240,50])
self.loadTiles("center")
def recenterView(self):
if (Player.view[0] > 3*self.tileSize):
self.centerTile[0] = self.centerTile[0]+1
Player.view[0] = Player.view[0]-self.tileSize
self.loadTiles("right")
print("right")
elif (Player.view[0] < 1*self.tileSize):
self.centerTile[0] = self.centerTile[0]-1
Player.view[0] = Player.view[0]+self.tileSize
self.loadTiles("center")
print("center")
if (Player.view[1] > 3*self.tileSize):
self.centerTile[1] = self.centerTile[1]+1
Player.view[1] = Player.view[1]-self.tileSize
self.loadTiles("center")
print("center")
elif (Player.view[1] < 1*self.tileSize):
self.centerTile[1] = self.centerTile[1]-1
Player.view[1] = Player.view[1]+self.tileSize
self.loadTiles("center")
print("center")
def loadTiles(self,load):
tileIndex = self.centerTile[0]+self.centerTile[1]*self.amount
if (load == "center"):
self.loadedTiles = []
for i in range(-2,3):
for u in range(-2,3):
loadTile = tileIndex + i*self.amount + u
self.loadedTiles.append(self.tiles[loadTile])
self.tiles[loadTile].loaded = [u+2,i+2]
self.surface = pygame.Surface([self.tileSize*5,self.tileSize*5], pygame.SRCALPHA, 32)
for i in range(0,len(self.loadedTiles) ):
sx = self.loadedTiles[i].loaded[0]*self.tileSize
sy = self.loadedTiles[i].loaded[1]*self.tileSize
self.surface.blit(self.loadedTiles[i].buttomLayer,(sx,sy) )
for i in range(0,len(self.loadedTiles) ):
sx = self.loadedTiles[i].loaded[0]*(self.tileSize+2)
sy = self.loadedTiles[i].loaded[1]*(self.tileSize+2)
self.surface.blit(self.loadedTiles[i].middleLayer,(sx,sy) )
for i in range(0,len(self.loadedTiles) ):
sx = self.loadedTiles[i].loaded[0]*(self.tileSize+2)
sy = self.loadedTiles[i].loaded[1]*(self.tileSize+2)
self.surface.blit(self.loadedTiles[i].topLayer,(sx,sy) )
elif (load == "right"):
self.loadedTiles = []
for i in range(-2,3):
for u in range(-2,3):
loadTile = tileIndex + i*self.amount + u
self.loadedTiles.append(self.tiles[loadTile])
self.tiles[loadTile].loaded = [u+2,i+2]
## OLD METHOD THAT WASNT WORKING ##
##subSurf = self.surface.subsurface(self.tileSize,0,self.tileSize*1,self.tileSize*5)
##self.surface = pygame.Surface([self.tileSize*5,self.tileSize*5], pygame.SRCALPHA, 32)
##self.surface.blit(subSurf,(0,0) )
## NEW METHOD ##
self.surface.scroll(dx=-self.tileSize*1,dy=0)
def draw(self):
global Player
image = self.surface.subsurface(Player.view[0],Player.view[1],self.tileSize,self.tileSize)
image = pygame.transform.scale(image,(self.tileSize,self.tileSize) )
gameDisplay.blit(image,((_W-self.tileSize)/2,(_H-self.tileSize)/2) )
image = pygame.transform.scale(self.surface,(300,300) )
gameDisplay.blit(image,(0,0 ) )
class Tile():
def __init__(self,image,coords):
transparentSurface = pygame.Surface([1000,1000], pygame.SRCALPHA, 32)
self.x = coords[0]
self.y = coords[1]
self.loaded = False
self.buttomLayer = image
self.middleLayer = copy.copy(transparentSurface)
self.topLayer = transparentSurface
class imageObject():
def __init__(self,info,tile,coords):
self.info = info
self.image = info.image
self.rect = self.image.get_rect()
self.x = coords[0]
self.y = coords[1]
self.hitBox = []
if (self.info.hitBox != "none"):
for i in range(0,len(self.info.hitBox) ):
self.hitBox.append([self.info.hitBox[i][0]+self.x,self.info.hitBox[i][1]+self.y])
#self.object = createObject(self.hitBox,True,"none")
if (info.type == "background"):
tile.buttomLayer.blit(self.image,(self.x,self.y) )
if (info.type == "object"):
tile.middleLayer.blit(self.image,(self.x,self.y) )
if (info.type == "object alphas"):
tile.topLayer.blit(self.image,(self.x,self.y) )
def imageFind(name):
for i in range(0,len(imageTable) ):
if (name == imageTable[i].name):
return(imageTable[i])
return("none")
def imageLoad(types):
if (types == "basic"):
image = loadScale("House.png","ratio",1,1)
basicHouse = ImageCreation("House.png",image,"object",[[190, 375], [350, 375], [350, 235], [190, 235]])
image = loadScale("Grass.png","ratio",1,1)
grass = ImageCreation("Grass.png",image,"background","none")
def enterFrameHandle(enterFrameTable):
for i in range(len(enterFrameTable)-1,-1,-1 ):
enterFrameTable[i].step(enterFrameTable)
def EventHandle(event):
global Player
if (event.type == pygame.QUIT):
endGame()
elif(event.type == pygame.KEYDOWN):
key = (pygame.key.name(event.key) )
if (key == "escape"):
endGame()
elif (key == "up" or key == "right" or key == "down" or key == "left"):
Player.moveView(key)
elif(event.type == pygame.KEYUP):
key = (pygame.key.name(event.key) )
if (key == "up" or key == "right" or key == "down" or key == "left"):
Player.endMoveView(key)
def endGame():
global QuitGame
QuitGame = True
def mainLoop():
## GLOBALS ##
global QuitGame
QuitGame = False
global Player
Player = PlayerCreation()
## MAIN TABLES ##
global enterFrameTable
enterFrameTable = []
global basicObjectTable
basicObjectTable = []
## TEMP TABLES ##
global imageTable
imageTable = []
## START UP LOOPS ##
imageLoad("basic")
global Map
Map = MapCreation()
## Temporary ##
while (QuitGame == False):
enterFrameHandle(enterFrameTable)
for event in pygame.event.get():
EventHandle(event)
Map.draw()
pygame.display.update() ## updates the screen ##
gameDisplay.fill([0,0,0]) ## Clears screen for next frame ##
gameClock.tick(64) ## The FPS ##
fps = gameClock.get_fps()
if (fps < 64 and fps != 0):
fps = gameClock.get_fps()
print("FPS HAS DROPPED TOO LOW DOWN TO",fps)
runGameNow = True
mainLoop()
pygame.quit()
quit()
路径查找器的问题是由于在查找最近点时在垂直线上拾取这一问题实际上非常简单。 你认为线的数量是疾病,原因必须是Pygame。通常,或者至少在几乎任何情况下——如果你不是一个使用语言和库的神,问题可能不是语言或库。因为很有可能你还没有达到这两个人能为你提供的极限。 这一事实的一个致命弱点是,如果你观察你的眼睛在屏幕上看到的东西,你会很快注意到,每当你的背景即将循环时,就会出现小故障/帧下降。 显然,这可能是图书馆做了一些可疑事情的原因。。如果是库进行了实际的循环 但在您的代码中,这是您自己完成的实现。 因此,最好的办法是从那里开始寻找。 为了对延迟发生的位置非常有信心,我们可以看看Python cProfiler附带的分析器
python -m cProfile -o sample_data.pyprof awesome_game.py
pyprof2calltree -i sample_data.pyprof -k
结果将显示以下内容:
从中我们可以看出,pygame.Surface和enterFrameHandle占用了大量的处理时间。我打赌pygame.Surface在enterFrameHandle中的某个位置被调用
因此,最好的选择是从eventFrameHandle链的末尾开始。
在这个细分中,这是loadTiles
马上,这里有很多警告标志。
这里至少有四个环路。。循环是不好的,因为它们需要处理时间
我只需执行以下操作即可添加调试信息:
def loadTiles
if load == "center":
print('Loading center')
elif load == "right":
print('Loading right')
很明显,只要出现故障,中心就会被触发。
这就把范围缩小了一点。所以我在每个for循环周围添加了计时器
循环一:需要0.0秒
循环二:需要0.29秒
循环三:需要0.5秒
循环四:需要0.6秒
总而言之,这些都对您极为不利,因为它们直接影响渲染序列。为什么会这样?让我们进一步细分。
我们将从占用0.3秒的第一个循环开始:
for i in range(0,len(self.loadedTiles) ):
sx = self.loadedTiles[i].loaded[0]*self.tileSize
sy = self.loadedTiles[i].loaded[1]*self.tileSize
self.surface.blit(self.loadedTiles[i].buttomLayer,(sx,sy) )
因此lenself.loadedTiles将为25。
这意味着在调用LoadTileCenter的每个渲染周期中,该循环必须迭代25次
每个循环几乎只需0.01秒,相当于每个完整循环0.25秒。这并不可怕,是的。。如果您希望游戏以60 FPS的速度结束,则循环或函数调用的总时间不能超过0.0166秒
所以我们已经超过了预期的FPS目标。所以如果我们想去任何地方,我们必须缩短几毫秒
循环本身并没有那么糟糕,我的意思是25次迭代,一台现代PC可以在比时间更短的时间内完成。所以,它都指向self.surface.blit。。从经验来看,确实如此。
这也与我们上面的图在pygame.surface.blit中花费了总CPU时间的30%这一事实相关。。这是我们的第一个小偷
看看其余的循环,它们基本上是相同的,只是数学中的数字较大,计算时间稍长,因此可能是循环中的时间差
那么,我们能做些什么来缩小规模呢?闪电时代?
我们可以停止在每次循环迭代中调用blit,只需移动sprite对象的位置,然后逐个执行blit。
但是老师,这几乎是一样的吗?
嗯,是的,我即将成为忍者神龟,它是。。这就是为什么,我们将精灵移动到批/组中,并渲染组。因此,我们可以快速更改位置操作,因为我们将渲染移到循环之外,所以我们还可以将它们转换为组对象并渲染组
首先,我们将您的对象转换为,这些是聪明的小对象,包含碰撞检测、移动等
self.grass = pygame.sprite.Sprite()
self.grass.image = pygame.image.load("Grass.png")
self.grass.rect = pygame.Rect(0, 0, 60, 60)
然后将其添加到一个渲染组或批处理中:
self.main_group = pygame.sprite.Group(self.grass)
Bam,而不是更新25个精灵,现在您可以执行以下操作:
self.main_group.draw(gameDisplay)
砰,速度
现在,您的代码不是为此而设计的。
因此,修复和纠正此设计缺陷需要一段时间。
因为我需要几个小时才能把你的原始代码保持不变
尽可能接近,我忽略了这一点,修改了你的整个地图创建,修改了你的PlayerCreation和你移动地图的方式。我从每次尝试重新居中更改,这是一个不错的想法,但要实现下午1点重写别人的代码要复杂得多。。所以以下是解决问题的新方法:
import pygame, os
from time import time
from collections import OrderedDict
os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()
_W,_H = pygame.display.Info().current_w, pygame.display.Info().current_h
flags = pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE
gameDisplay = pygame.display.set_mode((500, 500))
gameDisplay.fill((0,0,0)) ## FILL COLOR OF SCREEN ##
pygame.display.set_caption("Dope Game") ## SETS NAME ##
gameClock = pygame.time.Clock() ## CLOCK OF THE GAME ##
import math
import os
import random
import copy
SQRT = math.sqrt
PI = math.pi
cos = math.cos
sin = math.sin
## REPEATABLE FUNCTIONS ##
def loadScale(file,command,sizeX,sizeY):
temp = pygame.image.load(file)
tempInfo = temp.get_rect()
tempInfo1,tempInfo2,tempInfo3,tempInfo4 = temp.get_rect()
tempInfo3 = int(tempInfo3)
tempInfo4 = int(tempInfo4)
if (command == "ratio"):
tempInfo3 = tempInfo3*sizeX
tempInfo4 = tempInfo4*sizeY
temp = pygame.transform.scale(temp,(int(tempInfo3),int(tempInfo4) ) )
elif (command == "size"):
temp = pygame.transform.scale(temp, (sizeX,sizeY) )
return(temp)
## NON GAME RELATED CLASSES ##
class EnterFrame():
def __init__(self,frameReset,function,parse,reset):
self.frameReset = frameReset
self.currentFrame = frameReset
self.function = function
self.parse = parse
self.reset = reset
if (self.reset != "onComplete"):
self.reset = (reset-1)
enterFrameTable.append(self)
def step(self,enterFrameTable):
if (self.currentFrame == 0):
self.function(self.parse)
if (self.reset != "onComplete"):
if (self.reset > 0):
self.currentFrame = self.frameReset
self.reset = self.reset-1
else:
enterFrameTable.remove(self)
del self
else:
self.currentFrame = self.frameReset
else:
self.currentFrame = self.currentFrame-1
class PlayerCreation():
def __init__(self):
self.x = _W
self.y = _H
self.view = [1600,1600]
self.viewShift = []
self.viewChangeSpeed = 25
def moveView(self,key):
add = EnterFrame(0,self.moveViewAction,key,"onComplete")
self.viewShift.append([add,key])
def moveViewAction(self,key):
if (key == "up"):
self.view[1] = self.view[1]-self.viewChangeSpeed
Map.move_tile(0, 1) # Player moves up, so the tiles should move down -> (0, 1) == (x, y)
if (self.view[1] < 0):
self.view[1] = 0
elif (key == "right"):
self.view[0] = self.view[0]+self.viewChangeSpeed
Map.move_tile(-1, 0)
if (self.view[0] > Map.tileSize*4):
self.view[0] = Map.tileSize*4
elif (key == "down"):
self.view[1] = self.view[1]+self.viewChangeSpeed
Map.move_tile(0, -1)
if (self.view[1] > Map.tileSize*4):
self.view[1] = Map.tileSize*4
elif (key == "left"):
self.view[0] = self.view[0]-self.viewChangeSpeed
Map.move_tile(1, 0)
if (self.view[0] < 0):
self.view[0] = 0
def endMoveView(self,key):
for i in range(len(self.viewShift)-1,-1,-1 ):
if (self.viewShift[i][1] == key):
enterFrameTable.remove(self.viewShift[i][0])
del self.viewShift[i]
class ImageCreation():
def __init__(self,name,image,type,hitBox):
self.name = name
self.image = image
self.type = type
self.hitBox = hitBox
self.rect = self.image.get_rect()
if (self.hitBox != "none"):
self.shiftX = hitBox[0][0]
self.shiftY = hitBox[0][1]
for i in range(1,len(hitBox) ):
if (hitBox[i][0] < self.shiftX):
self.shiftX = hitBox[i][0]
if (hitBox[i][1] < self.shiftY):
self.shiftY = hitBox[i][1]
else:
self.shiftX = self.rect[2]/2
self.shiftY = self.rect[3]/2
imageTable.append(self)
def draw(self,x,y):
image = self.image
self.blit = gameDisplay.blit(image,(x,y) )
class MapCreation():
def __init__(self):
self.tileSize = 800
self.size = self.tileSize*10
self.tiles = []
self.centerTile = [5,5]
self.amount = round(self.size/self.tileSize)
self.sprites = OrderedDict()
self.grass_image = pygame.image.load("Grass.png")
self.grass_group = pygame.sprite.Group()
for x in range(0, self.amount*60, 60): ## 10*60, but we step 60 pixels, so in the end, this will be 10 steps.
for y in range(0, self.amount*60, 60): ## Which is the same as `for x in range(self.amount)` but we scale it up
## to give us pixels instead of just the ammount.
index = len(self.sprites) # -- Generate a index for this sprite. Used for access later (to update pos for instace)
## == Create the sprite, add a image to it and define a position and size.
self.sprites[index] = pygame.sprite.Sprite()
self.sprites[index].image = self.grass_image
self.sprites[index].rect = pygame.Rect(x, y, 60, 60)
## == Then add the sprite to the grass group.
self.grass_group.add(self.sprites[index])
def move_tile(self, dx, dy):
for index in self.sprites:
x, y, width, height = self.sprites[index].rect
## == this is how you move the sprites:d
self.sprites[index].rect = pygame.Rect(x+dx, y+dy, 60, 60)
def draw(self):
self.grass_group.update()
self.grass_group.draw(gameDisplay)
class Tile():
def __init__(self,image,coords):
transparentSurface = pygame.Surface([1000,1000], pygame.SRCALPHA, 32)
self.x = coords[0]
self.y = coords[1]
self.loaded = False
self.buttomLayer = image
self.middleLayer = copy.copy(transparentSurface)
self.topLayer = transparentSurface
class imageObject():
def __init__(self,info,tile,coords):
self.info = info
self.image = info.image
self.rect = self.image.get_rect()
self.x = coords[0]
self.y = coords[1]
self.hitBox = []
if (self.info.hitBox != "none"):
for i in range(0,len(self.info.hitBox) ):
self.hitBox.append([self.info.hitBox[i][0]+self.x,self.info.hitBox[i][1]+self.y])
#self.object = createObject(self.hitBox,True,"none")
if (info.type == "background"):
tile.buttomLayer.blit(self.image,(self.x,self.y) )
if (info.type == "object"):
tile.middleLayer.blit(self.image,(self.x,self.y) )
if (info.type == "object alphas"):
tile.topLayer.blit(self.image,(self.x,self.y) )
def imageFind(name):
for i in range(0,len(imageTable) ):
if (name == imageTable[i].name):
return(imageTable[i])
return("none")
def imageLoad(types):
if (types == "basic"):
image = loadScale("House.png","ratio",1,1)
basicHouse = ImageCreation("House.png",image,"object",[[190, 375], [350, 375], [350, 235], [190, 235]])
image = loadScale("Grass.png","ratio",1,1)
grass = ImageCreation("Grass.png",image,"background","none")
def enterFrameHandle(enterFrameTable):
for i in range(len(enterFrameTable)-1,-1,-1 ):
enterFrameTable[i].step(enterFrameTable)
def EventHandle(event):
global Player
if (event.type == pygame.QUIT):
endGame()
elif(event.type == pygame.KEYDOWN):
key = (pygame.key.name(event.key) )
if (key == "escape"):
endGame()
elif (key == "up" or key == "right" or key == "down" or key == "left"):
Player.moveView(key)
elif(event.type == pygame.KEYUP):
key = (pygame.key.name(event.key) )
if (key == "up" or key == "right" or key == "down" or key == "left"):
Player.endMoveView(key)
def endGame():
global QuitGame
QuitGame = True
def mainLoop():
## GLOBALS ##
global QuitGame
QuitGame = False
global Player
Player = PlayerCreation()
## MAIN TABLES ##
global enterFrameTable
enterFrameTable = []
global basicObjectTable
basicObjectTable = []
## TEMP TABLES ##
global imageTable
imageTable = []
## START UP LOOPS ##
imageLoad("basic")
global Map
Map = MapCreation()
## Temporary ##
while (QuitGame == False):
enterFrameHandle(enterFrameTable)
for event in pygame.event.get():
EventHandle(event)
pygame.display.update() ## updates the screen ##
gameDisplay.fill([0,0,0]) ## Clears screen for next frame ##
#Map.draw()
Map.grass_group.update()
Map.grass_group.draw(gameDisplay)
gameClock.tick(64) ## The FPS ##
fps = gameClock.get_fps()
if (fps < 64 and fps != 0):
fps = gameClock.get_fps()
print("FPS HAS DROPPED TOO LOW DOWN TO",fps)
pygame.display.flip()
runGameNow = True
mainLoop()
pygame.quit()
quit()
此代码很少在FPS中下拉。
当它这样做时,它会下降到约63 FPS,因为我移动了窗口。这是一件很费力的事情,因为所有OpenGL引用都需要补偿新的窗口位置,Pygame resize事件、move事件等中触发的事件都很费力,但不是每次渲染循环都会发生一次。。所以这是可以接受的
结论
性能缓慢很少是库的错。
暂时停止作为开发人员的思考,观察屏幕,看看是否能找到错误所在的线索。在这种情况下,每次瓷砖围绕屏幕边缘旋转时都会出现明显的故障。。这是个线索!不需要任何编程技能就能直观地看到这个bug。
在代码花费大部分时间的地方使用分析器和调试。
试着看看其他人是如何解决游戏设计的。。通过将所有内容放在类中,您走上了正确的道路,但这主要有助于提高代码的可读性—尝试查看其他人类中的内容以及他们如何使用Pygame调用。
总而言之,这是一个非常有趣的代码。
它不是为性能而设计的,而且很难在以后编写代码。。所以从头开始也许不是个坏主意?但请保留旧代码库以供参考,并避免明显的陷阱:
渲染序列中的循环
逐个渲染对象,请改用批处理
仅循环更新位置/统计信息,而不是图形!
关于这个主题的最后一点:图形卡是巨大的发电站。他们可以每秒计算几百万次运算,如果不是更多的话。每次你在屏幕上显示一些东西时,图形卡都需要中断它的计算和内存分配,以翻转缓冲区并更新你在屏幕上看到的内容。。这是一项缓慢的工作,因为这不是计算,而是操作任务,通常包括等待队列和信号。。因此,与其每秒向图形卡抛出数百个blit,不如通过向图形卡发送描述事物外观的数学数据来对其抛出数学运算。。然后调用blit draw,在本例中是一次,让图形卡接受所有的数学运算——做一个大的逻辑运算——然后进行预处理。。x100的速度已经很快了。你的问题有点模糊。你能从你的游戏中提供一些代码吗?就像我希望人们在更广泛的意义上使用Pyglet一样。我要大胆地猜测一下,你根本没有使用或者没有正确地使用?我不认为在这里转储一千行代码会给你带来任何有用的建议。你应该先做一些准备工作,把这堆乱七八糟的东西减少到一个合理的最小程度,这样人们就可以在不知道你的代码的所有细节的情况下阅读和遵循你的代码了。我本来试图避免删除任何代码,但它是被要求的,我试图将其尽可能减少到250左右,这是尽可能少的,但没有潜在的消除问题,我已经做了尽可能多的研究,但得出的结论是,每当在pygame中blitting大型曲面时,它都会显著降低帧率,有没有一种好的方法来预处理blit曲面以避免这种情况?谢谢你提供我正在学习的信息,我只是想找到正确的方向。你是一个团队,而不是一个接一个地出现。如果这不起作用,那么你要么在渲染序列中对你的对象进行大量更新,要么你实际上已经成功地将Pygame的边界推到了它的绝对极限记住,它并不是真正为复杂的3D游戏设计的。我只想让你知道,我非常感谢你如此彻底的回应。总的来说,我很困惑,而你在澄清问题上帮助了我很多。“你是一个真正的英雄!”梅森为巴德喝彩,当你的回答中有一个是有意义的,并且实际地教导/澄清了一些东西时,这总是很好的:我祝你在比赛中好运!此外,欢迎使用StackOverflow,如果我的答案或任何其他答案解决了您的问题,请不要忘记将其标记为已解决,以便其他人可以轻松找到问题的正确答案: