Help with a simple game

Asked

Viewed 728 times

1

Well, I’m trying to make a "ball" follow the rectangle of the game, but it doesn’t seem to be happening because the "ball" kind of blurs the screen when I move the player. I already looked for the solution of the problem and I found nothing.

Previously I had the same problem only only to draw a rectangle that moves and the problem was that I was using window.Fill(color) after drawing the rectangle. This time is not the case, even changing location the function does not happen anything.

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()

1 answer

1


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

The other problem (which prompted the question) is that you don’t move the ball. As you are using an object-oriented approach, this moving code should be performed in the ball class itself. Simply make the center of the ball equal to the center of the player. As 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 builder, or in an additional method of type setParent).

Here’s 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" working:

inserir a descrição da imagem aqui

P.S.: Notice that I printed the "count" of sprites at stake using the \r in the string and the sys.stdout.write just for him to print always in the same position (and not to print one line after the other, as his code did before). This count ensures that in this version of the code you are not getting any "memory leakage" (with sprites lost not deleted).

  • So thanks for the answer, but that’s not exactly what I wanted in the end result. I asked the same question in Stack Overflow gringo and there explained to me that I was creating the instance and adding several times in the group and such, because then I was confusing the logic of the function " pygame.draw.rect(Surface, Color, (x, y, w, h))", which can be used in looping and will still delete itself, but with the group this has to be done manually (by code). Again, thank you for the time you took to explain it to me. I’ll leave the program link of the other Stack Overflow below

  • http://stackoverflow.com/questions/40834370/pygame-logic-issue/40838269?noredirect=1#comment68924361_40838269 .

  • A, and one more thing, my game goal is not to make a shooter but a Breakout or Brick Breaker, I had implemented this code "Shoot" just for testing.

  • For nothing. But, anyway, as you noticed, it’s hard to know what you need if you don’t explain it properly right? And, yes, I was led to believe that it wasn’t a ball because of the method shoot. :) Good luck!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.