Skip to main content
Addressed question by OP.
Source Link
Bram
  • 3.7k
  • 20
  • 26

It's easier to handle allJust iterate over the events inas you retrieve them from the same placequeue, so you don't reuseand handle them right then and there, without keeping a reference to it. You could move the player sprite

You can use a secondary handler in Player class to do the game event loop like this:actual work for keypresses if you want, as show below.

import pygame_sdl2 as pg

# colors
WHITE = (255, 255, 255)
GREY = (100, 100, 100)

class Game:

    def __init__(self):
        pg.init()
        self.screen = pg.display.set_mode((640, 640))
        self.clock = pg.time.Clock()
        pg.key.set_repeat()

    def new(self):
        self.all_sprites = pg.sprite.Group()
        self.player = Player(self, 100,100)

    def run(self):
        self.playing = True
        while self.playing:
            self.clock.tick(60)
            self.events()
            self.update()
            self.draw()

    def quit(self):
        pg.quit()

    def update(self):
        self.all_sprites.update()

    def draw(self):
        self.screen.fill(GREY)
        for sprite in self.all_sprites:
            self.screen.blit(sprite.image, sprite.rect)         
        pg.display.flip()

    def events(self):
        for self.event in pg.event.get():
            if self.event.type == pg.QUIT:
                self.quit()
            if self.event.type == pg.KEYDOWN:
                if self.player.handle_keydown( event.key ==)


class Player(pg.K_LEFTsprite.Sprite):
        def __init__(self, game, x, y):
        self.player.pos[0]groups -= 1game.all_sprites
                    printpg.sprite.Sprite.__init__("This should only be printed once per keyself, press"self.groups)
        self.game = game
       elif self.event.keyimage === pg.K_RIGHT:Surface((32,32))
          self.image.fill(WHITE)
        self.rect = self.playerimage.pos[0]get_rect()
 += 1
      self.pos = [x, y]

    def handle_keydown( self, key ) :
  print("This should only be printed once perif key press")


class== Player(pg.sprite.Sprite)K_LEFT:
    def __init__(self, game, x, y):
        self.groupspos[0] -= game.all_sprites1
        pg.sprite.Sprite.__init__(self, self.groups)
   print("This should only be printed once self.gameper =key gamepress")
        self.imageelif =key == pg.Surface((32,32))K_RIGHT:
            self.image.fill(WHITE)
pos[0] += 1
      self.rect = self.image.get_rect()
    print("This should only be self.posprinted =once [x,per y]key press")

    def update(self):
        self.rect.centery = self.pos[1]             
        self.rect.centerx = self.pos[0]     


g = Game()
while True:
    g.new()
    g.run()

If you really want to handle key presses in Player that is fine too. Just add a handler func and pass in the event (or key) from Game.

It's easier to handle all the events in the same place, so you don't reuse it. You could move the player sprite in the game event loop like this:

import pygame_sdl2 as pg

# colors
WHITE = (255, 255, 255)
GREY = (100, 100, 100)

class Game:

    def __init__(self):
        pg.init()
        self.screen = pg.display.set_mode((640, 640))
        self.clock = pg.time.Clock()
        pg.key.set_repeat()

    def new(self):
        self.all_sprites = pg.sprite.Group()
        self.player = Player(self, 100,100)

    def run(self):
        self.playing = True
        while self.playing:
            self.clock.tick(60)
            self.events()
            self.update()
            self.draw()

    def quit(self):
        pg.quit()

    def update(self):
        self.all_sprites.update()

    def draw(self):
        self.screen.fill(GREY)
        for sprite in self.all_sprites:
            self.screen.blit(sprite.image, sprite.rect)         
        pg.display.flip()

    def events(self):
        for self.event in pg.event.get():
            if self.event.type == pg.QUIT:
                self.quit()
            if self.event.type == pg.KEYDOWN:
                if self.event.key == pg.K_LEFT:
                    self.player.pos[0] -= 1
                    print("This should only be printed once per key press")
                elif self.event.key == pg.K_RIGHT:
                    self.player.pos[0] += 1
                    print("This should only be printed once per key press")


