pygame-web / pygbag

python and pygame wasm for everyone ( packager + test server + simulator )
https://github.com/pygame-web
MIT License
316 stars 36 forks source link

I keep gettnig stuck on a balckscreen #177

Open Paper-Crusader opened 1 week ago

Paper-Crusader commented 1 week ago

I keep loading the game but my code keeps getting stuck on a black screen it says its a problem with trnpersnt images but i dont rlly know

import pygame  
import random
import os
import time
import asyncio

# Initialize Pygame
pygame.init()
pygame.mixer.init()  # Initialize the mixer for music and sound effects

# Screen dimensions
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# Tile settings
TILE_SIZE = 100  # Set a fixed size for the tiles
PADDING = 10     # Space between tiles

# Create the screen
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Memory Matching Game")

# Relative path to assets directory (force forward slashes)
image_dir = 'images/'
music_dir = 'music/'
sounds_dir = 'sounds/'

# Function to load images with optional scaling and fill color
def load_image(image_path, scale_size=None, fill_color=None):
    try:
        # Load the image with alpha transparency
        image = pygame.image.load(image_path).convert_alpha()
        if fill_color:
            # Fill the image with the specified color while keeping transparency
            image.fill(fill_color + (0,), special_flags=pygame.BLEND_RGBA_MULT)
        if scale_size:
            image = pygame.transform.scale(image, scale_size)
        return image
    except FileNotFoundError:
        print(f"Error: {image_path} not found.")
        return None
    except pygame.error as e:
        print(f"Error loading image {image_path}: {e}")
        return None

# Load Sonny Angel logo with transparency (manual forward slashes)
logo_path = 'images/SonnyAngel_logo.png'
logo = load_image(logo_path, (400, 100))
if not logo:
    logo = pygame.Surface((400, 100))  # Create a placeholder surface

# Load the title screen image
title_image_path = 'images/title.png'
title_image = load_image(title_image_path)
if not title_image:
    title_image = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))  # Create a placeholder surface

# Load the background images for each level
background_paths = [f'images/level-{i}.png' for i in range(1, 5)]
backgrounds = [load_image(path, (SCREEN_WIDTH, SCREEN_HEIGHT)) for path in background_paths]
backgrounds = [bg if bg else pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT)) for bg in backgrounds]  # Fallback to placeholder

# Load the start button image
start_image_path = 'images/start.png'
start_image = load_image(start_image_path, (200, 80))
if not start_image:
    start_image = pygame.Surface((200, 80))  # Create a placeholder surface

# Load images (Ensure exactly 20 images named img1.png to img20.png)
image_files = [f'images/img{i}.png' for i in range(1, 21)]
images = []

# Load the images
for img_file in image_files:
    img = load_image(img_file, (TILE_SIZE, TILE_SIZE))
    if img:
        images.append(img)

# Ensure there are exactly 20 images loaded
if len(images) != 20:
    raise RuntimeError(f"Error: Expected 20 images but found only {len(images)}.")

# Load placeholder image
placeholder_image = pygame.Surface((TILE_SIZE, TILE_SIZE))
placeholder_image.fill(BLACK)

# Duplicate images to create pairs
all_images = images + images
random.shuffle(all_images)

# Load the font
font = pygame.font.Font('Lonely Cake.ttf', 30)

# Game variables
level = 1
level_sizes = [8, 12, 16, 20]  # Ensure even numbers for grid sizes
time_limit_per_level = [60, 45, 30, 20]
grid = []
revealed = []
first_click = None
second_click = None
matches_found = 0
total_matches = 0

# Add timer to keep mismatched tiles shown for a brief time
show_mismatched_time = None

# Load background music (manual forward slashes)
music_path = 'music/Earfquake.mp3'
pygame.mixer.music.load(music_path)
pygame.mixer.music.set_volume(0.3)  # Set volume to 30%
pygame.mixer.music.play(-1)  # Play the music indefinitely

# Load the match sound effect
match_sound_path = 'sounds/correct.mp3'
match_sound = pygame.mixer.Sound(match_sound_path)

def calculate_grid_start_positions(num_rows, num_cols):
    grid_width = num_cols * TILE_SIZE + (num_cols - 1) * PADDING
    grid_height = num_rows * TILE_SIZE + (num_rows - 1) * PADDING
    start_x = (SCREEN_WIDTH - grid_width) // 2
    start_y = (SCREEN_HEIGHT - grid_height) // 2
    return start_x, start_y

