Pip S
Pip S

Reputation: 133

pygame sprite flickers when moving - how to fix?

I'm writing a top-down type game and I can't seem to fix the flicker of my world entities when they are drawn to screen... I was wondering if someone can review this code and help me find the solution. Thanks.

#!/usr/bin/env python

#Unnamed Game

import pygame,sys,spriteUtil,random 
from pygame.locals import *
from threading import Thread

class Game():
  def __init__(self):
    pygame.init()
    pygame.key.set_repeat(1,100)
    self.size = (512, 512)
    self.screen = pygame.display.set_mode(self.size)
    self.clock = pygame.time.Clock()

    self.titleScreen = pygame.image.load("unnamed.png")
    self.titleScreenRect = self.titleScreen.get_rect()

    self.screen.blit(self.titleScreen, self.titleScreenRect)
    pygame.display.flip()

class Hero(pygame.sprite.Sprite):
  def __init__(self, screen, background):
    pygame.sprite.Sprite.__init__(self)
    self.size = (30,30)
    self.northWalk = 'link.png'
    self.screen = screen
    self.background = background
    self.s = spriteUtil.SpriteUtility()  #this just takes a sprite sheet and returns a list of sprite images  
    self.northSprites = self.s.getSprites(self.size, self.northWalk) #as above

    self.x_coord = 0
    self.y_coord = 0

  def walkNorthAnimation(self):
    for sprite in self.northSprites:
      self.screen.blit(self.background,(0,0))
      self.screen.blit(sprite, (256-20,256-30))
      pygame.display.update()

class WorldEntity(pygame.sprite.Sprite):
  def __init__(self, screen, ent_img, size=(60,90)):
    pygame.sprite.Sprite.__init__(self)
    self.screen = screen
    self.size = size
    self.ent = pygame.image.load(ent_img)
    self.layer = -100

    self.width, self.height = size
    self.x_coord = random.randint(0,513)
    self.y_coord = random.randint(0,513)


  def drawEnt(self):  
    self.screen.blit(self.ent,(self.x_coord, self.y_coord))

class World():
  def __init__(self, screen):
    self.screen = screen
    self.background = pygame.image.load('grass.png')
    self.backgroundRect = self.background.get_rect()
    self.entityList = []

  def loadWorld(self):
    self.screen.blit(self.background, self.backgroundRect)
    pygame.display.update()

  def populateEntities(self):
    for tree in range(1):
      tree = WorldEntity(self.screen,'tree.png')
      self.entityList.append(tree)

  def drawWorld(self):
    for ent in self.entityList:    
      ent.drawEnt()
    pygame.display.update()

def main():
  g = Game()
  world = World(g.screen)
  world.populateEntities()
  player = Hero(g.screen, world.background)
  player.walkNorthAnimation()
  world.drawWorld()
  while 1: 
    for event in pygame.event.get():
      if event.type == pygame.QUIT: 
        sys.exit()
      elif event.type == KEYDOWN:
        if event.key == pygame.K_w:
          steps = 6
          for step in range(steps): 
            for ent in world.entityList:
              ent.y_coord += 5        
            player.walkNorthAnimation()
            world.drawWorld()

if __name__ == '__main__':
  main()

I have tried just blitting the sprites in the northWalk animation method rather than updating display there and it results in successfully removing the flicker, but then the sprite doesn't animate/"walk".... grateful for advice on how to fix this.

Upvotes: 0

Views: 1025

Answers (2)

furas
furas

Reputation: 143187

if you need sprites animated all time you will have to move blit outside for event loop.

you example

# --- events ---

for event in pygame.event.get():
    if event.key == pygame.K_w:
         move_y = 1
    if event.key == pygame.K_s:
         move_y = -1
    if event.key == pygame.K_a:
         move_x = -1
    if event.key == pygame.K_d:
         move_x = 1

# --- updates in every loop (without drawing) ---

for sprite in player.northSprites:
    for ent in world.entityList:
        ent.x_coord += move_x
        ent.y_coord += move_y

# --- draws in every loop (without updates) ---

g.screen.blit(world.background, (0,0))

g.screen.blit(sprite, (256-20,256-30))
world.drawWorld() 

pygame.display.update()

# --- 25 FPS ---

clock.tick(25)

--

Pygame is not ideal - probably it has problem with VSYNC (vertical synchronization) so it has problem with screen tearing.

Upvotes: 1

Pip S
Pip S

Reputation: 133

thanks for the tips guys - I worked it out!

if event.key == pygame.K_w:
  for sprite in player.northSprites:
    for ent in world.entityList:
      ent.y_coord +=1            
    g.screen.blit(world.background, (0,0))
    g.screen.blit(sprite, (256-20,256-30))
    world.drawWorld() 

And removed the updating from within classes.

Upvotes: 0

Related Questions