Menu
CoddyTech

Un límite mínimo para el hueco

Parte de la sección Reglas del juego del Journey de Pygame de Coddy. Lección 16 de 29.

Las rocas caen más rápido, pero siguen apareciendo cada 800 ms. Las rocas que aparecen con más frecuencia también hacen que el juego sea más difícil. Empieza con un intervalo de un segundo y redúcelo con el tiempo:

interval = 1000 - seconds * 60

Después de 10 segundos, eso equivale a 400 ms; después de 17 segundos, es menos de 0, y un temporizador con un intervalo de 0 o menos se detiene. El juego necesita un límite inferior: un intervalo mínimo por debajo del cual nunca baja. max devuelve el mayor de sus números, así que nunca deja que el intervalo baje del primero:

interval = max(400, 1000 - seconds * 60)

Un temporizador conserva el intervalo con el que se inició. Para cambiarlo, inícialo de nuevo: cada vez que cae una roca, calcula el nuevo intervalo y llama a set_timer con él. La siguiente roca aparece después de ese intervalo.

if event.type == SPAWN and state == "play":
    rocks.append(...)
    seconds = (pygame.time.get_ticks() - start_time) // 1000
    interval = max(400, 1000 - seconds * 60)
    pygame.time.set_timer(SPAWN, interval)
challenge icon

Desafío

Intermedio
  1. En reset(), inicia el temporizador SPAWN en 1000 ms.
  2. Cada vez que caiga una roca, establece interval = max(400, 1000 - seconds * 60) e inicia de nuevo el temporizador SPAWN con ese valor.

Pruébalo tú mismo

import random
import pygame

pygame.init()
screen = pygame.display.set_mode((480, 360))
pygame.display.set_caption("Meteor Dodge")
clock = pygame.time.Clock()
heart = pygame.image.load("assets/images/heart.png").convert_alpha()
heart_empty = pygame.image.load("assets/images/heart_empty.png").convert_alpha()
font = pygame.font.Font("assets/fonts/pixel.ttf", 24)
big_font = pygame.font.Font("assets/fonts/pixel.ttf", 48)
WHITE = (240, 240, 240)
PLATE = (60, 60, 90)
POINT = pygame.USEREVENT + 1
SPAWN = pygame.USEREVENT + 2


def reset():
    global player, rocks, score, lives, start_time
    player = pygame.Rect(220, 300, 40, 40)
    rocks = []
    score = 0
    lives = 3
    start_time = pygame.time.get_ticks()
    pygame.time.set_timer(POINT, 1000)
    pygame.time.set_timer(SPAWN, 800)


def draw_menu():
    screen.fill((30, 30, 46))
    title = big_font.render("Meteor Dodge", True, WHITE)
    title_rect = title.get_rect(center=(240, 140))
    pygame.draw.rect(screen, PLATE, title_rect.inflate(24, 12))
    screen.blit(title, title_rect)
    hint = font.render("Press Enter to play", True, WHITE)
    screen.blit(hint, hint.get_rect(center=(240, 200)))


def draw_game():
    screen.fill((30, 30, 46))
    pygame.draw.rect(screen, (255, 196, 0), player)
    for rock in rocks:
        pygame.draw.rect(screen, (235, 80, 80), rock)
    score_text = font.render(f"{score:05}", True, WHITE)
    score_rect = score_text.get_rect(topright=(470, 10))
    pygame.draw.rect(screen, PLATE, score_rect.inflate(12, 8))
    screen.blit(score_text, score_rect)
    for i in range(3):
        if i < lives:
            screen.blit(heart, (10 + i * 40, 10))
        else:
            screen.blit(heart_empty, (10 + i * 40, 10))


def play_frame():
    global rocks, lives, state
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        player.x -= 6
    if keys[pygame.K_RIGHT]:
        player.x += 6
    player.clamp_ip(screen.get_rect())

    seconds = (pygame.time.get_ticks() - start_time) // 1000
    speed = 3 + seconds // 5
    kept = []
    for rock in rocks:
        rock.y += speed
        if rock.colliderect(player):
            lives -= 1
        elif rock.top <= 360:
            kept.append(rock)
    rocks = kept
    if lives <= 0:
        state = "over"
    draw_game()


def draw_over():
    draw_game()
    message = big_font.render("Game over", True, WHITE)
    screen.blit(message, message.get_rect(center=(240, 160)))
    hint = font.render("Press R to play again", True, WHITE)
    screen.blit(hint, hint.get_rect(center=(240, 200)))


reset()
state = "menu"

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == POINT and state == "play":
            score += 1
        if event.type == SPAWN and state == "play":
            rocks.append(pygame.Rect(random.randint(0, 456), -24, 24, 24))
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_RETURN and state == "menu":
                reset()
                state = "play"
            elif event.key == pygame.K_r and state == "over":
                reset()
                state = "play"

    if state == "menu":
        draw_menu()
    elif state == "play":
        play_frame()
    else:
        draw_over()
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Reglas del juego

Practica por tu cuenta: Playground de Pygame