简体   繁体   中英

OOP game in pygame, keyboard events and controling

I've been making a game, kind of 'arkanoid' What I have is a ball and a paddle.

This is first game I am trying to make using OOP so I really appreciate all your comments. I created an Objectmanager class for managing all the objects in the game, and now I don't know where to put the keyboard control and player paddle movement.

  1. Wrote keyevent method for Objectmanager and passed event.key to it, then manipulated the paddle - didn't work very good.
  2. The same method but passing pygame.key.getpressed() and checking the buttons in Objectmanager

Both ways make the paddle move in a bad way or not stopping when I want it to stop.

I think the 1. was better, but i couldn't get it perfect, so I am asking You for some tips. I would make It easily in one loop, but I really want to learn OOP, and I don't know if i should put it or Objectmanager or in main loop. I was also thinking of putting the Paddle into the main loop, not into the Objectmanager. What's Your opinion? Thank you all.

import random, pygame, sys, math, itertools
from pygame.locals import *
#            R    G    B
BLACK    = (  0,   0,   0)
GRAY     = (100, 100, 100)
NAVYBLUE = ( 60,  60, 100)
WHITE    = (255, 255, 255)
RED      = (255,   0,   0)
GREEN    = (  0, 255,   0)
BLUE     = (  0,   0, 255)
YELLOW   = (255, 255,   0)
ORANGE   = (255, 128,   0)
PURPLE   = (255,   0, 255)
CYAN     = (  0, 255, 255)
BALLSIZE = 15
BALLSPEED = 5
FPS = 60
PADDLEWIDTH = 80
PADDLEHEIGHT = 20

class Ball:
    def __init__(self):
        self.middle = [250,250]
        self.angle = math.radians(random.randint(1, 360))
        self.speed = BALLSPEED
    def update(self):
        xspeed = self.speed * math.sin(self.angle)
        yspeed = self.speed * math.cos(self.angle)
        deltax = round(xspeed)
        deltay = round(yspeed)
        self.middle[0] += deltax
        if self.middle[0] <= 0 or self.middle[0] >= 500:
            self.middle[0] -= 2*deltax
            self.angle = 2*math.pi - self.angle
        self.middle[1] += deltay
        if self.middle[1] <= 0 or self.middle[1] >= 500:
            self.middle[1] -= 2*deltay
            self.angle = math.pi - self.angle
    def draw(self,surface):
        pygame.draw.circle(surface,WHITE,self.middle,BALLSIZE)

class Paddle:
    def __init__(self):
        self.middle = [250,480]
        self.deltax = 0
    def update(self):
        self.middle[0] += self.deltax
    def rect(self):
        return pygame.Rect(self.middle[0]-(PADDLEWIDTH/2),self.middle[1]-(PADDLEHEIGHT/2),PADDLEWIDTH,PADDLEHEIGHT)
    def moveleft(self):
        self.deltax -= 10
    def moveright(self):
        self.deltax += 10
    def stop(self):
        self.deltax = 0
    def draw(self,surface):
        pygame.draw.rect(surface,WHITE,self.rect())
        pygame.draw.rect(surface, GRAY, self.rect(),4)

class ObjectManager:
    def __init__(self):
        self.balls = [Ball(),]
        self.paddle = Paddle()
    def add(self,object):
        if type(object) == Ball:
            self.balls.append(object)

    def update(self):
        for object in itertools.chain(self.balls,(self.paddle,)):
            object.update()
    def keyevent(self,keys):
        if keys[K_RIGHT]:
            self.paddle.moveright()
        elif keys[K_LEFT]:
            self.paddle.moveleft()
        else:
            self.paddle.stop()
    def draw(self,surface):
        for object in itertools.chain(self.balls,(self.paddle,)):
            object.draw(surface)

class Game:
    def __init__(self):
        pygame.init()
        self.FPS = FPS
        self.fpsClock = pygame.time.Clock()
        DISPLAYSURF = pygame.display.set_mode((500,500),0,32)
        pygame.display.set_caption('arkanoid')
        manager = ObjectManager()

        while True:
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    sys.exit()
                elif event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        pygame.quit()
                        sys.exit()

            manager.keyevent(pygame.key.get_pressed())
            manager.update()

            DISPLAYSURF.fill(BLACK)
            manager.draw(DISPLAYSURF)
            pygame.display.update()
            self.fpsClock.tick(self.FPS)
game = Game()

Objectmanager:

def keydown(self,key):
    if key == K_RIGHT:
        self.paddle.moveright()
    elif key == K_LEFT:
        self.paddle.moveleft()
def keyup(self):
    self.paddle.stop()

main loop:

    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            if event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
            else:
                manager.keydown(event.key)
        else:
            manager.keyup()

what do You think? this works fine, I just got to this when I published my problem....

Your ObjectManager should be responsible for only your custom GameObject , which could be an abstract class or interface which defines move(), update() etcetera. (Your ball and paddle could inherit/implement from this).

So from my perspective I think you should process the events in your Main loop. (Creating an EventManager is also an option.) You should ask yourself what is this class responsible for? And keep them as simple as possible to seperate concerns.

Also I would put the colors into a list of dicts eg:

['black':{'R':0,'G':0,'B':0}]

So that you can change color at runtime more easily, for example selecting a random color.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM