Pygame seems to “avoid” loop

2019-07-17 08:11发布

I am just getting started with Pygame and I am currently trying out some basic movement functions.

I ran into a problem when trying to code my movement conditions into my object class rather than in the game loop.

My first attempt which works is as follow:

classes.py:

import pygame, sys
from pygame.locals import *
class GameObject:
    def __init__(self, image, height, speed):
        self.speed = speed
        self.image = image
        self.pos = image.get_rect().move(0, height) #initial placement

    def move_south(self):
        self.pos = self.pos.move(0, self.speed)
        if self.pos.right > 600:
            self.pos.left = 0

    def move_east(self):
        self.pos = self.pos.move(self.speed , 0)
        if self.pos.right > 600:
            self.pos.left = 0

main.py:

import pygame, sys
from pygame.locals import *
from classes import *

screen = pygame.display.set_mode((640, 480))
#Importing Chars
player = pygame.image.load('green_hunter_small.png').convert()
#player.set_alpha(100) #makes whole player transparent
player.set_colorkey((0,0,0)) #sets background colour to transparent

ennemi =  pygame.image.load('red_hunter_small.png').convert()
ennemi.set_colorkey((0,0,0))

background = pygame.image.load('grass_map_640x640.png').convert()
screen.blit(background, (0, 0))
objects = []
objects.append(GameObject(player, 80, 0))
for x in range(2):      #create 2 objects
    o = GameObject(ennemi, x*40, 0)
    objects.append(o)
while True:
    for event in pygame.event.get(): #setting up quit
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == KEYDOWN:
            if event.key == K_DOWN:
                for o in objects:
                    screen.blit(background, o.pos, o.pos) #erases players by bliting bg 
                for o in objects:
                    o.speed = 4
                    o.move_south() #moves player
                    o.speed = 0
                    screen.blit(o.image, o.pos) #draws player
            if event.key == K_RIGHT:
                for o in objects:
                    screen.blit(background, o.pos, o.pos) #erases players by bliting bg 
                for o in objects:
                    o.speed = 4
                    o.move_east() #moves player
                    o.speed = 0
                    screen.blit(o.image, o.pos) #draws player                    
    pygame.display.update()
    pygame.time.delay(50)

My second attempt which didn't work was to dp:

classes.py:

import pygame, sys
from pygame.locals import *

class GameObject:
    def __init__(self, image, height, speed):
        self.speed = speed
        self.image = image
        self.pos = image.get_rect().move(0, height) #initial placement

    def move_south(self):
        self.pos = self.pos.move(0, self.speed)
        if self.pos.right > 600:
            self.pos.left = 0

    def move_east(self):
        self.pos = self.pos.move(self.speed , 0)
        if self.pos.right > 600:
            self.pos.left = 0

    def move(self):
        for event in pygame.event.get():
            if event.type == KEYDOWN:
                if event.key == K_DOWN:
                    screen.blit(background, self.pos, self.pos) #erases players by bliting bg 
                    self.speed = 4
                    self.move_south() #moves player
                    self.speed = 0
                if event.key == K_RIGHT:
                    screen.blit(background, self.pos, self.pos) #erases players by bliting bg 
                    self.speed = 4
                    self.move_east() #moves player
                    self.speed = 0
                screen.blit(self.image, self.pos) #draws player

main.py:

import pygame, sys
from pygame.locals import *
from classes import *

screen = pygame.display.set_mode((640, 480))
#Importing Chars
player = pygame.image.load('green_hunter_small.png').convert()
#player.set_alpha(100) #makes whole player transparent
player.set_colorkey((0,0,0)) #sets background colour to transparent

ennemi =  pygame.image.load('red_hunter_small.png').convert()
ennemi.set_colorkey((0,0,0))

background = pygame.image.load('grass_map_640x640.png').convert()
screen.blit(background, (0, 0))
objects = []
objects.append(GameObject(player, 80, 0))
for x in range(2):      #create 2 objects
    o = GameObject(ennemi, x*40, 0)
    objects.append(o)
while True:
    for event in pygame.event.get(): #setting up quit
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
    for o in objects:
        o.move()        
    pygame.display.update()
    pygame.time.delay(50)

So it seems that the code struggles to go and check the event loop from the instance. The reason I wanted to code the movement as a method rather than straight in main was to save space and make it easier to add characters later on.

1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-07-17 08:53

Your code has a race condition (to use the term really loosely).

The reason that your characters are not moving is that the first pygame.event.get call (when you are checking for a QUIT event) consumes all the KEYDOWN events that are on the queue. Then (unless you manage to press a key while the first loop is running), there are no KEYDOWN events in the queue when the first GameObject checks for events. Diddo for all other GameObjects.

You need to handler all pygame events in one loop. Example code:

class GameObject():
    #rest of class
    def move(self,event):
        if event.key == K_DOWN:
             screen.blit(background, self.pos, self.pos) #erases players by bliting bg 
             self.speed = 4
             self.move_south() #moves player
             self.speed = 0
        #repeat for all other directions
        screen.blit(self.image, self.pos) #draws player
#initialize objects
while True:
    for event in pygame.event.get():
         if event.type == QUIT: #handle quit event
         elif event.type == KEYDOWN:
            for o in objects:
                o.move(event)
    #do non-eventhandling tasks.
查看更多
登录 后发表回答