Help with a simple game

0

Well, I'm trying to make a "ball" follow the playing rectangle, however it does not seem to be happening as the "ball" kind of blurs the screen when I move the player. I already tried to solve the problem and found nothing.

Previously I had the same problem just to draw a rectangle that moves and the problem was that I was using window.fill (color) after drawing the rectangle. This time it is not the case, even changing the place the function does nothing.

import pygame

pygame.init()

isRunning = True

WIDTH = 800
HEIGHT = 600

FPS = 60

clock = pygame.time.Clock()

window = pygame.display.set_mode((WIDTH, HEIGHT))

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.Surface((60, 30))
        self.image.fill((200, 255, 200))
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT - 30

    def update(self):
        self.speedx = 0

        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_a]:
            self.speedx = -5

        if keystate[pygame.K_d]:
            self.speedx = 5

        self.rect.x += self.speedx

        if self.rect.right + self.speedx > WIDTH:
            self.rect.right = WIDTH

        if self.rect.left + self.speedx < 0:
            self.rect.left = 0

        ball = Ball(self.rect.centerx, self.rect.top)
        for i in all_sprites:
            print(i)
        all_sprites.add(ball)

    def shoot(self):
        ball = Ball(self.rect.centerx, self.rect.top)
        all_sprites.add(ball)
        balls.add(ball)

class Ball(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((10, 10))
        self.image.fill((100, 150, 200))
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.speedy = -3

    def update(self):
        pass
        #self.rect.y += self.speedy

all_sprites = pygame.sprite.Group()
balls = pygame.sprite.Group()
player = Player()
all_sprites.add(player)

while isRunning:

    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            isRunning = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                player.shoot()

    window.fill((0, 0, 30))

    all_sprites.update()

    all_sprites.draw(window)

    pygame.display.flip()

pygame.quit()
quit()
    
asked by anonymous 27.11.2016 / 20:31

1 answer

1

The main problem with your code is that you create a new Ball object with each new game frame . In addition to causing the unwanted effect, you are consuming absurdly the memory of your game. The correct thing is to create this object only with each call of the shoot method of your player class, and ensure that the ball is eliminated as it exits the screen boundaries - or collide with something else if it is a bullet ( " bullet ") and not a ball (" ball "). :)

The other problem (what motivated the question) is that you do not move the ball. Since you are using an object-oriented approach, this move code must be performed in the ball class itself. Simply make the center of the ball equal to the center of the player. Since your player is in a global variable, this is trivial to do. But the ideal was to add the player to an attribute of the ball class (in the constructor, or in an additional method of type setParent ).

Here is a version of the code with these fixes:

import pygame
import sys

pygame.init()

isRunning = True

WIDTH = 800
HEIGHT = 600

FPS = 60

clock = pygame.time.Clock()

window = pygame.display.set_mode((WIDTH, HEIGHT))

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.Surface((60, 30))
        self.image.fill((200, 255, 200))
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT - 30

        self.balls = []

    def update(self):
        self.speedx = 0

        keystate = pygame.key.get_pressed()
        if keystate[pygame.K_a]:
            self.speedx = -5

        if keystate[pygame.K_d]:
            self.speedx = 5

        self.rect.x += self.speedx

        if self.rect.right + self.speedx > WIDTH:
            self.rect.right = WIDTH

        if self.rect.left + self.speedx < 0:
            self.rect.left = 0

        #ball = Ball(self.rect.centerx, self.rect.top)
        #for i in all_sprites:
        #    print(i)
        #all_sprites.add(ball)

    def shoot(self):
        ball = Ball(self.rect.centerx, self.rect.top)
        all_sprites.add(ball)

class Ball(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface((10, 10))
        self.image.fill((100, 150, 200))
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.speedy = -3

        self.player = None

    def update(self):
        # Move a bola para cima, na velocidade configurada
        self.rect.y += self.speedy

        # Move a bola para a posicao central (no eixo X) do player
        self.rect.centerx = player.rect.centerx

        # Verifica se a bola ja saiu da tela
        if self.rect.centery <= 0:
            all_sprites.remove(self)


all_sprites = pygame.sprite.Group()
balls = pygame.sprite.Group()
player = Player()
all_sprites.add(player)

while isRunning:

    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            isRunning = False

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                player.shoot()

    window.fill((0, 0, 30))

    all_sprites.update()
    sys.stdout.write('\rTotal de sprites em jogo: {:5d}'.format(len(all_sprites)))

    all_sprites.draw(window)

    pygame.display.flip()

pygame.quit()
quit()

And the result of the "game" running:

PS:NoticethatIprintedthein-game"sprites" count using the \r in the string and the sys.stdout.write only to always print in the same position (and not print line behind the other, as your code did before). This count ensures that in this version of the code you are not getting any "memory leak" (with missing sprites ).

    
28.11.2016 / 23:56