""" --------------------------------------------- Project: Dungeon Run Standard: School: Tauranga Boys College Author: Aidan Plummer Date: May 2025 Python: 3.11.9 --------------------------------------------- """ # 1:54:10 import pygame import sys from time import sleep from pytmx.util_pygame import load_pygame class Tile(pygame.sprite.Sprite): # Sprite class to handle tiles def __init__(self,pos,surf,groups, fov, alpha=None): super().__init__(groups) new_size = (int(surf.get_width() * fov), int(surf.get_height() * fov)) self.image = pygame.transform.scale(surf, new_size) new_pos = (int(pos[0] * fov), int(pos[1] * fov)) self.rect = self.image.get_rect(topleft = new_pos) if alpha is not None: self.image.set_alpha(alpha) class Player(pygame.sprite.Sprite): def __init__(self, pos, groups, speed, collision_group, debug=False): super().__init__(groups) self.debug = debug raw_image = pygame.image.load("assets/BlueWizard/2BlueWizardIdle/Chara - BlueIdle00000.png") self.image = pygame.transform.scale(raw_image, (200, 200)) # Scales the image down self.rect = self.image.get_rect(center=pos) # set image rect self.rect = pygame.Rect(0, 0, 60, 110) # Changes the hitbox size self.rect.center = pos self.image_rect = self.image.get_rect(midbottom=self.rect.midbottom) self.image_offset_y = 65 # Changes the y offset of the image (not the collision hitbox) self.image_rect.y += self.image_offset_y self.speed = speed self.velocity_y = 0 self.gravity = 1.5 self.jump_strength = 25 self.on_ground = False self.collision_group = collision_group self.idleAnims = "assets/BlueWizard/2BlueWizardIdle" def update(self): # Scroll camera if player is past screen boundaries if player.rect.centerx - camera_offset.x < LEFT_SCROLL_BOUNDARY: camera_offset.x = player.rect.centerx - LEFT_SCROLL_BOUNDARY elif player.rect.centerx - camera_offset.x > RIGHT_SCROLL_BOUNDARY: camera_offset.x = player.rect.centerx - RIGHT_SCROLL_BOUNDARY keys = pygame.key.get_pressed() if keys[pygame.K_a] or keys[pygame.K_LEFT]: self.rect.x -= self.speed # checks for collision on the left side collided_tiles = pygame.sprite.spritecollide(self, self.collision_group, False) for tile in collided_tiles: if self.rect.colliderect(tile.rect): self.rect.left = tile.rect.right break # if not keys[pygame.K_a] or keys[pygame.K_LEFT] or keys[pygame.K_d] or keys[pygame.K_RIGHT]: if keys[pygame.K_d] or keys[pygame.K_RIGHT]: self.rect.x += self.speed # checks for collision on the right side collided_tiles = pygame.sprite.spritecollide(self, self.collision_group, False) for tile in collided_tiles: if self.rect.colliderect(tile.rect): self.rect.right = tile.rect.left break # Handles jumping if self.on_ground and (keys[pygame.K_SPACE] or keys[pygame.K_w] or keys[pygame.K_UP]): self.velocity_y = -self.jump_strength self.on_ground = False self.velocity_y += self.gravity self.rect.y += self.velocity_y collided_tiles = pygame.sprite.spritecollide(self, self.collision_group, False) if self.debug: print(f"Player Y: {self.rect.y}, Player X: {self.rect.x}, VelY: {self.velocity_y}, Collisions: {len(collided_tiles)}") if collided_tiles: # Detect when player touches layers that are set in collided_tiles sprite group for tile in collided_tiles: if self.velocity_y > 0: self.rect.bottom = tile.rect.top self.velocity_y = 0 self.on_ground = True break elif self.velocity_y < 0: self.rect.top = tile.rect.bottom self.velocity_y = 0 else: self.on_ground = False self.image_rect.midbottom = self.rect.midbottom self.image_rect.y += self.image_offset_y if self.debug: pygame.draw.rect(display, (255,255,255), self.rect, 2) # Visualizes hitbox pygame.init() clock = pygame.time.Clock() # Essential Variables screen_width = 350*3 screen_height = 250*3 LEFT_SCROLL_BOUNDARY = screen_width // 3 RIGHT_SCROLL_BOUNDARY = screen_width * 2 // 3 fov = 0.25 # How much the camera is zoomed out, smaller = zoom in, larger = zoom out fps = 60 camera_offset = pygame.Vector2(0, 0) display = pygame.display.set_mode((screen_width,screen_height)) pygame.display.set_caption("CaveQuest") tmx_data = load_pygame('map.tmx') # Loads the tiled map sprite_group = pygame.sprite.Group() foreground_group = pygame.sprite.Group() main_group = pygame.sprite.Group() background_group = pygame.sprite.Group() collision_group = pygame.sprite.Group() for obj in tmx_data.objects: # Finds objects (a special type of tyle in tiled) and renders them pos = obj.x, obj.y if obj.image: Tile(pos = pos, surf = obj.image, groups = sprite_group, fov=fov) # Cycle through all layers for layer in tmx_data.visible_layers: if hasattr(layer,'data'): for x,y,surf in layer.tiles(): pos = x * 256, y * 256 if layer.name == "BackgroundLevel": # Checks if tile is part of this layer and passes arguments based on that, alpha = transparency alpha=128 Tile(pos = pos, surf = surf, groups = background_group, fov=fov, alpha=alpha) if layer.name == "MainLayer": alpha=None Tile(pos = pos, surf = surf, groups = (collision_group, main_group), fov=fov, alpha=alpha) print("Loaded Level") # get all layers # print(tmx_data.layers) # for layer in tmx_data.visible_layers: # get visible layers # print(layer) # print(tmx_data.get_layer_by_name('FrontLayers')) # get one layer by name # for obj in tmx_data.objectgroups: # get object layers # print(obj) # Get Tiles #layer = tmx_data.get_layer_by_name('FrontLayers') # Background Images mushroomcavebg1 = pygame.image.load("assets/background\Mushroom_Cave_L1.png") mushroomcavebg1 = pygame.transform.scale(mushroomcavebg1, (screen_width,screen_height)) player = Player(pos=(500, 200), groups=sprite_group, speed=8, collision_group=collision_group, debug=True) # Player starting position and arguments while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() sprite_group.update() display.blit(mushroomcavebg1, (0, 0)) background_group.update() foreground_group.update() display.blit(player.image, player.image_rect.topleft - camera_offset) # Draws player on screen for sprite in background_group: display.blit(sprite.image, sprite.rect.topleft - camera_offset) for sprite in main_group: display.blit(sprite.image, sprite.rect.topleft - camera_offset) for sprite in foreground_group: display.blit(sprite.image, sprite.rect.topleft - camera_offset) pygame.display.update() clock.tick(fps)