""" ---------------------------------------- Project: Platformer Shooter = Standard: 91883 (AS1.7) v.1 School: = Tauranga Boys' College = Author: Sam Coley = Date: June 2024 = Python: 3.12 = ---------------------------------------- """ import pygame # Import the Pygame module for game development import button # Import a custom button module import csv # Import the CSV module for handling CSV file operations import pickle # Import the Pickle module for serializing and deserializing objects pygame.init() # Initialize Pygame clock = pygame.time.Clock() # Create a clock object to manage the frame rate FPS = 120 # Set the frames per second # Game window dimensions SCREEN_WIDTH = 800 # Width of the game screen SCREEN_HEIGHT = 640 # Height of the game screen LOWER_MARGIN = 100 # Additional space at the bottom of the screen SIDE_MARGIN = 300 # Additional space on the right side of the screen # Set up the display with extra space for margins screen = pygame.display.set_mode((SCREEN_WIDTH + SIDE_MARGIN, SCREEN_HEIGHT + LOWER_MARGIN)) # Create the game window pygame.display.set_caption('Level Editor') # Set the window caption # Define game variables ROWS = 16 # Number of rows for the grid MAX_COLUMNS = 150 # Maximum number of columns for the grid TILE_SIZE = SCREEN_HEIGHT // ROWS # Calculate the tile size based on screen height TILE_TYPES = 21 # Total number of different tiles level = 0 # Current level current_tile = 0 # Currently selected tile scroll_left = False # Flag to check if scrolling left scroll_right = False # Flag to check if scrolling right scroll = 0 # Scroll amount scroll_speed = 1 # Scroll speed # Load background image darksky_image = pygame.image.load('Images/Background/dark_sky.jpg').convert_alpha() # Load the sky image and convert it for Pygame # Store tiles in a list image_list = [] # Initialize an empty list to hold tile images for x in range(TILE_TYPES): # Loop through each tile type image = pygame.image.load(f'Images/Tile Blocks/{x}.png').convert_alpha() # Load and convert the tile image image = pygame.transform.scale(image, (TILE_SIZE, TILE_SIZE)) # Scale the tile image to the correct size image_list.append(image) # Add the image to the list # Load save and load button images and scale them save_image = pygame.image.load('Images/Background/Save.png').convert_alpha() # Load the save button image and convert it save_image = pygame.transform.scale(save_image, (80, 60)) # Scale the save button image load_image = pygame.image.load('Images/Background/Load.png').convert_alpha() # Load the load button image and convert it load_image = pygame.transform.scale(load_image, (80, 60)) # Scale the load button image # Define colors BLUE = (144, 201, 120) # Define the color BLUE WHITE = (255, 255, 255) # Define the color white RED = (200, 25, 25) # Define the color red BLUE = (0, 0, 128) # Blue color # Define font font = pygame.font.SysFont('Pixel Operator 8', 20) # Define the font and size for text # Create empty tile list world_data = [] # Initialize an empty list for world data for row in range(ROWS): # Loop through each row r = [-1] * MAX_COLUMNS # Create a list of -1 for each column world_data.append(r) # Add the row to the world data list # Create ground for tile in range(0, MAX_COLUMNS): # Loop through each column in the last row world_data[ROWS - 1][tile] = 0 # Set the tile to 0 (ground) # Function for outputting text onto the screen def draw_text(text, font, text_col, x, y): image = font.render(text, True, text_col) # Render the text screen.blit(image, (x, y)) # Draw the text on the screen at the specified position # Function for drawing background def draw_bg(): screen.fill(BLUE) # Fill the screen with the blue color width = darksky_image.get_width() # Get the width of the background image for x in range(4): # Loop to cover the screen width with the background image screen.blit(darksky_image, ((x * width) - scroll * 0.5, 0)) # Draw the background image # Draw grid def draw_grid(): # Vertical lines for c in range(MAX_COLUMNS + 1): # Loop through each column pygame.draw.line(screen, WHITE, (c * TILE_SIZE - scroll, 0), (c * TILE_SIZE - scroll, SCREEN_HEIGHT)) # Draw vertical line # Horizontal lines for c in range(ROWS + 1): # Loop through each row pygame.draw.line(screen, WHITE, (0, c * TILE_SIZE), (SCREEN_WIDTH, c * TILE_SIZE)) # Draw horizontal line # Function for drawing the world tiles def draw_world(): for y, row in enumerate(world_data): # Loop through each row in the world data for x, tile in enumerate(row): # Loop through each tile in the row if tile >= 0: # Check if the tile is valid screen.blit(image_list[tile], (x * TILE_SIZE - scroll, y * TILE_SIZE)) # Draw the tile # Create buttons save_button = button.Button(SCREEN_WIDTH // 2, SCREEN_HEIGHT + LOWER_MARGIN - 50, save_image, 1) # Create the save button load_button = button.Button(SCREEN_WIDTH // 2 + 200, SCREEN_HEIGHT + LOWER_MARGIN - 50, load_image, 1) # Create the load button # Make a button list for tile selection button_list = [] # Initialize an empty list for buttons button_columns = 0 # Initialize column counter button_row = 0 # Initialize row counter for i in range(len(image_list)): # Loop through each image in the list tile_button = button.Button(SCREEN_WIDTH + (75 * button_columns) + 50, 75 * button_row + 50, image_list[i], 1) # Create a button for each tile button_list.append(tile_button) # Add the button to the list button_columns += 1 # Increment the column counter if button_columns == 3: # If the column counter reaches 3 button_row += 1 # Increment the row counter button_columns = 0 # Reset the column counter # Main game loop run = True # Flag to keep the game running while run: clock.tick(FPS) # Ensure the game runs at the specified FPS draw_bg() # Draw the background draw_grid() # Draw the grid draw_world() # Draw the world tiles draw_text(f'Level: {level}', font, WHITE, 10, SCREEN_HEIGHT + LOWER_MARGIN - 90) # Draw the level text draw_text('Press UP or DOWN to change level', font, WHITE, 10, SCREEN_HEIGHT + LOWER_MARGIN - 60) # Draw the instruction text # Save and load data if save_button.draw(screen): # If the save button is clicked with open(f'level{level}_data.csv', 'w', newline='') as csvfile: # Open a new CSV file for writing writer = csv.writer(csvfile, delimiter=',') # Create a CSV writer object for row in world_data: # Loop through each row in the world data writer.writerow(row) # Write the row to the CSV file if load_button.draw(screen): # If the load button is clicked scroll = 0 # Reset scroll back to the start of the level with open(f'level{level}_data.csv', newline='') as csvfile: # Open the CSV file for reading reader = csv.reader(csvfile, delimiter=',') # Create a CSV reader object for x, row in enumerate(reader): # Loop through each row in the CSV file for y, tile in enumerate(row): # Loop through each tile in the row world_data[x][y] = int(tile) # Update the world data # Draw tile panel and tiles pygame.draw.rect(screen, BLUE, (SCREEN_WIDTH, 0, SIDE_MARGIN, SCREEN_HEIGHT)) # Draw the tile panel # Choose a tile button_count = 0 # Initialize the button counter for button_count, i in enumerate(button_list): # Loop through each button in the list if i.draw(screen): # If the button is clicked current_tile = button_count # Set the current tile to the button index # Highlight the selected tile pygame.draw.rect(screen, RED, button_list[current_tile].rect, 3) # Draw a red rectangle around the selected tile # Scroll the map if scroll_left and scroll > 0: # If scrolling left and not at the start scroll -= 5 * scroll_speed # Decrease the scroll amount if scroll_right and scroll < (MAX_COLUMNS * TILE_SIZE) - SCREEN_WIDTH: # If scrolling right and not at the end scroll += 5 * scroll_speed # Increase the scroll amount # Add new tiles to the screen pos = pygame.mouse.get_pos() # Get the mouse position x = (pos[0] + scroll) // TILE_SIZE # Calculate the tile x coordinate y = pos[1] // TILE_SIZE # Calculate the tile y coordinate # Check that the coordinates are within the tile area if pos[0] < SCREEN_WIDTH and pos[1] < SCREEN_HEIGHT: # If the mouse is within the screen if pygame.mouse.get_pressed()[0] == 1: # If the left mouse button is pressed if world_data[y][x] != current_tile: # If the tile is different from the current tile world_data[y][x] = current_tile # Update the tile if pygame.mouse.get_pressed()[2] == 1: # If the right mouse button is pressed world_data[y][x] = -1 # Remove the tile # Event handling for event in pygame.event.get(): # Loop through each event if event.type == pygame.QUIT: # If the event is quitting the game run = False # Set the run flag to False if event.type == pygame.KEYDOWN: # If a key is pressed if event.key == pygame.K_UP: # If the UP key is pressed level += 1 # Increment the level if event.key == pygame.K_DOWN and level > 0: # If the DOWN key is pressed and level is greater than 0 level -= 1 # Decrement the level if event.key == pygame.K_LEFT: # If the LEFT key is pressed scroll_left = True # Set the scroll left flag to True if event.key == pygame.K_RIGHT: # If the RIGHT key is pressed scroll_right = True # Set the scroll right flag to True if event.key == pygame.K_RSHIFT: # If the right SHIFT key is pressed scroll_speed = 5 # Increase the scroll speed if event.type == pygame.KEYUP: # If a key is released if event.key == pygame.K_LEFT: # If the LEFT key is released scroll_left = False # Set the scroll left flag to False if event.key == pygame.K_RIGHT: # If the RIGHT key is released scroll_right = False # Set the scroll right flag to False if event.key == pygame.K_RSHIFT: # If the right SHIFT key is released scroll_speed = 1 # Reset the scroll speed pygame.display.update() # Update the display pygame.quit() # Quit Pygame