Puszek
Puszek

Reputation: 17

Pygame displays black window

I'm doing tutorial for platform game but my Pygame window displays a black screen.

I don't know how to solve this.

I tried closing and opening Visual Studio Code again but nothing happens.

import pygame

SCREEN_SIZE = (700,500)
DARK_GREY = (50,50,50)
OGURKOWY = (21,179, 58)

pygame.init()

screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.set_caption("Platformówka")
player_image = pygame.image.load("ogurek\doggo.png")
player_x = 300
platforms = [
  pygame.Rect(100,300,400,50),
  pygame.Rect(100,250 ,50,50),
  pygame.Rect(450,250,50,50),
  pygame.Rect(450,250,100,50)
]

running = True

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    keys = pygame.key.get_pressed()
    if keys[pygame.K_a]:
        player_x -= 2
    if keys[pygame.K_a]:
        player_x += 2   
    #tło
    screen.fill(DARK_GREY)
    #platformy

for p in platforms: 
    pygame.draw.rect(screen, (OGURKOWY), p)
    #gracz
    screen.blit(player_image, (player_x,100))
    # 
    pygame.display.flip()

pygame.quit()

Upvotes: 2

Views: 227

Answers (2)

hc_dev
hc_dev

Reputation: 9377

How to fix this apparent indentation issue was commented by Ari Cooper-Davis and answered by Rabbid76.

My answer aims to avoid such issues by design (keeping loops short and segregating nested constructs into methods).


Advice to avoid such indentation typos and improve readability of your code:

  • keep the game-loop (your while running:) short
  • extract code-blocks into functions/methods
  • put empty-lines (vertical spacing) between major code-blocks like for/if/functions, etc.

Extract methods

This recipe follows Single Responsibility Principle (SRP) and structures your code like your comments did. Moreover it makes the code more expressive, because method-calls will document same as comments to the reader.

def handle_exit_events():
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False


def handle_key_events():
    keys = pygame.key.get_pressed()
    if keys[pygame.K_a]:
        player_x -= 2
    if keys[pygame.K_a]:
        player_x += 2   


def draw_background():
    # tło
    screen.fill(DARK_GREY)


def draw_platforms():
    # platformy
    for p in platforms: 
        pygame.draw.rect(screen, (OGURKOWY), p)


def draw_player():
    # gracz
    screen.blit(player_image, (player_x,100))


def update_display():
    pygame.display.flip()       

Note the 2 blank lines between each method definition.

Keep loops short

Now that we declared the methods (before), we can use them to shorten the loop:

# methods declared (from above)

# inits (screen/game-objects/color definitions) omitted to focus on game-loop

running = True
while running:
    handle_exit_events()
    handle_key_events()
    draw_background()  # currently static, could move above loop 
    draw_platforms()  # currently static, could move above loop
    draw_player()  # player move triggered by key-press only
    update_display()

pygame.quit()

See how your original comments inside the game-loop (# platformy, # tło and # gracz) were transformed to method-calls. Thus your code documents itself (making these comments obsolete).

What depends on change inside game-loop ?

Now we can think and recognize dependencies inside the loop. The game-loop is for interactive parts like reacting to events or updating the screen.

Draw static objects once ahead

So the handle_x_events methods fit well inside the loop. But some static scenery like background and platforms are fixed objects in your game. They can be drawn once before entering the game-loop. Because they don't change with any of the events (like quit or key-pressed).

# methods declared (from above)

# inits (screen/game-objects/color definitions) omitted to focus on game-loop
draw_background()
draw_platforms()

running = True
while running:    

Next is more questionable and depends on your design-approach.

Draw player when event triggers change (position or appearence)

draw_player() is needed once before the loop because when the game starts, the player is placed into the world. Then the player uses key-presses to change its position (see handle_key_events()) which will trigger the player-image to be re-positioned (horizontally only, player_x) and drawn on the screen.

You could express that dependency in code:

player_y = 100  # initial vertical position (fixed at the moment)
player_x = 300
player_x_speed = 2  # pixels delta per horizontal movement

def move_player_forward():
    player_x += player_x_speed
    screen.blit(player_image, (player_x, player_y))


def move_player_backward():
    player_x -= player_x_speed
    screen.blit(player_image, (player_x, player_y))


def handle_key_events():
    keys = pygame.key.get_pressed()
    if keys[pygame.K_a]:
        move_player_backward()
    if keys[pygame.K_a]:
        move_player_forward()

# remaining code

while running:
    handle_exit_events()
    handle_key_events()
    update_display()

pygame.quit()

See how the horizontal movement is expressed in code. The player_x modification was internalized into the movement methods.

Usually you would work with Player class and objects or at least player-coordinates, for example defined as tuple, which has some benefits:

player_position = (300, 100)  # pixel coordinates of players initial position`
player_x_speed = 2  # pixels delta per horizontal movement
player_jump_height = 10  # pixels to jump vertically, e.g. on a platform

# walk forward
player_position[0] += player_x_speed

# jump forward
player_position = (player_position[0] + player_x_speed, player_position[1] + player_jump_height)

# directly drawn
screen.blit(player_image, player_position) 

Upvotes: 0

Rabbid76
Rabbid76

Reputation: 210889

It is a matter of Indentation. The for-loop that draws the platforms (for p in platforms:) must be *in the application loop instead of after the application loop:

while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    keys = pygame.key.get_pressed()
    if keys[pygame.K_a]:
        player_x -= 2
    if keys[pygame.K_a]:
        player_x += 2   
    #tło
    screen.fill(DARK_GREY)
    #platformy

# INDENTATION
#-->|
    for p in platforms: 
        pygame.draw.rect(screen, (OGURKOWY), p)
        
    #gracz
    screen.blit(player_image, (player_x,100))
    # 
    pygame.display.flip()

Upvotes: 1

Related Questions