Herramientas de usuario

Herramientas del sitio


informatica:programacion:python:pyxel:juego_tipo_breakout

Breakout clon

Juego tipo Breakout / Arkanoid usando Pyxel.

El código fue generado por DeepSeek (una inteligencia artificial generativa)

import pyxel
import math
import random
 
class Breakout:
    def __init__(self):
        pyxel.init(160, 256, title="Pyxel Breakout", fps=60)
        self.reset_game()
        self.setup_sounds()
        pyxel.run(self.update, self.draw)
 
    def reset_game(self):
        self.paddle_x = 64
        self.paddle_speed = 4
        self.lives = 3
        self.score = 0
        self.ball_x = 80
        self.ball_y = 200
        self.ball_angle = random.uniform(math.pi * 5/4, math.pi * 7/4)  # Ángulo hacia arriba
        self.ball_speed = 3.5
        self.ball_active = False
        self.blocks = []
        self.create_level(1)
        self.powerups = []
        self.active_powerup = None
        self.powerup_time = 0
 
    def create_level(self, level):
        colors = [2, 3, 4, 5, 6, 8, 9, 10]
        for y in range(4 + level):
            for x in range(10):
                self.blocks.append({
                    'x': x * 16,
                    'y': y * 12 + 40,
                    'color': colors[(y + x) % len(colors)],
                    'hp': 1 if y < 2 else 2
                })
 
    def setup_sounds(self):
        pyxel.sound(0).set(notes="C4", tones="T", volumes="5", effects="N", speed=10)
        pyxel.sound(1).set(notes="E4", tones="T", volumes="5", effects="N", speed=10)
 
    def update(self):
        if self.lives <= 0 or len(self.blocks) == 0:
            if pyxel.btnp(pyxel.KEY_R):
                self.reset_game()
            return
 
        paddle_width = 48 if self.active_powerup == 'expand' else 32
 
        # Movimiento paleta
        if pyxel.btn(pyxel.KEY_LEFT):
            self.paddle_x = max(0, self.paddle_x - self.paddle_speed)
        if pyxel.btn(pyxel.KEY_RIGHT):
            self.paddle_x = min(160 - paddle_width, self.paddle_x + self.paddle_speed)
 
        # Lógica de la bola
        if self.ball_active:
            self.ball_x += math.cos(self.ball_angle) * self.ball_speed
            self.ball_y += math.sin(self.ball_angle) * self.ball_speed
 
            # Colisión con paredes
            if self.ball_x < 2 or self.ball_x > 158:
                self.ball_angle = math.pi - self.ball_angle
                self.ball_x = max(2, min(158, self.ball_x))
                pyxel.play(0, 0)
 
            # Colisión con techo
            if self.ball_y < 2:
                self.ball_angle = -self.ball_angle
                self.ball_y = 2
                pyxel.play(0, 0)
 
            # Colisión con paleta (sistema mejorado)
            if (self.paddle_x - 2 < self.ball_x < self.paddle_x + paddle_width + 2 and 
                200 <= self.ball_y <= 210):
 
                # Cálculo preciso del punto de impacto
                hit_pos = (self.ball_x - self.paddle_x) / paddle_width
                self.ball_angle = math.pi * (1.25 + hit_pos * 0.5)  # Ángulos entre 125% y 175% de π
                self.ball_y = 195  # Posicionar claramente encima de la paleta
                self.ball_x += math.cos(self.ball_angle) * 5  # Impulso adicional
                pyxel.play(0, 0)
 
            # Colisión con bloques
            for block in self.blocks[:]:
                if (block['x'] < self.ball_x < block['x'] + 16 and
                    block['y'] < self.ball_y < block['y'] + 8):
 
                    block['hp'] -= 1
                    self.score += 10 * block['hp'] + 10
 
                    # Cálculo de rebote preciso
                    bx_center = block['x'] + 8
                    by_center = block['y'] + 4
                    dx = self.ball_x - bx_center
                    dy = self.ball_y - by_center
 
                    if abs(dx) > abs(dy):
                        self.ball_angle = math.pi - self.ball_angle
                    else:
                        self.ball_angle = -self.ball_angle
 
                    if block['hp'] <= 0:
                        self.blocks.remove(block)
                        if random.random() < 0.2:
                            self.powerups.append({
                                'x': block['x'],
                                'y': block['y'],
                                'type': random.choice(['expand', 'laser', 'multi'])
                            })
                    pyxel.play(0, 0)
                    break
 
            # Actualizar power-ups
            for powerup in self.powerups[:]:
                powerup['y'] += 1
                if powerup['y'] > 256:
                    self.powerups.remove(powerup)
                elif (self.paddle_x < powerup['x'] < self.paddle_x + paddle_width and
                      200 < powerup['y'] < 210):
                    self.activate_powerup(powerup['type'])
                    self.powerups.remove(powerup)
                    pyxel.play(0, 1)
 
            # Manejar power-up activo
            if self.active_powerup:
                self.powerup_time -= 1
                if self.powerup_time <= 0:
                    self.active_powerup = None
                    self.paddle_x = 64
 
            # Verificar pérdida de bola
            if self.ball_y > 256:
                self.lives -= 1
                self.ball_active = False
                self.reset_ball(paddle_width)
        else:
            # Posición inicial centrada en la paleta
            self.ball_x = self.paddle_x + (paddle_width // 2)
            if pyxel.btnp(pyxel.KEY_SPACE):
                self.ball_active = True
                # Ángulo hacia arriba entre 45° izquierda y 45° derecha
                self.ball_angle = random.uniform(math.pi * 5/4, math.pi * 7/4)
 
    def activate_powerup(self, power_type):
        self.active_powerup = power_type
        self.powerup_time = 600
        if power_type == 'expand':
            self.paddle_x = max(0, self.paddle_x - 16)
            self.paddle_speed = 3
 
    def reset_ball(self, paddle_width):
        self.ball_active = False
        self.ball_x = self.paddle_x + (paddle_width // 2)
        self.ball_y = 200
 
    def draw(self):
        pyxel.cls(0)
 
        # Dibujar bloques
        for block in self.blocks:
            pyxel.rect(block['x'], block['y'], 16, 8, block['color'])
            if block['hp'] > 1:
                pyxel.rect(block['x']+4, block['y']+3, 8, 2, 0)
 
        # Dibujar paleta
        paddle_width = 48 if self.active_powerup == 'expand' else 32
        pyxel.rect(self.paddle_x, 200, paddle_width, 8, 7)
 
        # Dibujar bola
        ball_color = 10 if self.ball_active else 8
        pyxel.circ(self.ball_x, self.ball_y, 3, ball_color)
 
        # Dibujar power-ups
        for powerup in self.powerups:
            color = 8 if powerup['type'] == 'expand' else 9 if powerup['type'] == 'laser' else 10
            pyxel.rect(powerup['x'], powerup['y'], 8, 8, color)
 
        # UI
        pyxel.text(5, 5, f"SCORE: {self.score}", 7)
        pyxel.text(120, 5, f"VIDAS: {'♥' * self.lives}", 7)
        if not self.ball_active and self.lives > 0:
            pyxel.text(40, 220, "PRESIONA [ESPACIO] PARA LANZAR", 9)
            pyxel.rect(self.paddle_x + (paddle_width//2) - 2, 197, 4, 4, 10)
 
        # Estados de juego
        if self.lives <= 0:
            pyxel.text(60, 120, "GAME OVER", pyxel.frame_count % 16)
            pyxel.text(40, 140, "Presiona R para reiniciar", 7)
        elif len(self.blocks) == 0:
            pyxel.text(60, 120, "¡NIVEL COMPLETADO!", 11)
            pyxel.text(40, 140, "Presiona R para siguiente nivel", 7)
 
Breakout()

Recursos

informatica/programacion/python/pyxel/juego_tipo_breakout.txt · Última modificación: por tempwin