1

I'm trying to make a pause function I've tested this pause function separately and it seems to be working fine although there is nothing that it can do at the moment but it still shows. However, when I implement it in my game it doesn't work?

I've put it in different places before the while loop and in the while loop. When it's before the while loop the pause function will show first then mess up the game. When it's put in the while loop, it wont show at all even when 'p' is pressed.

What is the issue?

   import pygame
import os
import sys
pygame.init()
pygame.font.init()
WHITE = (255, 255, 255)
BLACK = (0, 0, 0, 0)

clock = pygame.time.Clock()
FPS = 60
DS = pygame.display.set_mode((900, 600))
sprite_image = pygame.Surface((50, 50), pygame.SRCALPHA)
pygame.draw.circle(sprite_image, (90, 100, 200), [25, 25], 25)
W, H = DS.get_size()
pause = True

st = pygame.font.SysFont("comicsans ms", 20)
lf = pygame.font.SysFont("comicsans ms", 120)


def paused():
    DS.fill((50, 50, 70))  # Fill the display surface.
    text_surf, text_rect = text_objects('Paused', (W/2, H/2), lf)
    DS.blit(text_surf, text_rect)
    # The buttons are dictionaries now.
    resume_button = button('Resume', 150, 450, 100, 50, WHITE, WHITE)
    quit_button = button('Quit', 350, 450, 100, 50, WHITE, WHITE)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()  # Should be pygame.quit not QUIT.
                sys.exit()  # Better use sys.exit() instead of quit().
            elif event.type == pygame.MOUSEMOTION:
                # Switch the active surface of the buttons
                # if we're hovering over them.
                for btn in (resume_button, quit_button):
                    if btn['rect'].collidepoint(event.pos):
                        btn['active_surface'] = btn['surface_hover']
                    else:
                        btn['active_surface'] = btn['surface']
            elif event.type == pygame.MOUSEBUTTONDOWN:
                # Check if the buttons were clicked.
                if resume_button['rect'].collidepoint(event.pos):
                    return  # Return to the main loop.
                elif quit_button['rect'].collidepoint(event.pos):
                    pygame.quit()
                    sys.exit()


def text_objects(text, pos, font):
    text_surface = font.render(text, True, BLACK)
    return text_surface, text_surface.get_rect(center=pos)





def display_message(text):
    lf = pygame.font.SysFont("comicsans", 120)
    TextSurf, TextRect = text_objects(text, lf)
    TextRect.center = ((W / 2)), ((H / 2))
    DS.blit(TextSurf, TextRect)
    pygame.display.update()


def button(msg, x, y, w, h, inactive_color, active_color):
    """Create a button dictionary with the images and a rect."""
    text_surf, text_rect = text_objects(msg, (w/2, h/2), st)
    # Create the normal and hover surfaces and blit the text onto them.
    surface = pygame.Surface((w, h))
    surface.fill(inactive_color)
    surface.blit(text_surf, text_rect)
    surface_hover = pygame.Surface((w, h))
    surface_hover.fill(active_color)
    surface_hover.blit(text_surf, text_rect)
    return {'active_surface': surface,
            'surface': surface,
            'surface_hover': surface_hover,
            'rect': pygame.Rect(x, y, w, h),
            }

class Platform(pygame.sprite.Sprite):
    def __init__(self, x, y, w, h):
        super(Platform, self).__init__()
        self.image = pygame.Surface((w, h))
        self.image.fill((90, 90, 120))
        self.rect = self.image.get_rect(topleft=(x, y))


class Sprite(pygame.sprite.Sprite):
    def __init__(self, pos):
        super(Sprite, self).__init__()
        self.image = sprite_image
        self.rect = self.image.get_rect()
        self.rect.center = pos
        self._vx = 0
        self._vy = 0
        self._spritex = pos[0]
        self._spritey = pos[1]
        self.level = None
        self._gravity = .9

    def update(self):
        # Adjust the x-position.
        self._spritex += self._vx
        self.rect.centerx = self._spritex  # And update the rect.

        block_hit_list = pygame.sprite.spritecollide(self, self.level, False)
        for block in block_hit_list:
            if self._vx > 0:
                self.rect.right = block.rect.left
            elif self._vx < 0:
                # Otherwise if we are moving left, do the opposite.
                 self.rect.left = block.rect.right
            self._spritex = self.rect.centerx  # Update the position.

        # Adjust the y-position.
        self._vy += self._gravity  # Accelerate downwards.
        self._spritey += self._vy
        self.rect.centery = self._spritey  # And update the rect.

        # Check and see if we hit anything
        if block_hit_list == pygame.sprite.spritecollide(self, self.level, False):
         for block in block_hit_list:
            # Reset our position based on the top/bottom of the object.
            if self._vy > 0:
                self.rect.bottom = block.rect.top
            elif self._vy < 0:
                self.rect.top = block.rect.bottom
            self._spritey = self.rect.centery  # Update the position.
            # Stop our vertical movement
            self._vy = 0


    def jump(self):
        self.rect.y += 3
        platform_hit_list = pygame.sprite.spritecollide(self, self.level, False)
        self.rect.y -= 3

        # If it is ok to jump, set our speed upwards
        if len(platform_hit_list) > 0 or self.rect.bottom >= H:
            self._vy = -17

    def go_left(self):
        # Called when the user hits the left arrow.
        self._vx = -3

    def go_right(self):
        #Called when the user hits the right arrow.
        self._vx = 3

    def stop(self):
        # Called when the user lets off the keyboard.
        self._vx = 0







