Goal, Description & Scope (when encountered issue)
I was building a testing script to see how implementing different ideas (event handling, update handling, draw method) to loading sprite images, passing data between class objects/attributes, movement mechanics, and the like. When I noticed the self.all_sprites
instance of pygame.sprite.Group.draw
method wasn't rendering the player image to the display. I walked through it line by line, threw in some print
functions to check the script a different points, spent some time looking through Pygame's docs (online & looking inside libs directory to see how Pygame built SpriteGroup objects), StackOverflow, & general to specific search queries of other sites... Still, I have no clue why the SpriteGroup draw method doesn't work, but Player's draw method does. SpriteGroup update works, and everything else seems to run fine, but not drawing to the main display through SpriteGroup's draw method.
Full code below:
import sys
from os import listdir
from os.path import join
import pygame as pg
# support function image loader
def img_loader(path=r'..\tmp'):
if path:
img_dir = {}
ls_files = listdir(path)
for file in ls_files:
if '.py' not in file:
key = file.split('.')[0]
value = pg.image.load(join(path, file)).convert_alpha()
img_dir[key] = value
img_dir['left'] = pg.transform.flip(
img_dir['right'], True, False)
img_dir['topleft'] = pg.transform.flip(
img_dir['topright'], True, False)
img_dir['bottomleft'] = pg.transform.flip(
img_dir['bottomright'], True, False)
img_dir['left_sink0'] = pg.transform.flip(
img_dir['right_sink0'], True, False)
img_dir['topleft_sink0'] = pg.transform.flip(
img_dir['topright_sink0'], True, False)
img_dir['bottomleft_sink0'] = pg.transform.flip(
img_dir['bottomright_sink0'], True, False)
img_dir['left_sink1'] = pg.transform.flip(
img_dir['right_sink1'], True, False)
img_dir['topleft_sink1'] = pg.transform.flip(
img_dir['topright_sink1'], True, False)
img_dir['bottomleft_sink1'] = pg.transform.flip(
img_dir['bottomright_sink1'], True, False)
return img_dir
else:
tmp = {}
return tmp
class Projectile(pg.sprite.Sprite):
def __init__(self):
pass
# Player Sprite
class Player(pg.sprite.Sprite):
def __init__(self, groups):
super().__init__(groups)
self.ds = pg.display.get_surface()
self.img_dir = img_loader()
self.key_dir = 'bottom'
self.image_reset = False
self.pos = pg.Vector2(200, 200)
self.image = self.img_dir[self.key_dir]#implement
self.rect = self.image.get_rect(center=self.pos)
self.direction = pg.Vector2()
self.speed = 100
self.projectiles = pg.sprite.Group()
def key_w(self, delta): self.direction.y -= self.speed * delta
def key_s(self, delta): self.direction.y += self.speed * delta
def key_a(self, delta): self.direction.x -= self.speed * delta
def key_d(self, delta): self.direction.x += self.speed * delta
def fire(self, delta, pos):
print('Cannon has fired')
pass# make bullet & add to self.projectiles w/delayed timer
def update(self, delta):
# update bullets before player
# make bullet class w/update method
#self.projectiles.update(delta)
if self.direction.x != 0.0 and self.direction.y != 0.0:
if self.direction.y < 0.0 and self.direction.x < 0.0:
self.key_dir = 'topleft'
elif self.direction.y < 0.0 and self.direction.x > 0.0:
self.key_dir = 'topright'
elif self.direction.y > 0.0 and self.direction.x < 0.0:
self.key_dir = 'bottomleft'
else: self.key_dir = 'bottomright'
self.direction *= 0.707107 # equalize diagonal movement
self.image_reset = True
else:
if self.direction.y != 0.0:
self.image_reset = True
if self.direction.y < 0.0: self.key_dir = 'top'
else: self.key_dir = 'bottom'
elif self.direction.x != 0.0:
self.image_reset = True
if self.direction.x < 0.0: self.key_dir = 'left'
else: self.key_dir = 'right'
else: pass
self.pos += self.direction
self.direction.x, self.direction.y = 0.0, 0.0
def draw(self, ds):
# draw bullets before player
#if self.projectiles.sprites(): self.projectiles.draw(ds)
#else: pass
if self.image_reset:
self.image = self.img_dir[self.key_dir]
self.rect = self.image.get_rect(center=self.pos)
self.image_reset = False
ds.blit(self.image, self.rect)
else:
ds.blit(self.image, self.rect)
# Main testing object
class Main:
def __init__(self):
pg.init()
self.display = pg.display.set_mode((400, 400), 0, 32)
pg.key.set_repeat(25, 25)
self.time = pg.time.Clock()
self.all_sprites = pg.sprite.Group()
self.player = Player(self.all_sprites)
def run(self):
# preset vars
done = False
paused = False
# set while loop
while not done:
# get framerate
delta = self.time.tick() / 1000
# handle Events
if pg.event.get(pg.QUIT): done = True
keys = pg.key.get_pressed()
if keys[pg.K_ESCAPE]: done = True
if keys[pg.K_SPACE]:
mouse_pos = pg.mouse.get_pos()
self.player.fire(delta, mouse_pos)
if keys[pg.K_w]: self.player.key_w(delta)
if keys[pg.K_s]: self.player.key_s(delta)
if keys[pg.K_a]: self.player.key_a(delta)
if keys[pg.K_d]: self.player.key_d(delta)
pg.event.clear()
# handle Updates
self.player.update(delta)
## self.all_sprites.update(delta) # Does handle correctly
# handle Drawing
_ = self.display.fill('black')
self.player.draw(self.display) # WORKS, draws to self.display
## self.all_sprites.draw(self.display) # Doesn't draw to self.display, gives a non-updated image
# Update main display
pg.display.update()
# autorun
if __name__ == '__main__':
test = Main()
test.run()
pg.quit()
sys.exit()
Image Illustration
I need to get the self.all_sprites
method draw
fully working, for implementing & testing down the road, especially with multiple sprites (passive, enemies, etc ...)
Inclosing
Any & all insight would be greatly appreciated, and I would like to express my Thanks for taking the time to help me figure this out.