import pygame, sys # --------------------------- # Configuración # --------------------------- ANCHO, ALTO = 960, 540 FPS = 60 GRAVEDAD = 0.9 VEL_X = 6 IMPULSO_SALTO = -18 pygame.init() ventana = pygame.display.set_mode((ANCHO, ALTO)) pygame.display.set_caption("Plataformas 2D - Niveles") clock = pygame.time.Clock() fuente = pygame.font.SysFont(None, 36) # --------------------------- # Sprites básicos # --------------------------- jugador_img = pygame.Surface((40, 52)) jugador_img.fill((40, 120, 255)) enemigo_img = pygame.Surface((40, 40)) enemigo_img.fill((200, 50, 50)) moneda_img = pygame.Surface((20, 20), pygame.SRCALPHA) pygame.draw.circle(moneda_img, (255, 220, 0), (10, 10), 10) plataforma_img = pygame.Surface((80, 20)) plataforma_img.fill((50, 50, 50)) check_img = pygame.Surface((20, 60)) check_img.fill((0, 200, 100)) meta_img = pygame.Surface((30, 100)) meta_img.fill((255, 0, 255)) # violeta para la meta # --------------------------- # Clases # --------------------------- class Jugador: def __init__(self, x, y): self.rect = jugador_img.get_rect(topleft=(x, y)) self.vx, self.vy = 0, 0 self.en_suelo = False self.monedas = 0 self.spawn = (x, y) def mover(self, teclas, plataformas): self.vx = 0 if teclas[pygame.K_LEFT] or teclas[pygame.K_a]: self.vx = -VEL_X if teclas[pygame.K_RIGHT] or teclas[pygame.K_d]: self.vx = VEL_X # Movimiento horizontal self.rect.x += self.vx for p in plataformas: if self.rect.colliderect(p): if self.vx > 0: self.rect.right = p.left elif self.vx < 0: self.rect.left = p.right # Gravedad self.vy += GRAVEDAD if self.vy > 30: self.vy = 30 self.rect.y += int(self.vy) # Colisiones verticales self.en_suelo = False for p in plataformas: if self.rect.colliderect(p): if self.vy > 0: self.rect.bottom = p.top self.vy = 0 self.en_suelo = True elif self.vy < 0: self.rect.top = p.bottom self.vy = 1 def saltar(self): if self.en_suelo: self.vy = IMPULSO_SALTO self.en_suelo = False def morir(self): self.rect.topleft = self.spawn self.vx, self.vy = 0, 0 self.monedas = 0 class Enemigo: def __init__(self, x, y, rango=100, vel=2): self.rect = enemigo_img.get_rect(topleft=(x, y)) self.base_x = x self.rango = rango self.vel = vel def mover(self): self.rect.x += self.vel if abs(self.rect.x - self.base_x) > self.rango: self.vel *= -1 class Moneda: def __init__(self, x, y): self.rect = moneda_img.get_rect(center=(x, y)) self.viva = True class Checkpoint: def __init__(self, x, y): self.rect = check_img.get_rect(bottomleft=(x, y)) self.activo = False class Meta: def __init__(self, x, y): self.rect = meta_img.get_rect(bottomleft=(x, y)) # --------------------------- # Definición de niveles # --------------------------- def crear_nivel1(): plataformas = [] enemigos = [] monedas = [] checks = [] metas = [] # Suelo for i in range(0, 2000, 80): plataformas.append(pygame.Rect(i, ALTO-40, 80, 40)) # Plataformas plataformas += [ pygame.Rect(300, 420, 160, 20), pygame.Rect(700, 360, 160, 20), pygame.Rect(1100, 300, 160, 20), ] # Enemigos enemigos.append(Enemigo(350, 380, rango=100)) # Monedas monedas += [Moneda(320, 380), Moneda(720, 320)] # Checkpoint checks.append(Checkpoint(900, ALTO-40)) # Meta metas.append(Meta(1800, ALTO-40)) return plataformas, enemigos, monedas, checks, metas def crear_nivel2(): plataformas = [] enemigos = [] monedas = [] checks = [] metas = [] # Suelo for i in range(0, 2500, 80): plataformas.append(pygame.Rect(i, ALTO-40, 80, 40)) # Plataformas plataformas += [ pygame.Rect(400, 400, 120, 20), pygame.Rect(800, 350, 120, 20), pygame.Rect(1200, 280, 120, 20), pygame.Rect(1600, 220, 120, 20), ] # Enemigos más difíciles enemigos.append(Enemigo(450, 360, rango=80, vel=3)) enemigos.append(Enemigo(1250, 240, rango=150, vel=2)) # Monedas monedas += [Moneda(420, 360), Moneda(820, 310), Moneda(1620, 180)] # Checkpoint checks.append(Checkpoint(1300, ALTO-40)) # Meta metas.append(Meta(2300, ALTO-40)) return plataformas, enemigos, monedas, checks, metas niveles = [crear_nivel1, crear_nivel2] # --------------------------- # Cámara # --------------------------- class Camara: def __init__(self): self.x = 0 def seguir(self, rect_jugador): objetivo = rect_jugador.centerx - ANCHO//2 self.x += (objetivo - self.x) * 0.1 def aplicar(self, rect): return pygame.Rect(rect.x - int(self.x), rect.y, rect.w, rect.h) # --------------------------- # Bucle principal # --------------------------- nivel_actual = 0 plataformas, enemigos, monedas, checkpoints, metas = niveles[nivel_actual]() jugador = Jugador(80, 100) camara = Camara() juego_completado = False while True: for e in pygame.event.get(): if e.type == pygame.QUIT: pygame.quit() sys.exit() if e.type == pygame.KEYDOWN: if not juego_completado: if e.key in (pygame.K_SPACE, pygame.K_w, pygame.K_UP): jugador.saltar() if e.key == pygame.K_r: nivel_actual = 0 plataformas, enemigos, monedas, checkpoints, metas = niveles[nivel_actual]() jugador = Jugador(80, 100) camara = Camara() juego_completado = False if not juego_completado: teclas = pygame.key.get_pressed() jugador.mover(teclas, plataformas) # Enemigos for enemigo in enemigos: enemigo.mover() if jugador.rect.colliderect(enemigo.rect): jugador.morir() # Monedas for moneda in monedas: if moneda.viva and jugador.rect.colliderect(moneda.rect): moneda.viva = False jugador.monedas += 1 # Checkpoints for check in checkpoints: if jugador.rect.colliderect(check.rect): check.activo = True jugador.spawn = (check.rect.x, check.rect.y - jugador.rect.h) # Meta for meta in metas: if jugador.rect.colliderect(meta.rect): nivel_actual += 1 if nivel_actual < len(niveles): plataformas, enemigos, monedas, checkpoints, metas = niveles[nivel_actual]() jugador = Jugador(80, 100) camara = Camara() else: juego_completado = True camara.seguir(jugador.rect) # Dibujar ventana.fill((135, 200, 255)) # cielo for p in plataformas: ventana.blit(plataforma_img, camara.aplicar(p)) for enemigo in enemigos: ventana.blit(enemigo_img, camara.aplicar(enemigo.rect)) for moneda in monedas: if moneda.viva: ventana.blit(moneda_img, camara.aplicar(moneda.rect)) for check in checkpoints: ventana.blit(check_img, camara.aplicar(check.rect)) for meta in metas: ventana.blit(meta_img, camara.aplicar(meta.rect)) ventana.blit(jugador_img, camara.aplicar(jugador.rect)) txt = fuente.render(f"Monedas: {jugador.monedas}", True, (0, 0, 0)) ventana.blit(txt, (10, 10)) if juego_completado: msg = fuente.render("¡Has ganado el juego! Pulsa R para reiniciar", True, (0, 0, 0)) ventana.blit(msg, (ANCHO//2 - msg.get_width()//2, ALTO//2)) pygame.display.flip() clock.tick(FPS)