class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = pg.Surface((32,32))
        self.image.fill(WHITE)
        self.rect = self.image.get_rect()
        self.pos = [x, y]

    def update(self):
        self.rect.centery = self.pos[1]             
        self.rect.centerx = self.pos[0]     


g = Game()
while True:
    g.new()
    g.run()

If you really want to handle key presses in Player that is fine too. Just add a handler func and pass in the event (or key) from Game.

Just iterate over the events as you retrieve them from the queue, and handle them right then and there, without keeping a reference to it.

You can use a secondary handler in Player class to do the actual work for keypresses if you want, as show below.

import pygame_sdl2 as pg

# colors
WHITE = (255, 255, 255)
GREY = (100, 100, 100)

class Game:

    def __init__(self):
        pg.init()
        self.screen = pg.display.set_mode((640, 640))
        self.clock = pg.time.Clock()
        pg.key.set_repeat()

    def new(self):
        self.all_sprites = pg.sprite.Group()
        self.player = Player(self, 100,100)

    def run(self):
        self.playing = True
        while self.playing:
            self.clock.tick(60)
            self.events()
            self.update()
            self.draw()

    def quit(self):
        pg.quit()

    def update(self):
        self.all_sprites.update()

    def draw(self):
        self.screen.fill(GREY)
        for sprite in self.all_sprites:
            self.screen.blit(sprite.image, sprite.rect)         
        pg.display.flip()

    def events(self):
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.quit()
            if event.type == pg.KEYDOWN:
                self.player.handle_keydown( event.key )


class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = pg.Surface((32,32))
        self.image.fill(WHITE)
        self.rect = self.image.get_rect()
        self.pos = [x, y]

    def handle_keydown( self, key ) :
        if key == pg.K_LEFT:
            self.pos[0] -= 1
            print("This should only be printed once per key press")
        elif key == pg.K_RIGHT:
            self.pos[0] += 1
            print("This should only be printed once per key press")

    def update(self):
        self.rect.centery = self.pos[1]             
        self.rect.centerx = self.pos[0]     


g = Game()
while True:
    g.new()
    g.run()
Source Link
Bram
  • 3.7k
  • 20
  • 26

I tried your code on Linux, using the pygame_sdl2 module.

The set_repeat() works fine, you just have an issue with your code. You keep seeing the same old event, because you keep a reference to it.

After running Game.events() func, the game.event will still point to the last event.

It's easier to handle all the events in the same place, so you don't reuse it. You could move the player sprite in the game event loop like this:

import pygame_sdl2 as pg

# colors
WHITE = (255, 255, 255)
GREY = (100, 100, 100)

class Game:

    def __init__(self):
        pg.init()
        self.screen = pg.display.set_mode((640, 640))
        self.clock = pg.time.Clock()
        pg.key.set_repeat()

    def new(self):
        self.all_sprites = pg.sprite.Group()
        self.player = Player(self, 100,100)

    def run(self):
        self.playing = True
        while self.playing:
            self.clock.tick(60)
            self.events()
            self.update()
            self.draw()

    def quit(self):
        pg.quit()

    def update(self):
        self.all_sprites.update()

    def draw(self):
        self.screen.fill(GREY)
        for sprite in self.all_sprites:
            self.screen.blit(sprite.image, sprite.rect)         
        pg.display.flip()

    def events(self):
        for self.event in pg.event.get():
            if self.event.type == pg.QUIT:
                self.quit()
            if self.event.type == pg.KEYDOWN:
                if self.event.key == pg.K_LEFT:
                    self.player.pos[0] -= 1
                    print("This should only be printed once per key press")
                elif self.event.key == pg.K_RIGHT:
                    self.player.pos[0] += 1
                    print("This should only be printed once per key press")


class Player(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self.groups = game.all_sprites
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = pg.Surface((32,32))
        self.image.fill(WHITE)
        self.rect = self.image.get_rect()
        self.pos = [x, y]

    def update(self):
        self.rect.centery = self.pos[1]             
        self.rect.centerx = self.pos[0]     


g = Game()
while True:
    g.new()
    g.run()

If you really want to handle key presses in Player that is fine too. Just add a handler func and pass in the event (or key) from Game.

Note that I get a crash when I close the window, so your code needs more work than this.