- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
相关代码,简化:
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 时,您应该考虑使用 Sprite
和 Group
类。使用 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)
关于python - 优化对象显示(gamedev),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58856807/
相关代码,简化: class Character: def __init__(self): self.projectiles = [] def shoot(self):
我目前正在用 Java 从头开始编写一个简单的 2D 游戏(出于学习目的) 我想控制玩家射击的速度。那里完成的方法有效,但还可以改进。如果用户按下/按住鼠标左键,则会调用该方法。当用户按住按钮时它
我只是想知道 gamedev 中的一些东西是如何工作的: 我知道,性能实际上至关重要,所以仍然(而且我认为永远不会)没有地方可以使用 Java/.NET 等托管语言/平台,只是因为他们的表现。但是..
背景 我们正在使用 C# 和 .NET Core 处理 RTS game engine。与大多数其他实时多人游戏不同,RTS 游戏倾向于将玩家输入同步给其他玩家,并同时在所有客户端上同步运行游戏模拟。
我从事自上而下的汽车游戏已经有一段时间了,它似乎总是回到能够正确地做一件事。在我的例子中,它正确地完成了我的汽车物理。 我遇到了当前轮换处理不当的问题。我知道问题在于我的幅度在乘以 Math.cos/
我是一名优秀的程序员,十分优秀!