Follow up from this question. I have added a slower loading system that allows the main game to run faster but I still get under 30 fps with caves even if I allow the player to outrun the loading. I could lower the worlds loading distance but then terrain has to keep being reloaded for no reason + if you stay still for long enough the terrain can be loaded to a large distance. I have profiled the code and the bottleneck is (obviously) world.load_nearest_chunk , and listcomps, chunks_to_unload = [chunk_pos for chunk_pos in self.chunks if chunk_pos not in chunks_in_range] and chunks_in_range = [(x, y) for x in chunk_range_x for y in chunk_range_y]. I think something like not generating chunks_in_range over and over again would help.
game.py:
import pygame
import world
MOVEMENT_SPEED = 64
class Game:
def __init__(self, title, window_size, fps):
self.title = title
self.window_size = window_size
self.FPS = fps
pygame.init()
self.screen = pygame.display.set_mode(self.window_size)
self.window_rect = pygame.Rect((0, 0), self.window_size)
self.clock = pygame.time.Clock()
pygame.display.set_caption(self.title)
self.running = True
self.world = world_numpy.World(64, 1)
self.cam_x = 0
self.cam_y = 0
self.draw_area = (
int(self.window_size[0] // world_numpy.CHUNK_TOTAL_SIZE) + 2,
int(self.window_size[1] // world_numpy.CHUNK_TOTAL_SIZE) + 2,
)
self.player = self.world.create_entity(
0,
pygame.Vector2(0, -512),
)
self.cam_on_player = True
def run(self):
print("pre-gen")
for i in range(4):
self.world.load_nearest_chunk(fast=True)
while self.running:
self.do_frame()
self.quit_pygame()
def do_frame(self):
self.handle_events()
self.game_logic()
self.draw()
pygame.display.update(self.window_rect)
self.clock.tick(self.FPS)
def quit_pygame(self):
pygame.quit()
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.KEYDOWN:
print(self.clock.get_fps(), len(self.world.chunks))
if event.key == pygame.K_ESCAPE:
self.running = False
if (event.key == pygame.K_w) and self.player.collide_y:
self.player.force += pygame.Vector2(0, -10)
if event.key == pygame.K_c:
self.cam_on_player = not self.cam_on_player
keys = pygame.key.get_pressed()
if not self.cam_on_player:
if keys[pygame.K_LEFT]:
self.cam_x += MOVEMENT_SPEED
elif keys[pygame.K_RIGHT]:
self.cam_x -= MOVEMENT_SPEED
elif keys[pygame.K_UP]:
self.cam_y += MOVEMENT_SPEED
elif keys[pygame.K_DOWN]:
self.cam_y -= MOVEMENT_SPEED
if keys[pygame.K_a]:
self.player.force += pygame.Vector2(-2, 0)
elif keys[pygame.K_d]:
self.player.force += pygame.Vector2(2, 0)
self.world.load_pos = (
int(-self.cam_x // world_numpy.CHUNK_TOTAL_SIZE),
int(-self.cam_y // world_numpy.CHUNK_TOTAL_SIZE),
)
def draw(self):
draw_offset_x = self.cam_x + self.window_rect.centerx
draw_offset_y = self.cam_y + self.window_rect.centery
# draw_offset = pygame.Vector2(draw_offset_x, draw_offset_y)
start_chunk_x = int((-draw_offset_x) // world_numpy.CHUNK_TOTAL_SIZE)
start_chunk_y = int((-draw_offset_y) // world_numpy.CHUNK_TOTAL_SIZE)
chunk_poses = [
(x, y)
for x in range(start_chunk_x, start_chunk_x + self.draw_area[0])
for y in range(start_chunk_y, start_chunk_y + self.draw_area[1])
]
chunk_textures = self.world.get_chunk_textures(chunk_poses)
self.screen.fill((255, 255, 255))
for i, chunk_texture in enumerate(chunk_textures):
chunk_pos = chunk_poses[i]
self.screen.blit(
chunk_texture,
(
(chunk_pos[0] * world_numpy.CHUNK_TOTAL_SIZE) + draw_offset_x,
(chunk_pos[1] * world_numpy.CHUNK_TOTAL_SIZE) + draw_offset_y,
),
)
for entity in self.world.entitys:
self.screen.blit(
entity.image,
(
int(entity.pos.x) + draw_offset_x,
int(entity.pos.y) + draw_offset_y,
),
)
def game_logic(self):
self.world.load_nearest_chunk()
for entity in self.world.entitys:
entity.update()
if self.cam_on_player:
self.cam_x = -int((self.player.pos.x + (self.player.size[0] / 2)))
self.cam_y = -int((self.player.pos.y + (self.player.size[1] / 2)))
new_game = Game("2D Block world_numpy", (1280, 640), 60)
new_game.run()
world.py:
import math
import perlin_noise
import pygame
import numpy
BLOCK_TEXTURE_NAMES = [
"textures/void.png",
"textures/air.png",
"textures/grass_block.png",
"textures/dirt.png",
"textures/stone.png",
"textures/sandstone.png",
"textures/sand.png",
"textures/bedrock.png",
"textures/oak_log.png",
"textures/oak_leaves.png",
"textures/cobblestone.png",
"textures/oak_leaves_over_log.png",
]
BLOCK_COLLISION_DATA = [0, 0, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2]
ENTITY_TEXTURE_NAMES = ["textures/player.png"]
ENTITY_SIZES = [(32, 64)]
ENTITY_HITBOX_DATA = [[(pygame.Vector2(8, 0), pygame.Vector2(16, 64))]]
# ENTITY_ARMS_TEXTURE_NAMES
GRAVITY = pygame.Vector2(0, 1)
RESISTANCE = pygame.Vector2(0.8, 0.99)
BACKGROUND_COLOR = (0, 200, 255)
BLOCK_SIZE = 8
CHUNK_SIZE = 32
CHUNK_TOTAL_SIZE = BLOCK_SIZE * CHUNK_SIZE
CHUNK_RANGE = range(CHUNK_SIZE)
COLUMNS_PER_FRAME = 2
EMPTY_CHUNK_DATA = numpy.zeros((CHUNK_SIZE, CHUNK_SIZE), dtype=numpy.int32)
BEDROCK = 1024
SOIL_AMOUNT = 16
FREQUENCY = 250
AMPLITUDE = 200
CAVE_FREQUENCY = 300
CAVE_SIZE = 0.25
def load_texture(texture, size):
return pygame.transform.scale(pygame.image.load(texture).convert_alpha(), size)
def block_to_chunk(block_pos):
chunk_x, block_x = divmod(block_pos[0], CHUNK_SIZE)
chunk_y, block_y = divmod(block_pos[1], CHUNK_SIZE)
return (chunk_x, chunk_y), (block_x, block_y)
class Textures:
def __init__(self):
self.block_textures = [
load_texture(texture_name, (BLOCK_SIZE, BLOCK_SIZE))
for texture_name in BLOCK_TEXTURE_NAMES
]
self.empty_chunk_surface = pygame.Surface(
(CHUNK_TOTAL_SIZE, CHUNK_TOTAL_SIZE)
).convert_alpha()
self.background_block_surface = pygame.Surface(
(BLOCK_SIZE, BLOCK_SIZE)
).convert_alpha()
self.entity_textures = [
load_texture(texture_name, ENTITY_SIZES[i])
for i, texture_name in enumerate(ENTITY_TEXTURE_NAMES)
]
self.empty_chunk_surface.fill(BACKGROUND_COLOR)
self.background_block_surface.fill(BACKGROUND_COLOR)
class Entity:
def __init__(
self,
world,
entity_number,
init_pos=pygame.Vector2(),
init_vel=pygame.Vector2(),
init_force=pygame.Vector2(),
):
self.world = world
self.size = pygame.Vector2(ENTITY_SIZES[entity_number])
self.image = self.world.textures.entity_textures[entity_number]
self.hitbox_data = ENTITY_HITBOX_DATA[entity_number]
self.pos = init_pos
self.vel = init_vel
self.force = init_force
self.collide_x = False
self.collide_y = False
self.collide_xy = False
self.stuck = False
def get_blocks_collide(self):
blocks = []
for start_pos, size in self.hitbox_data:
start_pos_block = (start_pos + self.test_pos) / BLOCK_SIZE
end_pos_block = (size + start_pos + self.test_pos) / BLOCK_SIZE
block_range_x = range(
math.floor(start_pos_block.x), math.floor(end_pos_block.x) + 1
)
block_range_y = range(
math.floor(start_pos_block.y), math.floor(end_pos_block.y) + 1
)
blocks += [
(block_x, block_y)
for block_x in block_range_x
for block_y in block_range_y
]
return self.world.get_blocks(blocks)
def collide(self):
self.blocks_collide = self.get_blocks_collide()
self.collide_data = [
BLOCK_COLLISION_DATA[block] for block in self.blocks_collide
]
def test(self):
self.test_pos = self.pos.copy()
self.collide()
def test_xy(self):
self.test_pos = self.pos.copy()
self.test_pos += self.vel
self.collide()
def test_x(self):
self.test_pos = self.pos.copy()
self.test_pos.x += self.vel.x
self.collide()
def test_y(self):
self.test_pos = self.pos.copy()
self.test_pos.y += self.vel.y
self.collide()
def update(self):
self.vel += self.force + GRAVITY
self.vel = self.vel.elementwise() * RESISTANCE
self.force = pygame.Vector2()
self.collide_x = False
self.collide_y = False
self.collide_xy = False
self.stuck = False
self.test()
if 1 in self.collide_data:
self.vel = pygame.Vector2()
self.stuck = True
return
self.test_xy()
if 1 in self.collide_data:
self.collide_xy = True
self.test_x()
if 1 in self.collide_data:
self.vel.x = 0
self.collide_x = True
self.test_y()
if 1 in self.collide_data:
self.vel.y = 0
self.collide_y = True
if not (self.collide_x or self.collide_y) and self.collide_xy:
self.vel.y = 0
self.collide_y = True
self.pos += self.vel
class Chunk_loader:
def __init__(self, world, chunk_pos):
self.world = world
self.pos = chunk_pos
self.data = EMPTY_CHUNK_DATA.copy()
self.texture = self.world.textures.empty_chunk_surface.copy()
self.chunk_block_x = self.pos[0] * CHUNK_SIZE
self.chunk_block_y = self.pos[1] * CHUNK_SIZE
self.chunk_block_range_x = [x + self.chunk_block_x for x in CHUNK_RANGE]
self.chunk_block_range_y = [y + self.chunk_block_y for y in CHUNK_RANGE]
self.generate_step = 0
def generate_next(self):
for x in range(self.generate_step, self.generate_step + COLUMNS_PER_FRAME):
if self.generate_step >= CHUNK_SIZE:
self.generate_chunk_texture()
return False
self.generate_data(x)
self.generate_step += 1
return True
def generate_data(self, x):
block_x = self.chunk_block_range_x[x]
surface = int(
self.world.surface_noise.noise(self.chunk_block_range_x[x] / FREQUENCY)
* AMPLITUDE
)
for y in CHUNK_RANGE:
block_y = self.chunk_block_range_y[y]
cave_noise = (
self.world.cave_noise.noise(
(block_x / CAVE_FREQUENCY, block_y / CAVE_FREQUENCY)
)
* 10
) + 1
cave = (cave_noise > (0.5 - CAVE_SIZE)) and (cave_noise < (0.5 + CAVE_SIZE))
if not block_y > BEDROCK:
if not cave:
if block_y == surface:
block_type = 2
elif block_y > surface and block_y <= surface + SOIL_AMOUNT:
block_type = 3
elif block_y > surface + SOIL_AMOUNT and block_y < BEDROCK:
block_type = 4
elif block_y == BEDROCK:
block_type = 7
else:
block_type = 1
else:
block_type = 1
else:
block_type = 0
self.data[x, y] = block_type
def generate_all_data(self):
surface = 0
for x in CHUNK_RANGE:
block_x = self.chunk_block_range_x[x]
if not self.world.flat:
surface = int(
self.world.surface_noise.noise(block_x / FREQUENCY) * AMPLITUDE
)
for y in CHUNK_RANGE:
block_y = self.chunk_block_range_y[y]
cave_noise = (
self.world.cave_noise.noise(
(block_x / CAVE_FREQUENCY, block_y / CAVE_FREQUENCY)
)
* 10
) + 1
cave = (cave_noise > (0.5 - CAVE_SIZE)) and (
cave_noise < (0.5 + CAVE_SIZE)
)
if not block_y > BEDROCK:
if not cave:
if block_y == surface:
block_type = 2
elif block_y > surface and block_y <= surface + SOIL_AMOUNT:
block_type = 3
elif block_y > surface + SOIL_AMOUNT and block_y < BEDROCK:
block_type = 4
elif block_y == BEDROCK:
block_type = 7
else:
block_type = 1
else:
block_type = 1
else:
block_type = 0
self.data[x, y] = block_type
self.generate_chunk_texture()
def generate_chunk_texture(self):
for x in CHUNK_RANGE:
for y in CHUNK_RANGE:
data = self.data[x, y]
self.texture.blit(
self.world.textures.block_textures[data],
(x * BLOCK_SIZE, y * BLOCK_SIZE),
)
class World:
def __init__(self, load_distance, seed=0):
self.flat = True
if seed:
self.flat = False
self.surface_noise = perlin_noise.PerlinNoise(octaves=1.3, seed=seed)
self.cave_noise = perlin_noise.PerlinNoise(octaves=1.3, seed=seed + 1)
self.textures = Textures()
self.chunks = {}
self.chunk_textures = {}
self.load_pos = (0, 0)
self.load_distance = load_distance
self.entitys = []
self.chunk_to_load = None
def create_entity(
self,
entity_number,
init_pos=pygame.Vector2(),
init_vel=pygame.Vector2(),
init_force=pygame.Vector2(),
):
new_entity = Entity(
self,
entity_number,
init_pos,
init_vel,
init_force,
)
self.entitys.append(new_entity)
return new_entity
def load_nearest_chunk(self, fast=False):
chunk_range_x = range(
self.load_pos[0] - self.load_distance,
self.load_pos[0] + self.load_distance + 1,
)
chunk_range_y = range(
self.load_pos[1] - self.load_distance,
self.load_pos[1] + self.load_distance + 1,
)
chunks_in_range = [(x, y) for x in chunk_range_x for y in chunk_range_y]
chunks_to_load = []
for chunk_pos in chunks_in_range:
if not self.chunk_to_load == None:
if self.chunk_to_load.pos == chunk_pos:
continue
if chunk_pos not in self.chunks:
chunks_to_load.append(chunk_pos)
chunks_to_unload = [chunk_pos for chunk_pos in self.chunks if chunk_pos not in chunks_in_range]
distances_from_load_pos = [
math.dist(self.load_pos, chunk_pos) for chunk_pos in chunks_to_load
]
if distances_from_load_pos:
best_distance = min(distances_from_load_pos)
self.set_chunk_loader(
chunks_to_load[distances_from_load_pos.index(best_distance)]
)
for chunk_pos in chunks_to_unload:
self.chunks.pop(chunk_pos)
self.chunk_textures.pop(chunk_pos)
if self.chunk_to_load:
if fast:
self.load_chunk_fast()
else:
self.load_chunk()
def set_chunk_loader(self, chunk_pos):
if self.chunk_to_load == None:
self.chunk_to_load = Chunk_loader(self, chunk_pos)
def load_chunk(self):
if not self.chunk_to_load.generate_next():
self.finish_chunk()
def load_chunk_fast(self):
self.chunk_to_load.generate_all_data()
self.finish_chunk()
def finish_chunk(self):
self.chunks[self.chunk_to_load.pos] = self.chunk_to_load.data
self.chunk_textures[self.chunk_to_load.pos] = self.chunk_to_load.texture
self.chunk_to_load = None
def get_blocks(self, block_poses):
blocks = []
for block_pos in block_poses:
chunk_pos, local_block_pos = block_to_chunk(block_pos)
if chunk_pos in self.chunks:
blocks.append(self.chunks[chunk_pos][local_block_pos])
else:
blocks.append(0)
return blocks
def get_chunk_textures(self, chunk_poses):
chunk_textures = []
for chunk_pos in chunk_poses:
if chunk_pos in self.chunk_textures:
chunk_textures.append(self.chunk_textures[chunk_pos])
else:
chunk_textures.append(self.textures.empty_chunk_surface)
return chunk_textures
Profile output:
1 0.000 0.000 12.035 12.035 game.py:1(<module>)
169 0.002 0.000 0.002 0.000 game.py:100(<listcomp>)
169 0.200 0.001 8.133 0.048 game.py:128(game_logic)
1 0.006 0.006 10.088 10.088 game.py:36(run)
169 0.007 0.000 9.104 0.054 game.py:45(do_frame)
1 0.000 0.000 0.075 0.075 game.py:54(quit_pygame)
169 0.006 0.000 0.152 0.001 game.py:57(handle_events)
1 0.000 0.000 0.000 0.000 game.py:7(Game)
1 0.000 0.000 0.290 0.290 game.py:8(__init__)
169 0.020 0.000 0.585 0.003 game.py:92(draw)
1 0.000 0.000 0.024 0.024 world.py:1(<module>)
384 0.006 0.000 0.049 0.000 world.py:102(get_blocks_collide)
384 0.002 0.000 0.002 0.000 world.py:115(<listcomp>)
384 0.003 0.000 0.053 0.000 world.py:122(collide)
384 0.002 0.000 0.002 0.000 world.py:124(<listcomp>)
169 0.001 0.000 0.029 0.000 world.py:128(test)
169 0.001 0.000 0.021 0.000 world.py:132(test_xy)
23 0.000 0.000 0.003 0.000 world.py:137(test_x)
23 0.000 0.000 0.003 0.000 world.py:142(test_y)
169 0.006 0.000 0.061 0.000 world.py:147(update)
1 0.000 0.000 0.000 0.000 world.py:182(Chunk_loader)
14 0.000 0.000 0.006 0.000 world.py:183(__init__)
14 0.000 0.000 0.000 0.000 world.py:191(<listcomp>)
14 0.000 0.000 0.000 0.000 world.py:192(<listcomp>)
169 0.003 0.000 1.876 0.011 world.py:196(generate_next)
320 0.059 0.000 1.842 0.006 world.py:205(generate_data)
4 0.023 0.006 0.770 0.193 world.py:238(generate_all_data)
13 0.020 0.002 0.046 0.004 world.py:277(generate_chunk_texture)
1 0.000 0.000 0.000 0.000 world.py:287(World)
1 0.000 0.000 0.038 0.038 world.py:288(__init__)
1 0.000 0.000 0.000 0.000 world.py:305(create_entity)
173 2.308 0.013 8.776 0.051 world.py:322(load_nearest_chunk)
173 0.492 0.003 0.492 0.003 world.py:331(<listcomp>)
173 0.696 0.004 0.696 0.004 world.py:342(<listcomp>)
173 1.155 0.007 2.000 0.012 world.py:344(<listcomp>)
173 0.001 0.000 0.007 0.000 world.py:363(set_chunk_loader)
169 0.001 0.000 1.877 0.011 world.py:367(load_chunk)
4 0.000 0.000 0.770 0.193 world.py:371(load_chunk_fast)
13 0.000 0.000 0.000 0.000 world.py:375(finish_chunk)
384 0.019 0.000 0.038 0.000 world.py:380(get_blocks)
169 0.004 0.000 0.005 0.000 world.py:390(get_chunk_textures)
13 0.000 0.000 0.037 0.003 world.py:48(load_texture)
10368 0.012 0.000 0.017 0.000 world.py:52(block_to_chunk)
1 0.000 0.000 0.000 0.000 world.py:58(Textures)
1 0.000 0.000 0.038 0.038 world.py:59(__init__)
1 0.000 0.000 0.034 0.034 world.py:60(<listcomp>)
1 0.000 0.000 0.002 0.002 world.py:70(<listcomp>)
1 0.000 0.000 0.000 0.000 world.py:79(Entity)
1 0.000 0.000 0.000 0.000 world.py:80(__init__)
1659 0.003 0.000 0.003 0.000 {built-in method __new__ of type object at 0x00007FFC4B94B810}
43 0.001 0.000 0.001 0.000 {built-in method _abc._abc_init}
14470 0.013 0.000 0.013 0.000 {built-in method _abc._abc_instancecheck}
12 0.000 0.000 0.000 0.000 {built-in method _abc._abc_register}
30/15 0.000 0.000 0.000 0.000 {built-in method _abc._abc_subclasscheck}
1 0.000 0.000 0.000 0.000 {built-in method _codecs.charmap_decode}
30 0.000 0.000 0.000 0.000 {built-in method _codecs.utf_8_decode}
2 0.003 0.002 0.003 0.002 {built-in method _ctypes.LoadLibrary}
2 0.000 0.000 0.000 0.000 {built-in method _ctypes.POINTER}
38 0.000 0.000 0.000 0.000 {built-in method _ctypes.sizeof}
1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_md5}
1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha1}
1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha224}
1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha256}
1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha384}
1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha512}
186 0.000 0.000 0.000 0.000 {built-in method _imp._fix_co_filename}
1818 0.001 0.000 0.001 0.000 {built-in method _imp.acquire_lock}
18 0.001 0.000 0.001 0.000 {built-in method _imp.create_builtin}
52/50 0.225 0.004 0.238 0.005 {built-in method _imp.create_dynamic}
18 0.000 0.000 0.000 0.000 {built-in method _imp.exec_builtin}
52/47 0.005 0.000 0.058 0.001 {built-in method _imp.exec_dynamic}
92 0.000 0.000 0.000 0.000 {built-in method _imp.is_builtin}
247 0.000 0.000 0.000 0.000 {built-in method _imp.is_frozen}
1818 0.001 0.000 0.001 0.000 {built-in method _imp.release_lock}
1 0.000 0.000 0.000 0.000 {built-in method _locale._getdefaultlocale}
1 0.000 0.000 0.000 0.000 {built-in method _socket.gethostname}
4 0.000 0.000 0.000 0.000 {built-in method _sre.ascii_iscased}
4 0.000 0.000 0.000 0.000 {built-in method _sre.ascii_tolower}
93 0.000 0.000 0.000 0.000 {built-in method _sre.compile}
609 0.000 0.000 0.000 0.000 {built-in method _sre.unicode_iscased}
463 0.000 0.000 0.000 0.000 {built-in method _sre.unicode_tolower}
596 0.000 0.000 0.000 0.000 {built-in method _stat.S_ISDIR}
1 0.000 0.000 0.000 0.000 {built-in method _stat.S_ISREG}
23 0.000 0.000 0.000 0.000 {built-in method _struct.calcsize}
1 0.000 0.000 0.000 0.000 {built-in method _thread._set_sentinel}
543 0.003 0.000 0.003 0.000 {built-in method _thread.allocate_lock}
1387 0.001 0.000 0.001 0.000 {built-in method _thread.get_ident}
1 0.000 0.000 0.000 0.000 {built-in method _thread.get_native_id}
5 0.000 0.000 0.000 0.000 {built-in method _warnings._filters_mutated}
2 0.000 0.000 0.000 0.000 {built-in method _win32sysloader.GetModuleFilename}
1 0.000 0.000 0.000 0.000 {built-in method _win32sysloader.LoadModule}
6 0.000 0.000 0.000 0.000 {built-in method _winapi.CloseHandle}
1 0.000 0.000 0.000 0.000 {built-in method _winapi.CreatePipe}
1 0.051 0.051 0.051 0.051 {built-in method _winapi.CreateProcess}
3 0.000 0.000 0.000 0.000 {built-in method _winapi.DuplicateHandle}
6 0.000 0.000 0.000 0.000 {built-in method _winapi.GetCurrentProcess}
1 0.000 0.000 0.000 0.000 {built-in method _winapi.GetExitCodeProcess}
1 0.000 0.000 0.000 0.000 {built-in method _winapi.GetStdHandle}
1 0.001 0.001 0.001 0.001 {built-in method _winapi.WaitForSingleObject}
519/515 0.017 0.000 0.089 0.000 {built-in method builtins.__build_class__}
381/18 0.001 0.000 0.979 0.054 {built-in method builtins.__import__}
115692 0.027 0.000 0.027 0.000 {built-in method builtins.abs}
219 0.000 0.000 0.000 0.000 {built-in method builtins.all}
126 0.000 0.000 0.000 0.000 {built-in method builtins.any}
11 0.000 0.000 0.000 0.000 {built-in method builtins.callable}
558 0.000 0.000 0.000 0.000 {built-in method builtins.chr}
3 0.000 0.000 0.000 0.000 {built-in method builtins.dir}
20796 0.005 0.000 0.005 0.000 {built-in method builtins.divmod}
207/1 0.005 0.000 12.035 12.035 {built-in method builtins.exec}
6032 0.006 0.000 0.006 0.000 {built-in method builtins.getattr}
411 0.000 0.000 0.000 0.000 {built-in method builtins.globals}
2895 0.002 0.000 0.002 0.000 {built-in method builtins.hasattr}
36 0.000 0.000 0.000 0.000 {built-in method builtins.hash}
18 0.000 0.000 0.000 0.000 {built-in method builtins.id}
55925 0.035 0.000 0.058 0.000 {built-in method builtins.isinstance}
645 0.000 0.000 0.000 0.000 {built-in method builtins.issubclass}
8 0.000 0.000 0.000 0.000 {built-in method builtins.iter}
342801/341843 0.069 0.000 0.070 0.000 {built-in method builtins.len}
1 0.000 0.000 0.000 0.000 {built-in method builtins.locals}
994 0.002 0.000 0.003 0.000 {built-in method builtins.max}
2838 0.116 0.000 0.116 0.000 {built-in method builtins.min}
24 0.000 0.000 0.010 0.000 {built-in method builtins.next}
1910 0.001 0.000 0.001 0.000 {built-in method builtins.ord}
24 0.006 0.000 0.006 0.000 {built-in method builtins.print}
107 0.000 0.000 0.000 0.000 {built-in method builtins.repr}
12 0.000 0.000 0.000 0.000 {built-in method builtins.round}
1928 0.001 0.000 0.001 0.000 {built-in method builtins.setattr}
21 0.002 0.000 0.115 0.005 {built-in method builtins.sorted}
73036 0.041 0.000 0.041 0.000 {built-in method builtins.sum}
6 0.000 0.000 0.000 0.000 {built-in method builtins.vars}
559 0.000 0.000 0.000 0.000 {built-in method from_bytes}
247 0.001 0.000 0.001 0.000 {built-in method fromkeys}
186 0.344 0.002 0.344 0.002 {built-in method io.open_code}
9 0.010 0.001 0.010 0.001 {built-in method io.open}
2 0.000 0.000 0.000 0.000 {built-in method maketrans}
186 0.043 0.000 0.043 0.000 {built-in method marshal.loads}
2877296 0.845 0.000 0.845 0.000 {built-in method math.dist}
1 0.000 0.000 0.000 0.000 {built-in method math.exp}
59776 0.046 0.000 0.046 0.000 {built-in method math.floor}
2 0.000 0.000 0.000 0.000 {built-in method math.log}
346752 0.187 0.000 0.187 0.000 {built-in method math.pow}
1 0.000 0.000 0.000 0.000 {built-in method math.sqrt}
1 0.000 0.000 0.000 0.000 {built-in method msvcrt.get_osfhandle}
1 0.000 0.000 0.000 0.000 {built-in method msvcrt.open_osfhandle}
2 0.000 0.000 0.000 0.000 {built-in method nt._add_dll_directory}
26 0.007 0.000 0.007 0.000 {built-in method nt._getfinalpathname}
4 0.000 0.000 0.000 0.000 {built-in method nt._getfullpathname}
262 0.001 0.000 0.001 0.000 {built-in method nt._path_splitroot}
1 0.000 0.000 0.000 0.000 {built-in method nt.close}
8268 0.002 0.000 0.002 0.000 {built-in method nt.fspath}
88 0.000 0.000 0.000 0.000 {built-in method nt.getcwd}
245 0.059 0.000 0.059 0.000 {built-in method nt.listdir}
1 0.000 0.000 0.000 0.000 {built-in method nt.open}
5 0.000 0.000 0.000 0.000 {built-in method nt.putenv}
1 0.000 0.000 0.000 0.000 {built-in method nt.readlink}
1 0.000 0.000 0.000 0.000 {built-in method nt.scandir}
1770 0.280 0.000 0.280 0.000 {built-in method nt.stat}
1 0.000 0.000 0.000 0.000 {built-in method nt.urandom}
118 0.001 0.000 0.001 0.000 {built-in method numpy.array}
1 0.000 0.000 0.000 0.000 {built-in method numpy.core._multiarray_umath._reload_guard}
1 0.000 0.000 0.000 0.000 {built-in method numpy.core._multiarray_umath._set_madvise_hugepage}
338 0.000 0.000 0.000 0.000 {built-in method numpy.core._multiarray_umath.add_docstring}
2 0.000 0.000 0.000 0.000 {built-in method numpy.core._multiarray_umath.implement_array_function}
1 0.000 0.000 0.000 0.000 {built-in method numpy.core._multiarray_umath.set_typeDict}
1 0.000 0.000 0.000 0.000 {built-in method numpy.empty}
18 0.000 0.000 0.000 0.000 {built-in method numpy.geterrobj}
9 0.000 0.000 0.000 0.000 {built-in method numpy.seterrobj}
1 0.000 0.000 0.000 0.000 {built-in method numpy.zeros}
3 0.000 0.000 0.000 0.000 {built-in method pygame.base.get_sdl_version}
1 0.181 0.181 0.191 0.191 {built-in method pygame.base.init}
1 0.075 0.075 0.075 0.075 {built-in method pygame.base.quit}
1 0.000 0.000 0.000 0.000 {built-in method pygame.display.set_caption}
1 0.059 0.059 0.062 0.062 {built-in method pygame.display.set_mode}
169 0.223 0.001 0.223 0.001 {built-in method pygame.display.update}
169 0.136 0.001 0.136 0.001 {built-in method pygame.event.get}
13 0.036 0.003 0.036 0.003 {built-in method pygame.image.load}
169 0.004 0.000 0.004 0.000 {built-in method pygame.key.get_pressed}
13 0.000 0.000 0.000 0.000 {built-in method pygame.transform.scale}
55 0.000 0.000 0.000 0.000 {built-in method sys._getframe}
2 0.000 0.000 0.000 0.000 {built-in method sys.audit}
1 0.000 0.000 0.000 0.000 {built-in method sys.exc_info}
2 0.001 0.000 0.001 0.000 {built-in method sys.getwindowsversion}
114 0.000 0.000 0.000 0.000 {built-in method sys.intern}
1 0.000 0.000 0.000 0.000 {built-in method win32api.GetFullPathName}
1 0.000 0.000 0.000 0.000 {built-in method win32api.GetTempPath}
1 0.000 0.000 0.000 0.000 {built-in method win32api.RegOpenKey}
1 0.000 0.000 0.000 0.000 {built-in method winreg.OpenKeyEx}
1 0.000 0.000 0.000 0.000 {built-in method winreg.QueryValueEx}
12 0.000 0.000 0.000 0.000 {function Random.getstate at 0x000002652F7A5AF0}
13 0.000 0.000 0.000 0.000 {function Random.seed at 0x000002652F7A5C10}
12 0.000 0.000 0.000 0.000 {function Random.setstate at 0x000002652F7A5DC0}
1 0.000 0.000 0.000 0.000 {function SeedSequence.generate_state at 0x000002652F747EE0}
114 0.000 0.000 0.000 0.000 {method '__contains__' of 'frozenset' objects}
1 0.000 0.000 0.000 0.000 {method '__enter__' of '_thread.lock' objects}
1 0.000 0.000 0.000 0.000 {method '__exit__' of '_thread.lock' objects}
11 0.000 0.000 0.000 0.000 {method '__init_subclass__' of 'object' objects}
471 0.001 0.000 0.001 0.000 {method '__reduce_ex__' of 'object' objects}
2 0.000 0.000 0.000 0.000 {method 'acquire' of '_thread.lock' objects}
842 0.000 0.000 0.000 0.000 {method 'add' of 'set' objects}
4 0.000 0.000 0.000 0.000 {method 'append' of 'collections.deque' objects}
2914448 0.474 0.000 0.474 0.000 {method 'append' of 'list' objects}
6 0.000 0.000 0.000 0.000 {method 'bit_length' of 'int' objects}
18213 0.470 0.000 0.470 0.000 {method 'blit' of 'pygame.surface.Surface' objects}
7 0.000 0.000 0.000 0.000 {method 'cast' of 'memoryview' objects}
6 0.000 0.000 0.000 0.000 {method 'clear' of 'dict' objects}
2 0.000 0.000 0.000 0.000 {method 'close' of '_io.TextIOWrapper' objects}
15 0.000 0.000 0.000 0.000 {method 'convert_alpha' of 'pygame.surface.Surface' objects}
3 0.000 0.000 0.000 0.000 {method 'copy' of 'dict' objects}
2 0.000 0.000 0.000 0.000 {method 'copy' of 'list' objects}
86 0.001 0.000 0.001 0.000 {method 'copy' of 'numpy.ndarray' objects}
384 0.000 0.000 0.000 0.000 {method 'copy' of 'pygame.math.Vector2' objects}
14 0.005 0.000 0.005 0.000 {method 'copy' of 'pygame.surface.Surface' objects}
1 0.000 0.000 0.000 0.000 {method 'count' of 'list' objects}
8 0.000 0.000 0.000 0.000 {method 'decode' of 'bytes' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
18 0.000 0.000 0.000 0.000 {method 'discard' of 'set' objects}
1 0.000 0.000 0.000 0.000 {method 'dot' of 'numpy.ndarray' objects}
169 0.000 0.000 0.000 0.000 {method 'elementwise' of 'pygame.math.Vector2' objects}
4 0.000 0.000 0.000 0.000 {method 'encode' of 'str' objects}
15 0.000 0.000 0.000 0.000 {method 'end' of 're.Match' objects}
11564 0.005 0.000 0.005 0.000 {method 'endswith' of 'str' objects}
31 0.000 0.000 0.000 0.000 {method 'expandtabs' of 'str' objects}
308 0.000 0.000 0.001 0.000 {method 'extend' of 'list' objects}
171 0.115 0.001 0.115 0.001 {method 'fill' of 'pygame.surface.Surface' objects}
1141 0.001 0.000 0.001 0.000 {method 'find' of 'bytearray' objects}
3 0.000 0.000 0.000 0.000 {method 'find' of 'str' objects}
4 0.000 0.000 0.000 0.000 {method 'findall' of 're.Pattern' objects}
1330 0.002 0.000 0.002 0.000 {method 'format' of 'str' objects}
10050 0.003 0.000 0.003 0.000 {method 'get' of 'dict' objects}
133 0.000 0.000 0.000 0.000 {method 'get' of 'mappingproxy' objects}
21 0.000 0.000 0.000 0.000 {method 'get_fps' of 'pygame.time.Clock' objects}
4315 0.002 0.000 0.002 0.000 {method 'group' of 're.Match' objects}
12 0.000 0.000 0.000 0.000 {method 'groupdict' of 're.Match' objects}
2 0.000 0.000 0.000 0.000 {method 'groups' of 're.Match' objects}
173 0.049 0.000 0.049 0.000 {method 'index' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'index' of 'tuple' objects}
1 0.000 0.000 0.000 0.000 {method 'indices' of 'slice' objects}
16 0.000 0.000 0.000 0.000 {method 'insert' of 'list' objects}
173 0.000 0.000 0.000 0.000 {method 'isidentifier' of 'str' objects}
12 0.000 0.000 0.000 0.000 {method 'islower' of 'str' objects}
845 0.000 0.000 0.000 0.000 {method 'isupper' of 'str' objects}
170 0.000 0.000 0.000 0.000 {method 'items' of 'dict' objects}
44 0.000 0.000 0.000 0.000 {method 'items' of 'mappingproxy' objects}
3629/3555 0.004 0.000 0.101 0.000 {method 'join' of 'str' objects}
3 0.000 0.000 0.000 0.000 {method 'keys' of 'dict' objects}
3602 0.001 0.000 0.001 0.000 {method 'lower' of 'str' objects}
926 0.000 0.000 0.000 0.000 {method 'lstrip' of 'str' objects}
345 0.001 0.000 0.001 0.000 {method 'match' of 're.Pattern' objects}
14 0.000 0.000 0.000 0.000 {method 'mro' of 'type' objects}
486 0.000 0.000 0.000 0.000 {method 'partition' of 'str' objects}
4 0.000 0.000 0.000 0.000 {method 'pop' of 'collections.deque' objects}
279 0.000 0.000 0.000 0.000 {method 'pop' of 'dict' objects}
48 0.000 0.000 0.000 0.000 {method 'pop' of 'list' objects}
21 0.000 0.000 0.000 0.000 {method 'random' of '_random.Random' objects}
192 0.028 0.000 0.028 0.000 {method 'read' of '_io.BufferedReader' objects}
1 0.015 0.015 0.015 0.015 {method 'read' of '_io.TextIOWrapper' objects}
2 0.000 0.000 0.000 0.000 {method 'readline' of '_io.BufferedReader' objects}
1 0.003 0.003 0.003 0.003 {method 'readlines' of '_io._IOBase' objects}
8 0.000 0.000 0.000 0.000 {method 'remove' of 'list' objects}
316 0.001 0.000 0.001 0.000 {method 'replace' of 'code' objects}
5152 0.002 0.000 0.002 0.000 {method 'replace' of 'str' objects}
27 0.000 0.000 0.000 0.000 {method 'reverse' of 'list' objects}
1956 0.002 0.000 0.002 0.000 {method 'rfind' of 'str' objects}
1671 0.002 0.000 0.002 0.000 {method 'rpartition' of 'str' objects}
6 0.000 0.000 0.000 0.000 {method 'rsplit' of 'str' objects}
8098 0.003 0.000 0.003 0.000 {method 'rstrip' of 'str' objects}
1025 0.005 0.000 0.005 0.000 {method 'search' of 're.Pattern' objects}
1 0.000 0.000 0.000 0.000 {method 'seek' of '_io.BufferedReader' objects}
469 0.000 0.000 0.000 0.000 {method 'setdefault' of 'dict' objects}
22 0.000 0.000 0.000 0.000 {method 'setter' of 'property' objects}
9 0.000 0.000 0.000 0.000 {method 'sort' of 'list' objects}
626 0.004 0.000 0.004 0.000 {method 'split' of 're.Pattern' objects}
932 0.001 0.000 0.001 0.000 {method 'split' of 'str' objects}
6 0.000 0.000 0.000 0.000 {method 'splitlines' of 'str' objects}
1 0.000 0.000 0.000 0.000 {method 'startswith' of 'bytes' objects}
13481 0.008 0.000 0.008 0.000 {method 'startswith' of 'str' objects}
442 0.000 0.000 0.000 0.000 {method 'strip' of 'str' objects}
210 0.001 0.000 0.001 0.000 {method 'sub' of 're.Pattern' objects}
169 0.004 0.000 0.004 0.000 {method 'tick' of 'pygame.time.Clock' objects}
2 0.000 0.000 0.000 0.000 {method 'title' of 'str' objects}
7 0.000 0.000 0.000 0.000 {method 'tolist' of 'memoryview' objects}
1 0.000 0.000 0.000 0.000 {method 'toordinal' of 'datetime.date' objects}
55 0.000 0.000 0.000 0.000 {method 'translate' of 'bytearray' objects}
99 0.000 0.000 0.000 0.000 {method 'translate' of 'str' objects}
1 0.000 0.000 0.000 0.000 {method 'union' of 'set' objects}
881 0.002 0.000 0.002 0.000 {method 'update' of 'dict' objects}
53 0.000 0.000 0.000 0.000 {method 'upper' of 'str' objects}
17 0.000 0.000 0.000 0.000 {method 'values' of 'dict' objects}
1 0.000 0.000 0.000 0.000 {method 'view' of 'numpy.generic' objects}
4/3 0.000 0.000 0.000 0.000 {method 'view' of 'numpy.ndarray' objects}
228 0.000 0.000 0.000 0.000 {method 'zfill' of 'str' objects}












