import pygame from pygame.locals import * from pygame import mixer import pickle from os import path pygame.mixer.pre_init(44100, -16, 2, 512) mixer.init() pygame.init() #how fast things are traveling and how fast the code is running clock = pygame.time.Clock() fps = 60 #size of the screen screen_width = 1000 screen_height = 1000 #the screen display screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption('Minecraft 2d Platformer') #define font font = pygame.font.SysFont('Bauhaus 93', 70) font_score = pygame.font.SysFont('Bauhaus 93', 30) #define game variables tile_size = 50 game_over = 0 main_menu = True level = 1 max_levels = 7 score = 0 #define colors white = (255,255,255) #load images bg_img = pygame.image.load('img/background_nether.png') restart_img = pygame.image.load('img/respawn_button.png') start_img = pygame.image.load('img/singleplayer_button.png') exit_img = pygame.image.load('img/exit_game.png') minecraft_title = pygame.image.load('img/minecraft_title.png') #load sounds pygame.mixer.music.load('img/Rubedo.mp3') pygame.mixer.music.play(-1, 0.0, 5000) pygame.mixer.music.set_volume(1.0) goldcollect_fx = pygame.mixer.Sound('img/goldcollect.wav') goldcollect_fx.set_volume(5) jump_fx = pygame.mixer.Sound('img/jump.wav') jump_fx.set_volume(0.5) damage_fx = pygame.mixer.Sound('img/damage.wav') damage_fx.set_volume(0.5) #identifying the font and text def draw_text(text,font,text_col,x,y): img = font.render(text, True, text_col) screen.blit(img, (x, y)) #function to reset level def reset_level(level): player.reset(100, screen_height - 130) magma_group.empty() platform_group.empty() lava_group.empty() exit_group.empty() #load in level data and create world if path.exists(f'level{level}_data'): with open(f'level{level}_data', 'rb') as f: world_data = pickle.load(f) world = World(world_data) return world 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): action = False #get mouse pos pos = pygame.mouse.get_pos() #check mouseover and clicked conditions if self.rect.collidepoint(pos): if pygame.mouse.get_pressed()[0] == 1 and self.clicked == False: action = True self.clicked = True if pygame.mouse.get_pressed()[0] == 0: self.clicked = False #draw button screen.blit(self.image, self.rect) return action class Player(): def __init__(self,x,y): self.reset(x,y) def update(self, game_over): dx = 0 dy = 0 walk_cooldown = 7.5 col_thresh = 20 if game_over == 0: key = pygame.key.get_pressed() if key[pygame.K_SPACE] and self.jumped == False and self.in_air == False: # Jumping if in air jump_fx.play() #sound effect for jumping self.vel_y = -15 self.jumped = True if key[pygame.K_SPACE] == False: #jumping key self.jumped = False if key[pygame.K_LEFT]:#walk left key dx -= 5 self.counter += 1 self.direction = -1 if key[pygame.K_RIGHT]:# walk right key dx += 5 self.counter += 1 self.direction = 1 if key[pygame.K_LEFT] == False and key[pygame.K_RIGHT] == False: #standing still self.counter = 0 self.index = 0 if self.direction == 1: #direction of the images for the character self.image = self.images_right[self.index] if self.direction == -1: self.image = self.images_left[self.index] if self.counter > walk_cooldown: self.counter = 0 self.index += 1 if self.index >= len(self.images_right): self.index = 0 if self.direction == 1: self.image = self.images_right[self.index] if self.direction == -1: self.image = self.images_left[self.index] self.vel_y += 1 if self.vel_y > 10: self.vel_y = 10 dy += self.vel_y #collision self.in_air = True for tile in world.tile_list: #check for collision in x direction if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 #check for collision in y direction if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): #check if bellow the ground i.e jumping if self.vel_y < 0: dy = tile[1].bottom - self.rect.top self.vel_y = 0 #check if above the ground i.e falling elif self.vel_y >= 0: dy = tile[1].top - self.rect.bottom self.vel_y = 0 self.in_air = False #check collsion for enemies if pygame.sprite.spritecollide(self, magma_group, False): game_over = -1 damage_fx.play() #check collsion for lava if pygame.sprite.spritecollide(self, lava_group, False): game_over = -1 damage_fx.play() #check collsion for exit if pygame.sprite.spritecollide(self, exit_group, False): game_over = 1 #check for collision with platforms for platform in platform_group: #collision in the x direction if platform.rect.colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 #collision in the y direction if platform.rect.colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): #check if below platform if abs((self.rect.top + dy) - platform.rect.bottom) < col_thresh: self.vel_y = 0 dy = platform.rect.bottom - self.rect.top #check if above platform elif abs((self.rect.bottom + dy) - platform.rect.top) < col_thresh: self.rect.bottom = platform.rect.top - 1 self.in_air = False dy = 0 #move sideways with the platform if platform.move_x != 0: self.rect.x += platform.move_direction self.rect.x += dx self.rect.y += dy #"You died" screen elif game_over == -1: self.image = self.dead_image draw_text('You Died!', font, white, (screen_width // 2) - 125, screen_height // 2 ) if self.rect.y > 200: self.rect.y -= 5 screen.blit(self.image, self.rect) return game_over #player and ghost animations def reset(self,x,y): self.images_right = [] self.images_left = [] self.index = 0 self.counter = 0 for num in range(1, 3): img_right = pygame.image.load(f'img/steve{num}.png') # player images img_right = pygame.transform.scale(img_right, (40,90)) # player hitbox img_left = pygame.transform.flip(img_right, True, False) #if the player turns left, it will face left self.images_right.append(img_right) self.images_left.append(img_left) dead_image = pygame.image.load('img/smoke.png') # image for ghost/Ghast self.dead_image = pygame.transform.scale(dead_image, (64, 128)) self.image = self.images_right[self.index] self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y self.width = self.image.get_width() self.height = self.image.get_height() self.vel_y = 0 self.jumped = False self.direction = 0 self.in_air = True class World(): def __init__(self,data): self.tile_list = [] dirt_img = pygame.image.load('img/netherack.png') #image for netherack/dirt grass_img = pygame.image.load('img/warped_grass.png') #image for warped grass/grass row_count = 0 for row in data: col_count = 0 for tile in row: if tile ==1: img = pygame.transform.scale(dirt_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 ==2: img = pygame.transform.scale(grass_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 == 3: # identifying the tile for the magma enemies magma = Magma(col_count * tile_size, row_count * tile_size + 15) magma_group.add(magma) if tile == 4: # identifying the tile for the slab platforms platform = Platform(col_count * tile_size, row_count * tile_size, 1, 0) platform_group.add(platform) if tile == 5: platform = Platform(col_count * tile_size, row_count * tile_size, 0, 1) platform_group.add(platform) if tile == 6: # identifying the tile for the lava lava = Lava(col_count * tile_size, row_count * tile_size + (tile_size // 2)) lava_group.add(lava) if tile == 7: # identifying the tile for the coins/gold coin = Coin(col_count * tile_size + (tile_size // 2), row_count * tile_size + (tile_size // 2)) coin_group.add(coin) if tile == 8: # identifying the tile for the exit/portal exit = Exit(col_count * tile_size, row_count * tile_size - (tile_size // 2)) exit_group.add(exit) col_count += 1 row_count += 1 def draw(self): for tile in self.tile_list: screen.blit(tile[0], tile[1]) #classes for every moving object and evey object colliding with the player class Magma(pygame.sprite.Sprite): #magma class def __init__(self,x,y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/magma.png') self.image = pygame.transform.scale(img, (tile_size, tile_size)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y - 15 self.move_direction = 1 self.move_counter = 0 def update(self): self.rect.x += self.move_direction self.move_counter += 1 if abs(self.move_counter) > 50: self.move_direction *= -1 self.move_counter *= -1 class Platform(pygame.sprite.Sprite): #platform class def __init__(self,x,y, move_x, move_y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/slab.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 self.move_counter = 0 self.move_direction = 1 self.move_x = move_x self.move_y = move_y def update(self): self.rect.x += self.move_direction * self.move_x self.rect.y += self.move_direction * self.move_y self.move_counter += 1 if abs(self.move_counter) > 50: self.move_direction *= -1 self.move_counter *= -1 class Lava(pygame.sprite.Sprite): #lava class def __init__(self,x,y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/lava.png') self.image = pygame.transform.scale(img, (tile_size, tile_size)) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y class Coin(pygame.sprite.Sprite): #gold/coin class def __init__(self,x,y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/gold.png') self.image = pygame.transform.scale(img, (tile_size // 2, tile_size // 2)) self.rect = self.image.get_rect() self.rect.center = (x,y) class Exit(pygame.sprite.Sprite): #exit/portal class def __init__(self,x,y): pygame.sprite.Sprite.__init__(self) img = pygame.image.load('img/portal.png') self.image = pygame.transform.scale(img, (tile_size, int(tile_size * 1.5))) self.rect = self.image.get_rect() self.rect.x = x self.rect.y = y player = Player(100, screen_height - 130) magma_group = pygame.sprite.Group() #identifiying the magma and putting it in the game platform_group = pygame.sprite.Group() #identifiying the platform and putting it in the game lava_group = pygame.sprite.Group() #identifiying the lava and putting it in the game coin_group = pygame.sprite.Group() #identifiying the coin/gold and putting it in the game exit_group = pygame.sprite.Group() #identifiying the exit/portal and putting it in the game #create dummy coin for showing score score_coin = Coin(tile_size // 2, tile_size // 2) coin_group.add(score_coin) #load in level data and create world if path.exists(f'level{level}_data'): pickle_in = open(f'level{level}_data', 'rb') world_data = pickle.load(pickle_in) world = World(world_data) #create buttons restart_button = Button(screen_width // 2 - 200, screen_height // 2 + 100, restart_img) start_button = Button(screen_width // 2 - 400, screen_height // 2, start_img) exit_button = Button(screen_width // 2 + 50, screen_height // 2, exit_img) run = True while run: clock.tick(fps) screen.blit(bg_img, (0,0)) if main_menu == True: screen.blit(minecraft_title, (240, 150)) if exit_button.draw(): run = False if start_button.draw(): main_menu = False else: world.draw() if game_over == 0: magma_group.update() platform_group.update() #update score #check if coin is collected if pygame.sprite.spritecollide(player, coin_group, True): score += 1 goldcollect_fx.play() draw_text('X ' + str(score), font_score,white, tile_size - 10, 10) magma_group.draw(screen) platform_group.draw(screen) lava_group.draw(screen) coin_group.draw(screen) exit_group.draw(screen) game_over = player.update(game_over) #if player is dead if game_over == -1: if restart_button.draw(): world_data = [] world = reset_level(level) game_over = 0 score = 0 #if player has completed a level if game_over == 1: #reset game and go to next level level += 1 if level <= max_levels: #reset level world_data = [] world = reset_level(level) game_over = 0 else: draw_text('YOU WIN!', font, white, (screen_width // 2) - 125, screen_height // 2) if restart_button.draw(): level = 1 world_data = [] world = reset_level(level) game_over = 0 score = 0 for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.display.update() pygame.quit()