#-------------------------------------------------------------------------- # Name : Platformer # Standard: US 91896 2.7 # School: Tauranga Boys College # Author: James Darby # Date: 29/04/2024 # Python: 3.19.13 #-------------------------------------------------------------------------- import pygame import csv import os.path as path # initializing pygame pygame.init() # set fps and screen dimensions as constant values fps = 60 SCREEN_WIDTH = 800 SCREEN_HEIGHT = 640 # create a clock that controls the framerate of the game clock = pygame.time.Clock() # set up display screen screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption('Scrolling Platformer Game') # main game variables level = 0 ROWS = 16 TILE_SIZE = SCREEN_HEIGHT // ROWS scroll_speed = 5 bg_x = 0 GRAVITY = 0.6 JUMP_POWER = -10 # negative value so player moves upwards # load in and scale background image bg_img = pygame.image.load('img/bg.png') bg_img = pygame.transform.scale(bg_img, (SCREEN_WIDTH, SCREEN_HEIGHT)) # create spike and doublespike groups spike_group = pygame.sprite.Group() doublespike_group = pygame.sprite.Group() # world class (handles all data for the "world") class World(): def __init__(self, data): self.tile_list = [] self.bg_x = 0 # load in ground tile image ground_img = pygame.image.load('img/tile/0.png') # load tiles form world data row_count = 0 for row in data: col_count = 0 for tile in row: if tile == 0: img = pygame.transform.scale(ground_img, (TILE_SIZE, TILE_SIZE)) img_rect = img.get_rect() img_rect.x = col_count * TILE_SIZE img_rect.y = row_count * TILE_SIZE tile = (img, img_rect) self.tile_list.append(tile) if tile == 7: spike = Spike(col_count * TILE_SIZE, row_count * TILE_SIZE + 15) spike_group.add(spike) if tile == 10: doublespike = DoubleSpike(col_count * TILE_SIZE, row_count * TILE_SIZE + 15) doublespike_group.add(doublespike) col_count += 1 row_count += 1 # draw function to display tiles onto screen def draw(self): for tile in self.tile_list: adjusted_x = tile[1].x + self.bg_x screen.blit(tile[0], (adjusted_x, tile[1].y)) def update(self): global bg_x # scrolling background bg_x -= scroll_speed if bg_x <= -SCREEN_WIDTH: bg_x = 0 # cube class (handles everything for the player aka jumping, collisions etc) class Cube(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) self.image1 = pygame.image.load('img/cube/1.png') self.image2 = pygame.image.load('img/cube/2.png') self.image_dead = pygame.image.load('img/cube/dead.png') self.image1 = pygame.transform.scale(self.image1, (TILE_SIZE, TILE_SIZE)) self.image2 = pygame.transform.scale(self.image2, (TILE_SIZE, TILE_SIZE)) self.image_dead = pygame.transform.scale(self.image_dead, (TILE_SIZE, TILE_SIZE)) self.image = self.image1 self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.y_velocity = 0 self.on_ground = False self.dead = 0 # update function for the cube (handles the cube's position and state) def update(self): if self.dead == 0: # gravity physics implimentation self.y_velocity += GRAVITY self.rect.y += self.y_velocity # checks for ground collision self.on_ground = False for tile in world.tile_list: if self.rect.colliderect(tile[1]) and self.y_velocity > 0: self.rect.bottom = tile[1].top self.y_velocity = 0 self.on_ground = True self.image = self.image1 # changes back to the original image once landed break # check for spike collision if pygame.sprite.spritecollide(self, spike_group, False) or pygame.sprite.spritecollide(self, doublespike_group, False): self.dead = 1 # set player as "dead" self.image = self.image_dead # jumping function for cube def jump(self): if self.on_ground and self.dead == 0: self.y_velocity = JUMP_POWER self.image = self.image2 # Change to the jumping image # class to handle spikes class Spike(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/spikes/1.png') self.image = pygame.transform.scale(img, (TILE_SIZE, TILE_SIZE // 2)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y # class to handle double spikes class DoubleSpike(pygame.sprite.Sprite): def __init__(self, x, y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/spikes/4.png') self.image = pygame.transform.scale(img, (TILE_SIZE, TILE_SIZE // 2)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y # load level data from the csv file def load_level_data(level): if path.exists(f'level_data{level}.csv'): world_data = [] with open(f'level_data{level}.csv', mode='r') as file: reader = csv.reader(file) for row in reader: # convert the CSV row back to the appropriate data types world_data.append([int(item) for item in row]) else: world_data = [[]] # Create an empty list if no world data is found return world_data world_data = load_level_data(level) world = World(world_data) # create the player as an instance of the cube class player = Cube(100, 400) # main game loop run = True while run: # frame rate clock.tick(fps) # event handler for event in pygame.event.get(): if event.type == pygame.QUIT: run = False if event.type == pygame.KEYDOWN: if event.key == pygame.K_SPACE: # space to jump player.jump() # scroll background bg_x -= scroll_speed if bg_x <= -SCREEN_WIDTH: bg_x = 0 # draw background images screen.blit(bg_img, (bg_x, 0)) screen.blit(bg_img, (bg_x + SCREEN_WIDTH, 0)) # update + draw player and world player.update() world.update() world.bg_x = bg_x world.draw() screen.blit(player.image, player.rect.topleft) # draw spikes spike_group.draw(screen) doublespike_group.draw(screen) # update the display pygame.display.update() # quit pygame pygame.quit()