diff --git a/code/button.py b/code/button.py index 8ee3554..c69ef78 100644 --- a/code/button.py +++ b/code/button.py @@ -1,28 +1,29 @@ -import pygame - - -class Button(): - def __init__(self,x,y, image): - self.image = image - self.rect = self.image.get_rect() - self.rect.x = x - self.rect.y = y - self.clicked = False - - def draw(self, surface): - action = False - - # get mouse position - pos = pygame.mouse.get_pos() - - # check mouseover and clicked conditions - if self.rect.collidepoint(pos): - if pygame.mouse.get_pressed()[0] == 1: - action = True - self.clicked = True - if pygame.mouse.get_pressed()[0] == 0: - self.clicked = False - # draw button on screen - surface.blit(self.image, self.rect) - - return action \ No newline at end of file +import pygame + + +class Button(): + def __init__(self,x,y, image): + self.image = image + self.rect = self.image.get_rect() + self.rect.x = x + self.rect.y = y + self.clicked = False + + def draw(self, surface): + action = False + + # get mouse position + pos = pygame.mouse.get_pos() + self.clicked = False + + # check mouseover and clicked conditions + if self.rect.collidepoint(pos): + if pygame.mouse.get_pressed()[0] == 1: + action = True + self.clicked = True + if pygame.mouse.get_pressed()[0] == 0: + self.clicked = False + # draw button on screen + surface.blit(self.image, self.rect) + + return action diff --git a/code/level.py b/code/level.py index 40b8ab6..062975b 100644 --- a/code/level.py +++ b/code/level.py @@ -1,6 +1,6 @@ import pygame from tiles import Tile -from settings import tile_size, screen_width, level_map2 +from settings import tile_size, screen_width, level_map, level_map2, screen_height from player import Player from enemies import Enemy from Door import Door @@ -99,9 +99,9 @@ def check_door_collision(self): if pygame.sprite.collide_rect(player, door): keys = pygame.key.get_pressed() if keys[pygame.K_SPACE]: - self.change_level() # Change the level when the player interacts with the door - - def change_level(self): + self.change_level(level_map2) # Change the level when the player interacts with the door + + def change_level(self, level=level_map): # Clear all sprite groups self.tiles.empty() self.player.empty() @@ -109,22 +109,23 @@ def change_level(self): self.doors.empty() # Load the new level data - self.setup_level(level_map2) - + self.setup_level(level) + def vertical_enemy_collision(self): - for enemy in self.enemies.sprites(): - temp_rect = enemy.rect.copy() - temp_rect.y += 1 - flag = False - for sprite in self.tiles.sprites(): - if sprite.rect.colliderect(temp_rect): - enemy.on_ground = True - flag = True - if not flag: - if enemy.direction.x < 0: - enemy.direction.x = 1 - elif enemy.direction.x > 0: - enemy.direction.x = -1 + pass + # for enemy in self.enemies.sprites(): + # temp_rect = enemy.rect.copy() + # temp_rect.y += 1 + # flag = False + # for sprite in self.tiles.sprites(): + # if sprite.rect.colliderect(temp_rect): + # enemy.on_ground = True + # flag = True + # if not flag: + # if enemy.direction.x < 0: + # enemy.direction.x = 1 + # elif enemy.direction.x > 0: + # enemy.direction.x = -1 def horizontal_movement_collision(self): @@ -134,11 +135,11 @@ def horizontal_movement_collision(self): #merging knock back, wall collision and invisble frames for enemy in self.enemies.sprites(): for sprite in self.tiles.sprites(): - if enemy.rect.colliderect(player.rect) and not player.is_invincible: + if enemy.rect.colliderect(player.rect) and not player.is_invincible and player.state != 'attack': + - # check if player is on the left of enemy or right and knock in that direction - if player.rect.left >= enemy.rect.left: + if player.rect.left >= enemy.rect.left: #player.direction.x = 1 #player.direction.y = -15 #player.rect.x += player.direction.x * player.speed * 2 @@ -151,7 +152,7 @@ def horizontal_movement_collision(self): elif enemy.direction.x > 0: enemy.direction.x = -1 - + elif player.rect.left <= enemy.rect.left: #player.direction.x = -1 #player.direction.y = -15 @@ -165,7 +166,9 @@ def horizontal_movement_collision(self): player.jump() player.on_ground = False - # check collision with the wall + # check collision with the wall + if enemy.rect.colliderect(player.rect) and not player.is_invincible and player.state == 'attack' and player.direction.x != enemy.direction.x: + enemy.kill() if sprite.rect.colliderect(player.rect) and sprite != self.doors.sprite: if player.direction.x < 0: player.rect.left = sprite.rect.right @@ -174,7 +177,7 @@ def horizontal_movement_collision(self): player.rect.right = sprite.rect.left self.world_shift = 0 - + def vertical_movement_collision(self): player = self.player.sprite player.apply_gravity() @@ -182,23 +185,32 @@ def vertical_movement_collision(self): #merging vertical knock back, wall collision and invislbe frames for enemy in self.enemies.sprites(): for sprite in self.tiles.sprites(): - if enemy.rect.colliderect(player.rect) and not player.is_invincible: - if player.rect.left <= enemy.rect.left: + if enemy.rect.colliderect(player.rect) and not player.is_invincible and player.state != 'jumpAttack': + if player.rect.left < enemy.rect.left: #player.direction.y = -15 player.is_attacked(-1) if enemy.direction.x < 0: enemy.direction.x = 1 elif enemy.direction.x > 0: enemy.direction.x = -1 - elif player.rect.left >= enemy.rect.left: + elif player.rect.left > enemy.rect.left: #player.direction.y = -15 player.is_attacked(1) if enemy.direction.x < 0: enemy.direction.x = 1 elif enemy.direction.x > 0: enemy.direction.x = -1 + else: + player.is_attacked(player.direction.x) + if enemy.direction.x < 0: + enemy.direction.x = 1 + elif enemy.direction.x > 0: + enemy.direction.x = -1 + player.jump() - player.on_ground = False + player.on_ground = False + if enemy.rect.colliderect(player.rect) and not player.is_invincible and player.state == 'jumpAttack': + enemy.kill() if sprite.rect.colliderect(player.rect): if player.direction.y > 0: player.rect.bottom = sprite.rect.top @@ -219,7 +231,7 @@ def run(self): # Doors self.doors.draw(self.display_surface) self.doors.update(self.world_shift) - + # Player self.player.update() self.scroll_x() # scroll_x before horizontal_movement_collision for moving screen @@ -234,3 +246,8 @@ def run(self): self.horizontal_enemy_collision() self.enemies.update(self.world_shift) self.enemies.draw(self.display_surface) + + def check_player(self): + if self.player.sprite.current_health == 0 or (self.player.sprite.rect.left < 0 or self.player.sprite.rect.right > screen_width) or (self.player.sprite.rect.bottom > screen_height or self.player.sprite.rect.bottom < -64): + return 0 + return 1 diff --git a/code/main.py b/code/main.py index 1cd69c3..dd566ba 100644 --- a/code/main.py +++ b/code/main.py @@ -5,41 +5,73 @@ from button import Button from os import path +class Main: + # Pygame setup -pygame.init() -screen = pygame.display.set_mode((screen_width,screen_height)) -clock = pygame.time.Clock() -level = Level(level_map, screen) -main_menu = True -start_img = pygame.image.load(path.join(base_path , 'buttons', 'start-1.png')).convert_alpha() -exit_img= pygame.image.load(path.join(base_path, 'buttons','exit-1.png')).convert_alpha() -start_button = Button(screen_width//2 - start_img.get_width()//2, 200, start_img) -exit_button = Button(screen_width//2 - exit_img.get_width()//2, 400, exit_img) -pygame.display.set_caption("2D Platformer Game") - -while True: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - pygame.quit() - sys.exit() - - background = pygame.image.load(path.join(base_path, 'bg.png')).convert() - background = pygame.transform.smoothscale(background, screen.get_size()) - screen.blit(background, (0, 0)) - - if start_button.clicked: - main_menu = False - - if exit_button.clicked: - pygame.quit() - sys.exit() - - if main_menu == True: - start_button.draw(screen) - exit_button.draw(screen) - else: - level.run() - - - pygame.display.update() - clock.tick(clock_tick) + def __init__(self): + pygame.init() + self.screen = pygame.display.set_mode((screen_width, screen_height)) + self.clock = pygame.time.Clock() + self.level = Level(level_map, self.screen) + self.main_menu = True + self.start_img = pygame.image.load(path.join(base_path, 'buttons', 'start-1.png')).convert_alpha() + self.exit_img = pygame.image.load(path.join(base_path, 'buttons', 'exit-1.png')).convert_alpha() + self.menu_img = pygame.image.load(path.join(base_path, 'title.png')).convert_alpha() + + self.menu_background_img = pygame.transform.scale(pygame.image.load(path.join(base_path, 'sky1.png')).convert(), self.screen.get_size()) + self.game_background_img = pygame.transform.scale(pygame.image.load(path.join(base_path, 'bg.png')).convert(), self.screen.get_size()) + + self.start_button = Button(screen_width//2 - self.start_img.get_width()//2, 500, self.start_img) + self.exit_button = Button(screen_width//2 - self.exit_img.get_width()//2, 600, self.exit_img) + pygame.display.set_caption("2D Platformer Game") + + + def run(self): + while True: + for event in pygame.event.get(): + if event.type == pygame.QUIT: + pygame.quit() + sys.exit() + + self.screen.fill((0, 0, 0)) # Clear the screen with black before drawing anything + + # Check if the game is in the main menu state + if self.main_menu: + # Load the main menu background image + background_img = self.menu_background_img + else: + # Resize the background image to match the screen size + background_img = self.game_background_img + + # Blit the background image onto the screen + self.screen.blit(background_img, (0, 0)) + + # Handle game logic based on the current state + if not self.main_menu: + self.level.run() + if not self.level.check_player(): + self.main_menu = True + self.level.change_level(level_map) + + if self.main_menu: + # Draw the main menu buttons + self.screen.blit(self.menu_img, (screen_width//2 - self.menu_img.get_width()//2, 50)) + self.start_button.draw(self.screen) + self.exit_button.draw(self.screen) + + if self.start_button.clicked: + self.main_menu = False + + if self.exit_button.clicked: + return 2 + else: + self.level.run() + + pygame.display.update() + self.clock.tick(clock_tick) + +if __name__ == '__main__': + main = Main() + out = 0 + while out != 2: + out = main.run() diff --git a/code/player.py b/code/player.py index b4a31ff..8072ca7 100644 --- a/code/player.py +++ b/code/player.py @@ -27,6 +27,8 @@ def __init__(self, pos): self.gravity = 0.8 self.jump_speed = -14 + self.player_dead = False + # Jumping and ground state self.jump_count = 0 self.on_ground = False @@ -62,8 +64,9 @@ def import_character_assets(self,size:(int,int)): def deplete_health(self, amount=1): self.current_health -= amount - if self.current_health < 0: + if self.current_health <= 0: self.current_health = 0 + self.player_death() def display_health(self, surface): """Displays the player's health on the given surface.""" @@ -85,14 +88,16 @@ def animate(self): if self.state == 'dead': self.frame_index = len(animation) - 1 elif self.state == 'attack' or self.state == 'jumpAttack': - self.is_attacking = False + self.is_attacking = True self.state = 'idle' else: + self.is_attacking = False self.frame_index = 0 + # Flip the image based on the direction image = animation[int(self.frame_index)%len(animation)] - if self.is_invincible: + if self.is_invincible: # if player is invincible then make every alternate frame blank if (int(self.frame_index)%len(animation)) % 2 == 0: image = pygame.mask.from_surface(image).to_surface() image.set_colorkey((0,0,0)) @@ -107,6 +112,7 @@ def update_state(self): self.attacked_c = 0 # checking if the player has already been knocked back then no need to knock back further. if self.is_attacking: + #self.direction.x = 0 return elif self.direction.x > 0: self.facing_right = True @@ -145,16 +151,32 @@ def is_attacked(self,dir=0): self.is_invincible = True self.attacked_dir = dir self.attacked_c = 1 - self.current_health -= 1 + self.deplete_health() + #self.jump() def get_input(self): - if self.is_attacking: - self.direction.x = 0 - return keys = pygame.key.get_pressed() mouse_buttons = pygame.mouse.get_pressed() + if self.is_attacking: + # if keys[pygame.K_RIGHT] or keys[pygame.K_d]: + # self.direction.x = 1 + # elif keys[pygame.K_LEFT] or keys[pygame.K_a]: + # self.direction.x = -1 + # #self.direction.x = 0 + # else: + #self.direction.x = 0 + if keys[pygame.K_UP] or keys[pygame.K_w] or keys[pygame.K_SPACE]: + if not self.jump_key_pressed: + self.jump() + self.jump_key_pressed = True + else: + self.jump_key_pressed = False + else: + self.direction.x = 0 + return + if keys[pygame.K_RIGHT] or keys[pygame.K_d]: self.direction.x = 1 elif keys[pygame.K_LEFT] or keys[pygame.K_a]: @@ -162,6 +184,7 @@ def get_input(self): else: self.direction.x = 0 + # force the player to move in the dirction of the kock back. if self.is_invincible and not self.on_ground and self.attacked_c: self.direction.x = self.attacked_dir @@ -175,11 +198,26 @@ def get_input(self): # Check for attack input (left mouse click or 'F' key) if mouse_buttons[0] or keys[pygame.K_f]: - self.attack() + #self.attack() + if self.on_ground: + self.state = 'attack' + else: + self.state = 'jumpAttack' + self.frame_index = 0 + self.is_attacking = True + + else: + self.is_attacking = False + + def player_death(self): + self.player_dead = True + self.state = 'dead' + self.frame_index = 0 + def attack(self): if not self.is_attacking: - self.is_attacking = True + #self.is_attacking = True if self.on_ground: self.state = 'attack' else: @@ -201,6 +239,7 @@ def jump(self,wind=0): def update(self): - self.get_input() - self.update_state() + if not self.player_dead: + self.get_input() + self.update_state() self.animate() diff --git a/code/settings.py b/code/settings.py index 401dd17..e5ff6c0 100644 --- a/code/settings.py +++ b/code/settings.py @@ -44,6 +44,7 @@ ] base_path = path.join(path.dirname(__file__), '..', 'graphics') +#base_path = "C:\\Users\\Dhruv\\Desktop\\workshop\\Platformer_Game_DeCoded\\graphics\\" tile_types = { 'T': path.join(base_path, 'Tiles', 'grassMid.png'), @@ -60,7 +61,7 @@ def import_folder(path_to_folder): surf_lst = [] for _,_,img_files in walk(path_to_folder): - for img in img_files: + for img in img_files: full_path = path.join(path_to_folder, img) img_surf = pygame.image.load(full_path).convert_alpha() surf_lst.append(img_surf) diff --git a/graphics/Title.PNG b/graphics/Title.PNG new file mode 100644 index 0000000..8bf9227 Binary files /dev/null and b/graphics/Title.PNG differ diff --git a/graphics/bg.png b/graphics/bg.png index 4e47906..4cc269b 100644 Binary files a/graphics/bg.png and b/graphics/bg.png differ diff --git a/graphics/bg1.png b/graphics/bg1.png new file mode 100644 index 0000000..1fec105 Binary files /dev/null and b/graphics/bg1.png differ diff --git a/graphics/sky1.png b/graphics/sky1.png new file mode 100644 index 0000000..b2b6dd1 Binary files /dev/null and b/graphics/sky1.png differ diff --git a/graphics/title.png b/graphics/title.png new file mode 100644 index 0000000..8bf9227 Binary files /dev/null and b/graphics/title.png differ