import pygame import os import random import csv import button pygame.init() SCREEN_WIDTH = 800 SCREEN_HEIGHT = int(SCREEN_WIDTH * 0.8) screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption('Shooter') #set framerate clock = pygame.time.Clock() FPS = 60 #define game variables GRAVITY = 0.75 SCROLL_THRESH = 200 ROWS = 16 COLS = 150 TILE_SIZE = SCREEN_HEIGHT // ROWS TILE_TYPES = 21 MAX_LEVELS = 3 screen_scroll = 0 bg_scroll = 0 level = 1 start_game = False #define player action variables moving_left = False moving_right = False shoot = False grenade = False grenade_thrown = False #load images #character images img_list #button images start_img = pygame.image.load('img/start_btn.png').convert_alpha() exit_img = pygame.image.load('img/exit_btn.png').convert_alpha() restart_img = pygame.image.load('img/restart_btn.png').convert_alpha() #background pine1_img = pygame.image.load('img/Background/pine1.png').convert_alpha() pine2_img = pygame.image.load('img/Background/pine2.png').convert_alpha() mountain_img = pygame.image.load('img/Background/mountain.png').convert_alpha() sky_img = pygame.image.load('img/Background/sky_cloud.png').convert_alpha() #store tiles in a list for x in range(TILE_TYPES): img = pygame.image.load(f'img/Tile/{x}.png') img = pygame.transform.scale(img, (TILE_SIZE, TILE_SIZE)) img_list.append(img) #bullet bullet_img = pygame.image.load('img/icons/bullet.png').convert_alpha() #define colours BG = (144, 201, 120) RED = (255, 0, 0) WHITE = (255, 255, 255) GREEN = (0, 255, 0) BLACK = (0, 0, 0) #define font font = pygame.font.SysFont('Futura', 30) #text function def draw_text(text, font, text_col, x, y): img = font.render(text, True, text_col) screen.blit(img, (x, y)) def draw_bg(): screen.fill(BG) width = sky_img.get_width() for x in range(5): screen.blit(sky_img, ((x * width) - bg_scroll * 0.5, 0)) screen.blit(mountain_img, ((x * width) - bg_scroll * 0.6, SCREEN_HEIGHT - mountain_img.get_height() - 300)) screen.blit(pine1_img, ((x * width) - bg_scroll * 0.7, SCREEN_HEIGHT - pine1_img.get_height() - 150)) screen.blit(pine2_img, ((x * width) - bg_scroll * 0.8, SCREEN_HEIGHT - pine2_img.get_height())) #function to reset level def reset_level(): enemy_group.empty() bullet_group.empty() decoration_group.empty() water_group.empty() exit_group.empty() #create empty tile list data = [] for row in range(ROWS): r = [-1] * COLS data.append(r) return data #THE ANNOYING ENEMY DATA class Soldier(pygame.sprite.Sprite): def __init__(self, char_type, x, y, scale, speed, ammo, grenades): pygame.sprite.Sprite.__init__(self) self.alive = True self.char_type = char_type self.speed = speed self.ammo = ammo self.start_ammo = ammo self.shoot_cooldown = 0 self.health = 40 self.max_health = self.health self.direction = 1 self.vel_y = 0 self.jump = False self.in_air = True self.flip = False self.animation_list = [] self.frame_index = 0 self.action = 0 self.update_time = pygame.time.get_ticks() #ai specific variables self.move_counter = 0 self.vision = pygame.Rect(0, 0, 150, 20) self.idling = False self.idling_counter = 0 #load all images for the players animation_types = ['Idle', 'Run', 'Jump', 'Death'] for animation in animation_types: #reset temporary list of images temp_list = [] #count number of files in the folder num_of_frames = len(os.listdir(f'img/{self.char_type}/{animation}')) for i in range(num_of_frames): img = pygame.image.load(f'img/{self.char_type}/{animation}/{i}.png').convert_alpha() img = pygame.transform.scale(img, (int(img.get_width() * scale), int(img.get_height() * scale))) temp_list.append(img) self.animation_list.append(temp_list) self.image = self.animation_list[self.action][self.frame_index] self.rect = self.image.get_rect() self.rect.center = (x, y) self.width = self.image.get_width() self.height = self.image.get_height() def update(self): self.update_animation() self.check_alive() #update cooldown if self.shoot_cooldown > 0: self.shoot_cooldown -= 1 def move(self, moving_left, moving_right): #reset movement variables screen_scroll = 0 dx = 0 dy = 0 #assign movement variables if moving left or right if moving_left: dx = -self.speed self.flip = True self.direction = -1 if moving_right: dx = self.speed self.flip = False self.direction = 1 #jump if self.jump == True and self.in_air == False: self.vel_y = -11 self.jump = False self.in_air = True #apply gravity self.vel_y += GRAVITY if self.vel_y > 10: self.vel_y dy += self.vel_y #check for collision for tile in world.obstacle_list: #check collision in the x direction if tile[1].colliderect(self.rect.x + dx, self.rect.y, self.width, self.height): dx = 0 #if the ai has hit a wall then make it turn around if self.char_type == 'enemy': self.direction *= -1 self.move_counter = 0 #check for collision in the y direction if tile[1].colliderect(self.rect.x, self.rect.y + dy, self.width, self.height): #check if below the ground, i.e. jumping if self.vel_y < 0: self.vel_y = 0 dy = tile[1].bottom - self.rect.top #check if above the ground, i.e. falling elif self.vel_y >= 0: self.vel_y = 0 self.in_air = False dy = tile[1].top - self.rect.bottom #check for collision with water if pygame.sprite.spritecollide(self, water_group, False): self.health = 0 #check for collision with exit level_complete = False if pygame.sprite.spritecollide(self, exit_group, False): level_complete = True #check if fallen off the map if self.rect.bottom > SCREEN_HEIGHT: self.health = 0 #check if going off the edges of the screen if self.char_type == 'player': if self.rect.left + dx < 0 or self.rect.right + dx > SCREEN_WIDTH: dx = 0 #update rectangle position self.rect.x += dx self.rect.y += dy #update scroll based on player position if self.char_type == 'player': if (self.rect.right > SCREEN_WIDTH - SCROLL_THRESH and bg_scroll < (world.level_length * TILE_SIZE) - SCREEN_WIDTH)\ or (self.rect.left < SCROLL_THRESH and bg_scroll > abs(dx)): self.rect.x -= dx screen_scroll = -dx return screen_scroll, level_complete def shoot(self): if self.shoot_cooldown == 0 and self.ammo > 0: self.shoot_cooldown = 20 bullet = Bullet(self.rect.centerx + (0.75 * self.rect.size[0] * self.direction), self.rect.centery, self.direction) bullet_group.add(bullet) #reduce ammo self.ammo -= 1 def ai(self): if self.alive and player.alive: if self.idling == False and random.randint(1, 200) == 1: self.update_action(0)#0: idle self.idling = True self.idling_counter = 50 #check if the ai in near the player if self.vision.colliderect(player.rect): #stop running and face the player self.update_action(0)#0: idle #shoot self.shoot() else: if self.idling == False: if self.direction == 1: ai_moving_right = True else: ai_moving_right = False ai_moving_left = not ai_moving_right self.move(ai_moving_left, ai_moving_right) self.update_action(1)#1: run self.move_counter += 1 #update ai vision as the enemy moves self.vision.center = (self.rect.centerx + 75 * self.direction, self.rect.centery) if self.move_counter > TILE_SIZE: self.direction *= -1 self.move_counter *= -1 else: self.idling_counter -= 1 if self.idling_counter <= 0: self.idling = False #scroll self.rect.x += screen_scroll def update_animation(self): #update animation ANIMATION_COOLDOWN = 100 #update image depending on current frame self.image = self.animation_list[self.action][self.frame_index] #check if enough time has passed since the last update if pygame.time.get_ticks() - self.update_time > ANIMATION_COOLDOWN: self.update_time = pygame.time.get_ticks() self.frame_index += 1 #if the animation has run out the reset back to the start if self.frame_index >= len(self.animation_list[self.action]): if self.action == 3: self.frame_index = len(self.animation_list[self.action]) - 1 else: self.frame_index = 0 def update_action(self, new_action): #check if the new action is different to the previous one if new_action != self.action: self.action = new_action #update the animation settings self.frame_index = 0 self.update_time = pygame.time.get_ticks() def check_alive(self): if self.health <= 0: self.health = 0 self.speed = 0 self.alive = False self.update_action(3) def draw(self): screen.blit(pygame.transform.flip(self.image, self.flip, False), self.rect) class World(): def __init__(self): self.obstacle_list = [] def process_data(self, data): self.level_length = len(data[0]) #iterate through each value in level data file for y, row in enumerate(data): for x, tile in enumerate(row): if tile >= 0: img = img_list[tile] img_rect = img.get_rect() img_rect.x = x * TILE_SIZE img_rect.y = y * TILE_SIZE tile_data = (img, img_rect) if tile >= 0 and tile <= 8: self.obstacle_list.append(tile_data) elif tile >= 9 and tile <= 10: water = Water(img, x * TILE_SIZE, y * TILE_SIZE) water_group.add(water) elif tile >= 11 and tile <= 14: decoration = Decoration(img, x * TILE_SIZE, y * TILE_SIZE) decoration_group.add(decoration) elif tile == 15:#create player player = Soldier('player', x * TILE_SIZE, y * TILE_SIZE, 1.65, 5, 20, 5) health_bar = HealthBar(10, 10, player.health, player.health) elif tile == 16:#create enemies enemy = Soldier('enemy', x * TILE_SIZE, y * TILE_SIZE, 1.65, 2, 20, 0) enemy_group.add(enemy) elif tile == 17:#create ammo box item_box = ItemBox('Ammo', x * TILE_SIZE, y * TILE_SIZE) item_box_group.add(item_box) elif tile == 18:#create grenade box item_box = ItemBox('Grenade', x * TILE_SIZE, y * TILE_SIZE) item_box_group.add(item_box) elif tile == 19:#create health box item_box = ItemBox('Health', x * TILE_SIZE, y * TILE_SIZE) item_box_group.add(item_box) elif tile == 20:#create exit exit = Exit(img, x * TILE_SIZE, y * TILE_SIZE) exit_group.add(exit) return player, health_bar def draw(self): for tile in self.obstacle_list: tile[1][0] += screen_scroll screen.blit(tile[0], tile[1])