Python 优化对象显示(gamedev)

Python 优化对象显示(gamedev),python,pygame,Python,Pygame,相关代码,简化: 类字符: 定义初始化(自): self.projectles=[] def喷射(自): self.projectles.append(sparket()) def牵引(自): 对于自射弹中的射弹: pygame.draw.rect()#args在这里似乎不相关 draw()每当产生射弹时,游戏速度都会非常慢 我的问题是: 我可以加快列表迭代过程吗? 我能实现比列表更好的方法吗? 我在哪里可以放一些多线程在这个 编辑: shoot()每帧最多调用一次(在键绑定时触发),并且投射

相关代码,简化:

类字符:
定义初始化(自):
self.projectles=[]
def喷射(自):
self.projectles.append(sparket())
def牵引(自):
对于自射弹中的射弹:
pygame.draw.rect()#args在这里似乎不相关
draw()
每当产生射弹时,游戏速度都会非常慢

我的问题是: 我可以加快列表迭代过程吗? 我能实现比列表更好的方法吗? 我在哪里可以放一些多线程在这个

编辑:

shoot()
每帧最多调用一次(在键绑定时触发),并且
投射物列表迭代两次(更新和绘制步骤)

游戏使用单个投射物时会变得非常迟缓,当投射物达到一定距离(地图限制)并从列表中删除时,游戏会再次变得流畅

我可以加快列表迭代过程吗

没有,但可能您对列表的迭代次数过多。调用
draw()
时,投射物有多大

我能实现比列表更好的方法吗

使用PyGoGAME时,应考虑使用<代码> SpRITE < /C>和<代码>组< /代码>类。使用

而不是列表。这提供了一些方便的功能,比如在不同的层上绘制精灵,抽象更新和绘制,以及使用
kill()
等轻松删除精灵

我在哪里可以放一些多线程在这个

我99.9%确定您实际上不需要多线程


您的问题是
类的更新方法:

def update(self, camera):
    self.posW += self.speed * self.dirW * Clock().tick(FPS)
    self.posH += self.speed * self.dirH * Clock().tick(FPS)
    self.rect = (self.posW, self.posH, 20, 20)
在这里,您将创建一个新的
时钟
实例,并为每个
投射物
实例每帧调用
勾选
两次,这将暂停游戏每帧多次

您应该做的是创建一次
时钟
实例,每帧只调用一次
勾选
,并将结果值向下传递给精灵以调整其速度


我更改了您的代码以使用游戏的
Sprite
类,并删除了许多文件:

camera.py:

import pygame

class CameraAwareLayeredUpdates(pygame.sprite.LayeredUpdates):
    def __init__(self, target, world_size, screen_size):
        super().__init__()
        self.target = target
        self.cam = pygame.Vector2(0, 0)
        self.world_size = world_size
        self.screen_size = screen_size
        if self.target:
            self.add(target)

    def update(self, *args):
        super().update(*args)

        if self.target:
            x = -self.target.rect.center[0] + self.screen_size[0]/2
            y = -self.target.rect.center[1] + self.screen_size[1]/2
            self.cam += (pygame.Vector2((x, y)) - self.cam) * 0.07
            self.cam.x = max(-(self.world_size[0]-self.screen_size[0]), min(0, self.cam.x))
            self.cam.y = max(-(self.world_size[1]-self.screen_size[1]), min(0, self.cam.y))

    def draw(self, surface):
        spritedict = self.spritedict
        surface_blit = surface.blit
        dirty = self.lostsprites
        self.lostsprites = []
        dirty_append = dirty.append
        init_rect = self._init_rect
        for spr in self.sprites():
            rec = spritedict[spr]
            newrect = surface_blit(spr.image, spr.rect.move(self.cam))
            if rec is init_rect:
                dirty_append(newrect)
            else:
                if newrect.colliderect(rec):
                    dirty_append(newrect.union(rec))
                else:
                    dirty_append(newrect)
                    dirty_append(rec)
            spritedict[spr] = newrect
        return dirty            
game.py:

import pygame