sprite = Sprite([60, 60])

active_sprite_list = pygame.sprite.Group(sprite)
sprite.level = pygame.sprite.Group()

# A list with rect style tuples (x, y, width, height).
rects = [
    (20, 20, 150, 20), (120, 200, 200, 20), (400, 440, 300, 20),
    (40, 100, 200, 20), (320, 300, 150, 20), (520, 550, 300, 20),
    (600, 100, 150, 20), (300, 200, 200, 20), (290, 440, 300, 20),
    (40, 100, 200, 20), (320, 300, 150, 20), (95, 550, 300, 20),
    (250,300,150,20), (350,100,150,20), (450,50,270,20), (700,185,70,20),
    (650,350,350,20)
]

# You can unpack the rect tuples directly in the head of the for loop.
for x, y, width, height in rects:
     # Create a new platform instance and pass the coords, width and height.
     platform = Platform(x, y, width, height)
     # Add the new platform instance to the sprite groups.
     sprite.level.add(platform)
     active_sprite_list.add(platform)
     active_sprite_list.add(sprite.level)

done = False
while not done:
    def paused():
        DS.fill((50, 50, 70))  # Fill the display surface.
        text_surf, text_rect = text_objects('Paused', (W / 2, H / 2), lf)
        DS.blit(text_surf, text_rect)
        # The buttons are dictionaries now.
        resume_button = button('Resume', 150, 450, 100, 50, WHITE, WHITE)
        quit_button = button('Quit', 350, 450, 100, 50, WHITE, WHITE)

        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()  # Should be pygame.quit not QUIT.
                    sys.exit()  # Better use sys.exit() instead of quit().
                elif event.type == pygame.MOUSEMOTION:
                    # Switch the active surface of the buttons
                    # if we're hovering over them.
                    for btn in (resume_button, quit_button):
                        if btn['rect'].collidepoint(event.pos):
                            btn['active_surface'] = btn['surface_hover']
                        else:
                            btn['active_surface'] = btn['surface']
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    # Check if the buttons were clicked.
                    if resume_button['rect'].collidepoint(event.pos):
                        return  # Return to the main loop.
                    elif quit_button['rect'].collidepoint(event.pos):
                        pygame.quit()
                        sys.exit()



    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_p:
             pause = True
             paused()

        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                sprite.go_left()
                pause = False
            if event.key == pygame.K_RIGHT:
                sprite.go_right()
                pause = False
            if event.key == pygame.K_UP:
                sprite.jump()
                pause = False
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT and sprite._vx < 0:
                sprite.stop()
                pause = False
            if event.key == pygame.K_RIGHT and sprite._vx > 0:
                sprite.stop()
    # If the player gets near the right side, shift the world left (-x)
    if sprite.rect.right > W:
        sprite.rect.right = W
        # If the player gets near the left side, shift the world right (+x)
    if sprite.rect.left < 0:
        sprite.rect.left = 0





    active_sprite_list.update()
    DS.fill(WHITE)

    # Blit the sprite's image at the sprite's rect.topleft position.
    active_sprite_list.draw(DS)

    pygame.display.flip()
    clock.tick(FPS)

