gpt4 book ai didi

python - 优化对象显示(gamedev)

转载 作者:太空宇宙 更新时间:2023-11-04 01:47:06 25 4
gpt4 key购买 nike

相关代码,简化:

class Character:
def __init__(self):
self.projectiles = []

def shoot(self):
self.projectiles.append(Projectile())

def draw(self):
for projectile in self.projectiles:
pygame.draw.rect() # args do not seem relevant here

draw() 每当有抛射物产生时,游戏速度就会非常慢。

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

编辑:

shoot() 每帧最多调用一次(在键绑定(bind)时触发),projectiles 列表迭代两次(更新和绘制步骤)。

游戏在使用单个射弹时会变得非常卡顿,当射弹到达一定距离( map 限制)并从列表中移除时,游戏会再次变得流畅。

最佳答案

Can I speed up the list iteration process?

不,但也许您在列表上重复了太多次,而不是必要的。当您调用 draw() 时,projectiles 有多大?

Can I implement a better way than a list?

使用 pygame 时,您应该考虑使用 SpriteGroup 类。使用 Group 而不是列表。这提供了一些方便的功能,例如在不同层上绘制 Sprite 、抽象更新和绘制,以及使用 kill() 轻松删除 Sprite 等。

Where could I put some multi-threading in this?

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


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

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)

在这里,您创建了一个新的 Clock 实例,并为每个 Projectile 实例每帧调用两次 tick,这将暂停您的游戏多次框架。

你应该做的是创建一个Clock实例一次,每帧只调用一次tick,然后将结果值传递给你的 Sprite 以调整它们的速度.


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

相机.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

游戏.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)

enter image description here

关于python - 优化对象显示(gamedev),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58856807/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com