from lib.camera import CameraAwareLayeredUpdates

TILESIZE = 50
WORLD_SIZE_IN_TILES = 30, 16
WORLD_SIZE = [v*TILESIZE for v in WORLD_SIZE_IN_TILES]
SCREEN_SIZE = 800, 500

class Actor(pygame.sprite.Sprite):
    def __init__(self, game, *args, **kwargs):
        super().__init__(*args)
        self.game = game

        self.image = pygame.Surface(kwargs.get('size', (50, 50)))
        self.image.fill(pygame.Color(kwargs.get('color', 'blue')))
        self.rect = self.image.get_rect()
        self.pos = pygame.Vector2(kwargs.get('pos', self.rect.center))
        self.rect.center = [int(x) for x in self.pos]
        self.vel = pygame.Vector2(kwargs.get('vel', (0, 0)))

    def update(self, dt, events):
        self.pos += (self.vel * dt/10)
        self.rect.center = [int(x) for x in self.pos]

class Character(Actor):
    def __init__(self, game, *args, **kwargs):
        super().__init__(game, *args, **kwargs)
        self.facing = pygame.Vector2(0, 1)

    def update(self, dt, events):
        for event in events:
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    self.game.add(Actor, 
                            pos=self.rect.center, 
                            vel=self.facing * 10,
                            color='blue',
                            size=(20, 20))

        pressed = pygame.key.get_pressed()

        self.vel.x, self.vel.y = 0, 0
        if pressed[pygame.K_a]: self.vel.x = -1
        if pressed[pygame.K_d]: self.vel.x = 1
        if pressed[pygame.K_w]: self.vel.y = -1
        if pressed[pygame.K_s]: self.vel.y = 1
        if self.vel.length() > 0:
            self.facing = pygame.Vector2(self.vel)
            self.facing.normalize_ip()
        self.vel *= 5

        super().update(dt, events)

class Tilemap(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self._layer = -100
        self.tilesH = WORLD_SIZE_IN_TILES[1]
        self.tilesW = WORLD_SIZE_IN_TILES[0]
        self.map = [
            'white' for i in range(self.tilesH * self.tilesW)
        ]

        for i in range(self.tilesH):
            for j in range(self.tilesW):
                if i * j == 0 or i == self.tilesH - 1 or j == self.tilesW - 1:
                    self.map[i * j] = 'grey'

        self.image = self.render()
        self.rect = self.image.get_rect()

    def update(self, *args):
        pass

    def render(self):
        surf = pygame.Surface(WORLD_SIZE)
        for i in range(self.tilesH):
            for j in range(self.tilesW):
                rect = (j * TILESIZE, i * TILESIZE, TILESIZE, TILESIZE)
                pygame.draw.rect(surf, pygame.Color(self.map[i * j]), rect)
        return surf

class Game:
    def __init__(self):
        pygame.init()
        pygame.display.set_caption("SANTARENA")
        self.screen = pygame.display.set_mode(SCREEN_SIZE)
        self.clock = pygame.time.Clock()
        player = Character(self, color='red', pos=self.screen.get_rect().center)
        self.all_sprites = CameraAwareLayeredUpdates(player, WORLD_SIZE, SCREEN_SIZE)
        self.all_sprites.add(Tilemap())

    def add(self, clazz, **kwargs):
        instance = clazz(self, self.all_sprites, **kwargs)
        return instance

    def start(self):
        dt = 0
        while True:
            events = pygame.event.get()
            for event in events:
                if event.type == pygame.QUIT:
                    return

            self.all_sprites.update(dt, events)
            self.all_sprites.draw(self.screen)
            pygame.display.update()
            dt = self.clock.tick(60)

我一定会把这些课程查出来。它可能很好地解决了我的问题,但我仍然更新了这个问题。@Pypaut你的射弹是矩形的吗?奇怪的是,一个单一的会导致滞后。也许发布你的完整代码(如果不是太多的话)。只链接我的代码可以吗
python/lib/*
。我当然还不习惯python的方式。给人印象深刻的我期待着更新这一切。非常感谢。