pygame.quit()
  • 2
    Where's your `Paused` function? One problem that I can already see is that you check `if event.type == pygame.K_p:`, but you have to use `if event.type == pygame.KEYDOWN:` first and in that clause `if event.key == pygame.K_p:`. – skrx Jan 14 '18 at 14:46
  • 2
    Also, don't define the `text_objects`, `display_message` and `button` functions in the while loop. Do that above the loop. – skrx Jan 14 '18 at 14:53
  • ive done what you said, however the pause menu and the actual game is now overlaping eachother and i cant move the sprite? –  Jan 14 '18 at 17:15
  • 1
    You have to fill the display surface when you enter the `Paused` function: `DS.fill((50, 50, 50))`. Then you need to add code to detect collisions between the mouse and the buttons (use the `collidepoint` method of the rects) and if the user presses resume, you can just use the `return` statement to go back to the main game loop. I recommend implementing the button in a different way. [Here's an answer](https://stackoverflow.com/a/47664205/6220679) with several solutions. – skrx Jan 14 '18 at 18:43
  • 1
    Just a small tip, next time you have a pygame question choose the python tag as well. –  Jan 14 '18 at 22:30

1 Answers1

0

Take a look at this example. I use dictionaries for the buttons which consist of the images, the currently active image and a rect which is used for the collision detection and as the position. If the user clicks the resume button, I just return to the main game loop.

import sys
import pygame


pygame.init()
WHITE = (255, 255, 255)
GRAY = pygame.Color("gray30")
BLACK = (0, 0, 0, 0)

clock = pygame.time.Clock()
FPS = 60
DS = pygame.display.set_mode((900, 600))
W, H = DS.get_size()
# Define the fonts once when the program starts.
st = pygame.font.SysFont("comicsans ms", 20)
lf = pygame.font.SysFont("comicsans ms", 120)


def paused():
    DS.fill((50, 50, 70))  # Fill the display surface.
    text_surf, text_rect = text_objects('Paused', (W/2, H/2), lf)
    DS.blit(text_surf, text_rect)
    # The buttons are dictionaries now.
    resume_button = button('Resume', 150, 450, 100, 50, WHITE, GRAY)
    quit_button = button('Quit', 350, 450, 100, 50, WHITE, GRAY)

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()  # Should be pygame.quit not QUIT.
                sys.exit()  # Better use sys.exit() instead of quit().
            elif event.type == pygame.MOUSEMOTION:
                # Switch the active surface of the buttons
                # if we're hovering over them.
                for btn in (resume_button, quit_button):
                    if btn['rect'].collidepoint(event.pos):
                        btn['active_surface'] = btn['surface_hover']
                    else:
                        btn['active_surface'] = btn['surface']
            elif event.type == pygame.MOUSEBUTTONDOWN:
                # Check if the buttons were clicked.
                if resume_button['rect'].collidepoint(event.pos):
                    return  # Return to the main loop.
                elif quit_button['rect'].collidepoint(event.pos):
                    pygame.quit()
                    sys.exit()

        # Draw the active surfaces at the rects of the buttons.
        DS.blit(resume_button['active_surface'], resume_button['rect'])
        DS.blit(quit_button['active_surface'], quit_button['rect'])
        pygame.display.update()
        clock.tick(15)


def text_objects(text, pos, font):
    text_surface = font.render(text, True, BLACK)
    return text_surface, text_surface.get_rect(center=pos)


def button(msg, x, y, w, h, inactive_color, active_color):
    """Create a button dictionary with the images and a rect."""
    text_surf, text_rect = text_objects(msg, (w/2, h/2), st)
    # Create the normal and hover surfaces and blit the text onto them.
    surface = pygame.Surface((w, h))
    surface.fill(inactive_color)
    surface.blit(text_surf, text_rect)
    surface_hover = pygame.Surface((w, h))
    surface_hover.fill(active_color)
    surface_hover.blit(text_surf, text_rect)
    return {'active_surface': surface,
            'surface': surface,
            'surface_hover': surface_hover,
            'rect': pygame.Rect(x, y, w, h),
            }


done = False
while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_p:
                paused()

    DS.fill((50, 50, 50))
    pygame.draw.circle(DS, (0, 90, 190), (100, 100), 50)

    pygame.display.flip()
    clock.tick(FPS)

pygame.quit()
skrx
  • 19,980
  • 5
  • 34
  • 48
  • When i put this into my actual code it comes up with the error 'line 98, in paused text_surf, text_rect = text_objects('Paused', (W/2, H/2), lf) TypeError: text_objects() takes 2 positional arguments but 3 were given ' –  Jan 14 '18 at 23:11
  • I've changed the `text_objects` function, so that it takes the position now as well. – skrx Jan 15 '18 at 07:43
  • it doesnt work at all and my game doesnt move anymore what could be the possible problem to this? I've tried putting it in different positions and it doesnt work at all –  Jan 15 '18 at 18:21
  • I can't see what you're doing, so it's very difficult for me to figure out what the problem is. You could post your most recent code, but I don't have time to answer atm. – skrx Jan 15 '18 at 22:41
  • its not possible for me to cut it down to minimal example though? is that okay –  Jan 16 '18 at 10:12
  • The mistake is that you have two `if event.type == pygame.KEYDOWN:` checks in your event loop and the second `elif` can never be executed. Just remove the `elif event.type == pygame.KEYDOWN:` line. – skrx Jan 17 '18 at 12:50
  • Also, the `paused` function should not be defined in the main while loop and you have to blit the buttons (see my example) and call `clock.tick(FPS` in the `paused` function as well. There's still a problem with the colors of the buttons and the collision detection and the movement of the circle don't work correctly. – skrx Jan 17 '18 at 12:55
  • mine isnt pausing at all would making it into a class be more easier –  Jan 17 '18 at 16:51
  • i get the error ' DS.blit(resume_button,quit_button) TypeError: argument 1 must be pygame.Surface, not dict ' –  Jan 17 '18 at 17:02
  • That should be `DS.blit(resume_button['active_surface'], resume_button['rect'])` and `DS.blit(quit_button['active_surface'], quit_button['rect'])`. – skrx Jan 18 '18 at 14:15