def reset_grid():
    global grid, revealed, matches_found, first_click, second_click, total_matches, START_X, START_Y

    matches_found = 0
    first_click, second_click = None, None

    grid_size = level_sizes[level - 1]
    num_rows = int(grid_size**0.5)
    num_cols = grid_size // num_rows
    grid = [[None for _ in range(num_cols)] for _ in range(num_rows)]
    revealed = [[False for _ in range(num_cols)] for _ in range(num_rows)]

    START_X, START_Y = calculate_grid_start_positions(num_rows, num_cols)

    level_images = []
    num_pairs = grid_size // 2

    selected_images = random.sample(images, num_pairs)
    for img in selected_images:
        level_images.append(img)
        level_images.append(img)

    random.shuffle(level_images)

    for i in range(num_rows):
        for j in range(num_cols):
            grid[i][j] = level_images.pop() if level_images else placeholder_image

    total_matches = grid_size // 2

def draw_grid():
    num_rows = len(grid)
    num_cols = len(grid[0])
    for i in range(num_rows):
        for j in range(num_cols):
            x = START_X + j * (TILE_SIZE + PADDING)
            y = START_Y + i * (TILE_SIZE + PADDING)
            if revealed[i][j]:
                screen.blit(grid[i][j], (x, y))
            else:
                pygame.draw.rect(screen, WHITE, (x, y, TILE_SIZE, TILE_SIZE))

def draw_score():
    score_text = f"Score: {matches_found}"
    score_surface = font.render(score_text, True, WHITE)
    screen.blit(score_surface, (10, 10))

def draw_timer(time_left):
    timer_text = f"Time: {int(time_left)}"
    timer_surface = font.render(timer_text, True, WHITE)
    screen.blit(timer_surface, (SCREEN_WIDTH - 150, 10))

async def main_loop():
    global first_click, second_click, matches_found, level, running, show_mismatched_time

    start_time = time.time()
    time_limit = time_limit_per_level[level - 1]

    while running:
        current_time = time.time()
        time_left = time_limit - (current_time - start_time)

        num_rows = len(grid)
        num_cols = len(grid[0])
        screen.blit(backgrounds[level - 1], (0, 0))
        draw_grid()
        draw_score()
        draw_timer(time_left)

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

            elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
                x, y = event.pos
                col = (x - START_X) // (TILE_SIZE + PADDING)
                row = (y - START_Y) // (TILE_SIZE + PADDING)

                if 0 <= row < num_rows and 0 <= col < num_cols and not revealed[row][col] and show_mismatched_time is None:
                    if first_click is None:
                        first_click = (row, col)
                        revealed[row][col] = True
                    elif second_click is None:
                        second_click = (row, col)
                        revealed[row][col] = True

        if first_click and second_click and show_mismatched_time is None:
            first_row, first_col = first_click
            second_row, second_col = second_click

            if grid[first_row][first_col] == grid[second_row][second_col]:
                matches_found += 1
                match_sound.play()  # Play the match sound effect
                first_click = None
                second_click = None
            else:
                show_mismatched_time = time.time()

        # Wait for 2 seconds before hiding mismatched images
        if show_mismatched_time and time.time() - show_mismatched_time > 2:
            first_row, first_col = first_click
            second_row, second_col = second_click
            revealed[first_row][first_col] = False
            revealed[second_row][second_col] = False
            first_click, second_click = None, None
            show_mismatched_time = None

        if matches_found == total_matches:
            if level < len(level_sizes):
                level += 1
                reset_grid()
                start_time = time.time()
            else:
                running = False

        if time_left <= 0:
            running = False

        pygame.display.flip()

async def main_menu():
    global running

    while True:
        screen.blit(title_image, (0, 0))
        logo_rect = logo.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 4))
        screen.blit(logo, logo_rect)
        start_rect = start_image.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 100))
        screen.blit(start_image, start_rect)

        quit_surface = font.render("Quit", True, WHITE)
        quit_rect = quit_surface.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 200))
        screen.blit(quit_surface, quit_rect)

        pygame.display.flip()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                return False

            elif event.type == pygame.MOUSEBUTTONDOWN:
                if start_rect.collidepoint(event.pos):
                    return True
                elif quit_rect.collidepoint(event.pos):
                    pygame.quit()
                    return False

        await asyncio.sleep(0)  # Sleep for roughly 16ms

async def main():
    global running

    while True:
        if not await main_menu():
            break

        running = True
        reset_grid()
        await main_loop()

    pygame.quit()

if __name__ == "__main__":
    asyncio.run(main())
pmp-p commented 3 hours ago

mp3 are not allowed they have side effects, see mandatory here https://pygame-web.github.io/#all-operating-systems .