import os import pygame import pickle from pygame.locals import * pygame.init() # Updated window dimensions WINDOW_WIDTH, WINDOW_HEIGHT = 1600, 1000 MAP_WIDTH, MAP_HEIGHT = 1000, 1000 TILE_SIZE = 50 # Colours WHITE = (255, 255, 255) GREY = (200, 200, 200) BLACK = (0, 0, 0) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) # Load images background_image = pygame.image.load('Images/Background.png') background_image = pygame.transform.scale(background_image, (MAP_WIDTH, MAP_HEIGHT)) # Block Images block_images = { 'brick0': pygame.image.load('Images/Level/brick_dark0.png'), 'brick1': pygame.image.load('Images/Level/brick_dark1.png'), 'brick2': pygame.image.load('Images/Level/brick_dark2.png'), 'brick3': pygame.image.load('Images/Level/brick_dark3.png'), 'cobbweb': pygame.image.load('Images/Level/Cobbwebs.png'), 'grill': pygame.image.load('Images/Level/Grill.png'), 'skulls': pygame.image.load('Images/Level/skulls.png'), 'platform': pygame.image.load('Images/Level/platform.png'), 'platform_vert': pygame.image.load('Images/Level/platform_vert.png'), 'platform_horz': pygame.image.load('Images/Level/platform_horz.png'), 'trog': pygame.image.load('Images/dngn_altar_trog.png'), 'key': pygame.image.load('Images/Key.png'), 'door': pygame.image.load('Images/dngn_closed_door.png'), 'drake': pygame.image.load('Images/drake.png') } # Resize block images to fit the tile size for key in block_images: if key == 'platform': platform_size = block_images[key].get_size() block_images[key] = pygame.transform.scale(block_images[key], (TILE_SIZE, platform_size[1])) elif key in ['platform_vert', 'platform_horz']: block_images[key] = pygame.transform.scale(block_images[key], platform_size) elif key == 'key': block_images[key] = pygame.transform.scale(block_images[key], (TILE_SIZE, 25)) else: block_images[key] = pygame.transform.scale(block_images[key], (TILE_SIZE, TILE_SIZE)) # Ensure the level_data directory exists if not os.path.exists('level_data'): os.makedirs('level_data') # Dictionary to hold the placed blocks for each level placed_blocks = {1: [], 2: [], 3: []} current_level = 1 # Start with level 1 undo_stack = [] # Stack to keep track of actions for undo functionality redo_stack = [] # Stack to keep track of actions for redo functionality #Window screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) pygame.display.set_caption('Level Editor') map_surface = pygame.Surface((MAP_WIDTH, MAP_HEIGHT)) #Font font = pygame.font.SysFont(None, 36) # Draw grid on screen def draw_grid(surface, width, height, tile_size): for x in range(0, width, tile_size): pygame.draw.line(surface, GREY, (x, 0), (x, height)) for y in range(0, height, tile_size): pygame.draw.line(surface, GREY, (0, y), (width, y)) def draw_menu(surface, save_button_color, load_button_color, reset_button_color, undo_button_color, current_level, selected_block): pygame.draw.rect(surface, WHITE, (0, 0, 600, WINDOW_HEIGHT)) text = font.render('Menu', True, BLACK) surface.blit(text, (250, 20)) y_offset = 70 x_offset = 50 for idx, (block_name, block_img) in enumerate(block_images.items()): if block_name == selected_block: pygame.draw.rect(surface, GREEN, (x_offset - 5, y_offset - 5, TILE_SIZE + 10, TILE_SIZE + 10), 2) surface.blit(block_img, (x_offset, y_offset)) x_offset += TILE_SIZE + 10 if x_offset > 500: x_offset = 50 y_offset += TILE_SIZE + 10 y_offset = WINDOW_HEIGHT - 200 button_width = 250 button_height = 50 save_button = pygame.Rect(50, y_offset + 20, button_width, button_height) load_button = pygame.Rect(320, y_offset + 20, button_width, button_height) reset_button = pygame.Rect(50, y_offset + 80, button_width, button_height) undo_button = pygame.Rect(320, y_offset + 80, button_width, button_height) pygame.draw.rect(surface, save_button_color, save_button) pygame.draw.rect(surface, load_button_color, load_button) pygame.draw.rect(surface, reset_button_color, reset_button) pygame.draw.rect(surface, undo_button_color, undo_button) save_text = font.render('Save', True, BLACK) load_text = font.render('Load', True, BLACK) reset_text = font.render('Reset', True, BLACK) undo_text = font.render('Undo/Redo', True, BLACK) surface.blit(save_text, (save_button.x + 90, save_button.y + 15)) surface.blit(load_text, (load_button.x + 90, load_button.y + 15)) surface.blit(reset_text, (reset_button.x + 90, reset_button.y + 15)) surface.blit(undo_text, (undo_button.x + 60, undo_button.y + 15)) level_name_box = pygame.Rect(50, y_offset + 160, button_width, button_height) pygame.draw.rect(surface, WHITE, level_name_box, 2) current_level_text = font.render(f'Current Level: {current_level}', True, BLACK) surface.blit(current_level_text, (200, WINDOW_HEIGHT - 50)) return save_button, load_button, reset_button, undo_button, level_name_box running = True selected_block = None dragging_left = False dragging_right = False level_name = "" save_button_color = GREY load_button_color = GREY reset_button_color = RED undo_button_color = GREY save_button_clicked = False load_button_clicked = False reset_button_clicked = False undo_button_clicked = False undo_button_right_clicked = False while running: screen.fill(WHITE) save_button, load_button, reset_button, undo_button, level_name_box = draw_menu(screen, save_button_color, load_button_color, reset_button_color, undo_button_color, current_level, selected_block) for event in pygame.event.get(): if event.type == QUIT: running = False elif event.type == MOUSEBUTTONDOWN: mouse_x, mouse_y = event.pos if event.button == 1: if mouse_x <= 600: y_offset = 70 x_offset = 50 for idx, block_name in enumerate(block_images.keys()): if x_offset <= mouse_x <= x_offset + TILE_SIZE and y_offset <= mouse_y <= y_offset + TILE_SIZE: selected_block = block_name break x_offset += TILE_SIZE + 10 if x_offset > 500: x_offset = 50 y_offset += TILE_SIZE + 10 if save_button.collidepoint(mouse_x, mouse_y): save_button_color = GREEN save_button_clicked = True elif load_button.collidepoint(mouse_x, mouse_y): load_button_color = GREEN load_button_clicked = True elif reset_button.collidepoint(mouse_x, mouse_y): reset_button_color = GREEN reset_button_clicked = True elif undo_button.collidepoint(mouse_x, mouse_y): undo_button_color = BLUE undo_button_clicked = True else: dragging_left = True if selected_block: tile_x = ((mouse_x - 600) // TILE_SIZE) * TILE_SIZE tile_y = (mouse_y // TILE_SIZE) * TILE_SIZE placed_blocks[current_level].append((tile_x, tile_y, selected_block)) undo_stack.append(('add', (tile_x, tile_y, selected_block))) elif event.button == 3: if mouse_x <= 600 and undo_button.collidepoint(mouse_x, mouse_y): undo_button_color = BLUE undo_button_right_clicked = True else: dragging_right = True if mouse_x > 600: tile_x = ((mouse_x - 600) // TILE_SIZE) * TILE_SIZE tile_y = (mouse_y // TILE_SIZE) * TILE_SIZE for block in placed_blocks[current_level]: if block[0] == tile_x and block[1] == tile_y: placed_blocks[current_level].remove(block) undo_stack.append(('remove', block)) break elif event.type == MOUSEBUTTONUP: if event.button == 1: dragging_left = False save_button_color = GREY load_button_color = GREY reset_button_color = RED undo_button_color = GREY elif event.button == 3: dragging_right = False undo_button_right_clicked = False undo_button_color = GREY elif event.type == MOUSEMOTION: mouse_x, mouse_y = event.pos if dragging_left and mouse_x > 600: if selected_block: tile_x = ((mouse_x - 600) // TILE_SIZE) * TILE_SIZE tile_y = (mouse_y // TILE_SIZE) * TILE_SIZE placed_blocks[current_level].append((tile_x, tile_y, selected_block)) undo_stack.append(('add', (tile_x, tile_y, selected_block))) elif dragging_right and mouse_x > 600: tile_x = ((mouse_x - 600) // TILE_SIZE) * TILE_SIZE tile_y = (mouse_y // TILE_SIZE) * TILE_SIZE for block in placed_blocks[current_level]: if block[0] == tile_x and block[1] == tile_y: placed_blocks[current_level].remove(block) undo_stack.append(('remove', block)) break elif event.type == KEYDOWN: if event.key == K_BACKSPACE: level_name = level_name[:-1] elif event.key == K_RETURN: pass elif event.key == K_LEFT: current_level = max(1, current_level - 1) elif event.key == K_RIGHT: current_level = min(3, current_level + 1) else: level_name += event.unicode level_name_text = font.render(level_name, True, BLACK) screen.blit(level_name_text, (level_name_box.x + 5, level_name_box.y + 5)) map_surface.blit(background_image, (0, 0)) for block in placed_blocks[current_level]: tile_x, tile_y, block_type = block if block_type == 'key': key_height = block_images[block_type].get_height() adjusted_y = tile_y + (TILE_SIZE - key_height) // 2 map_surface.blit(block_images[block_type], (tile_x, adjusted_y)) elif block_type in ['platform', 'platform_vert', 'platform_horz']: adjusted_y = tile_y + (TILE_SIZE - block_images[block_type].get_height()) map_surface.blit(block_images[block_type], (tile_x, adjusted_y)) else: map_surface.blit(block_images[block_type], (tile_x, tile_y)) draw_grid(map_surface, MAP_WIDTH, MAP_HEIGHT, TILE_SIZE) screen.blit(map_surface, (600, 0)) pygame.display.flip() if save_button_clicked: try: with open(f'level_data/level{current_level}_data', 'wb') as pickle_out: pickle.dump(placed_blocks[current_level], pickle_out) print(f"Level {current_level} saved successfully.") except Exception as e: print(f"Error saving level {current_level}: {e}") save_button_clicked = False if load_button_clicked: try: with open(f'level_data/level{current_level}_data', 'rb') as pickle_in: placed_blocks[current_level] = pickle.load(pickle_in) print(f"Level {current_level} loaded successfully.") except FileNotFoundError: print(f"No save file found for level {current_level}. Starting with an empty level.") placed_blocks[current_level] = [] except Exception as e: print(f"Error loading level {current_level}: {e}") load_button_clicked = False if reset_button_clicked: placed_blocks[current_level] = [] undo_stack = [] redo_stack = [] print(f"Level {current_level} reset successfully.") reset_button_clicked = False if undo_button_clicked and undo_stack: action, block = undo_stack.pop() if action == 'add': placed_blocks[current_level].remove(block) redo_stack.append(('add', block)) elif action == 'remove': placed_blocks[current_level].append(block) redo_stack.append(('remove', block)) print(f"Undo performed for level {current_level}.") undo_button_clicked = False if undo_button_right_clicked and redo_stack: action, block = redo_stack.pop() if action == 'add': placed_blocks[current_level].append(block) undo_stack.append(('add', block)) elif action == 'remove': placed_blocks[current_level].remove(block) undo_stack.append(('remove', block)) print(f"Redo performed for level {current_level}.") undo_button_right_clicked = False pygame.quit()