def main(): pg.init() pg.font.init() screen = pg.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) pg.display.set_caption('My_game') clock = pg.time.Clock() # sprites img = load_image('player.png') Player.images = [img] img = load_image('player_shot.png') Player_shot.images = [img] img = load_image('enemy_new.png') Enemy.images = [img] # sounds crow_sound = load_sound('crow.wav') shot_sound = load_sound('shot.wav') shot_sound.set_volume(0.1) background = pg.Surface(SCREEN_RECT.size) background.fill(BACKGROUND_COLOR) screen.blit(background, (0, 0)) pg.display.flip() # Создание контейнеров all = pg.sprite.RenderUpdates() shots = pg.sprite.Group() enemies = pg.sprite.Group() # Присвоение контейнеров Player.containers = all Player_shot.containers = all, shots Enemy.containers = all, enemies player = Player() # Таймеры появлений объектов gun_timer = 0 enemy_spawn_timer = 0 crow_sound_timer = 0 score_delta = 0 score = Score() game_over = False def check_quit_keys(): for event in pg.event.get(): if event.type == QUIT or \ (event.type == KEYDOWN and event.key == K_ESCAPE): return True if pg.font: all.add(score) # initialiaing fonts pg.font.init() my_font = pg.font.SysFont('Comic Sans MS', 40) my_font_bot = pg.font.SysFont('Comic Sans MS', 20) text_over = my_font.render('Game over', False, (0, 0, 0)) text_score = my_font.render('Score: ' + str(score.score), False, (0, 0, 0)) instruction = my_font_bot.render('Press S to start a new game ', False, (0, 0, 0)) while player.alive(): if check_quit_keys(): break key_state = pg.key.get_pressed() horiz_direction = key_state[K_RIGHT] - key_state[K_LEFT] vert_direction = key_state[K_DOWN] - key_state[K_UP] player.move(horiz_direction, vert_direction) score_delta = 0 for shot in shots: enemies_hit_list = pg.sprite.spritecollide(shot, enemies, True) if len(enemies_hit_list) > 0: if crow_sound_timer <= 0: crow_sound.play() crow_sound_timer = Enemy.CROW_SOUND_COOLDOWN shot.kill() score_delta += len(enemies_hit_list) crow_sound_timer -= 1 if score_delta > 0: score.set_score_delta(score_delta) d = pg.sprite.spritecollide(player, enemies, True) if len(d) > 0: player.kill() text_score = my_font.render('Score: ' + str(score.score), False, (0, 0, 0)) game_over = True if key_state[K_x]: if gun_timer != 0: gun_timer = gun_timer - 1 else: Player_shot(player.get_guns()[0]) Player_shot(player.get_guns()[1]) shot_sound.play() gun_timer = Player_shot.GUN_RELOAD if enemy_spawn_timer != 0: enemy_spawn_timer = enemy_spawn_timer - 1 else: Enemy() enemy_spawn_timer = Enemy.SPAWN_COOLDOWN all.clear(screen, background) all.update() pg.display.update(all.draw(screen)) clock.tick(60) while game_over: if check_quit_keys(): break key_state = pg.key.get_pressed() if key_state[K_s]: main() break screen.blit(background, (0, 0)) screen.blit(text_over, (100, 0)) screen.blit(text_score, (125, 100)) screen.blit(instruction, (50, 600)) pg.display.update() clock.tick(60) pg.quit()
class Level(State): event_block_limit = 180 bonus_num = 100000 show_label_time = 300 amount_of_levels = 1 def __init__(self, level_num: int): super().__init__() self.players = pygame.sprite.Group() self.player_1: Player = pygame.sprite.Sprite() self.player_2: Player = pygame.sprite.Sprite() self.enemies = pygame.sprite.Group() self.enemy_hitboxes = pygame.sprite.Group() self.enemy_bullets = pygame.sprite.Group() self.boss: Enemy = pygame.sprite.Sprite() self.special_effects = pygame.sprite.Group() self.items = pygame.sprite.Group() self.controls: Dict[str, int] = {} self.event_block: bool = True # No moving at the start self.level_num: int = level_num self.background: Background = Background(self.level_num) self.enemy_spawn_dict: dict = MAPS[f"map{level_num}"] # This is used if the player wants to join midway through the game, or if they die. self.player_1_choose: bool = False self.player_1_choose_time: int = 60 * 20 # 20 seconds to choose self.player_2_choose: bool = False self.player_2_choose_time: int = 60 * 20 self.choice = {'1p': 0, '2p': 0} self.show_continue = False self.continue_time = 10 * 60 # 10 seconds to continue self.stage_clear = False self.show_label_timer = 0 self.stage_transition = StageTransition(level_num) self.hud = Hud(self) def startup(self, persist: dict): self.frame = 0 self.players.empty() self.enemies.empty() self.enemy_hitboxes.empty() self.enemy_bullets.empty() self.special_effects.empty() self.items.empty() self.boss = pygame.sprite.Sprite() self.done = False self.show_continue = False self.continue_time = 10 * 60 self.stage_transition = StageTransition(self.level_num) self.event_block = True self.stage_clear = True self.show_label_timer = 0 self.persist = persist self.controls = self.persist['controls'] # Guarantee will load self.coins = self.persist[ 'coins'] # no need to do try except because player had to insert coins to start # Player 1 if 'player_1' in self.persist: self.player_1 = self.persist['player_1'] if self.player_1.alive(): # If it's not just a base sprite # Reset position, hitbox and rect positions will be updated on next frame. self.player_1.pos = PVector(150, 700) self.player_1.game = self # Make sure it's spawning bullets, etc in the right game. self.players.add(self.player_1) # If the player just instantiated a character from select screen elif 'choice' in self.persist and self.persist['choice']['1p']: self.player_1 = Player(self, self.persist['choice']['1p'], PVector(150, 700)) else: # Just create a raw sprite for .alive() checking self.player_1 = pygame.sprite.Sprite() # Player 2 if 'player_2' in self.persist: self.player_2 = self.persist['player_2'] if self.player_2.alive(): # If it's not just a base sprite # Reset position, hitbox and rect positions will be updated on next frame. self.player_2.pos = PVector(150, 700) self.player_2.game = self # Make sure it's spawning bullets, etc in the right game. self.players.add(self.player_2) # If the player just instantiated a character from select screen elif 'choice' in self.persist and self.persist['choice']['2p']: self.player_2 = Player(self, self.persist['choice']['2p'], PVector(450, 700)) else: # Just create a raw sprite for .alive() checking self.player_2 = pygame.sprite.Sprite() self.set_music() def cleanup(self): persist = { 'controls': self.controls, 'coins': self.coins, 'player_1': self.player_1, 'player_2': self.player_2 } return persist def update(self): if self.frame == self.event_block_limit: self.event_block = False self.stage_transition.update() self.check_continue() if not self.show_continue: # Game frames should only continue when the players are playing, # otherwise, enemies will all spawn, and boss will spawn as well. # One problem that could occur is that boss spawns when player is selecting ship, however. To remedy this, # To remedy this, only advance frames if there is at least one player playing. # This can be checked with self.players. if self.stage_clear: self.stage_clear_effect() if self.players: self.frame += 1 self.player_choose_update() self.background.update() self.spawn_enemies( ) # Spawn enemies will not spawn duplicates when frame is frozen since key is deleted. self.players.update() self.enemies.update() self.items.update() self.special_effects.update() self.enemy_bullets.update() self.collision_check() else: pass self.hud.update() # Always update hud to show remaining time. def draw(self, surface: pygame.Surface): self.background.draw(surface) # This calls the draw function instead of just blitting image at rect position. [player.draw(surface) for player in self.players] self.enemies.draw(surface) self.enemy_bullets.draw(surface) self.special_effects.draw(surface) self.items.draw(surface) self.hud.draw(surface) self.stage_transition.draw(surface) def set_music(self): if self.level_num == 1: pygame.mixer.music.load(MUSIC['01_-_speedway_0']) elif self.level_num == 2: pygame.mixer.music.load(MUSIC['02_-_chip_beach_0']) elif self.level_num == 3: pygame.mixer.music.load(MUSIC['03_-_press_any_key_to_continue_0']) elif self.level_num == 4: pygame.mixer.music.load(MUSIC['04_-_i_want_more_candy_0']) elif self.level_num == 5: pygame.mixer.music.load(MUSIC['05_-_rain_island_0']) # pygame.mixer.music.play(-1) def spawn_enemies(self): if self.frame % 60 == 1: # enemy_dict[f'{randint(1,5)}'](self, PVector(randint(0, 600), 0)) # enemy_dict[f'{7}'](self, PVector(randint(0, 600), 1000)) pass enemies = self.enemy_spawn_dict.get(str(self.frame)) if enemies: for enemy in enemies: new_enemy = enemy_dict[enemy](self, PVector.from_tuple( enemies[enemy])) if 'Boss' in new_enemy.__class__.__name__: self.boss = new_enemy self.enemy_spawn_dict.pop(str(self.frame)) # This makes sure that the same enemy doesn't get spawned over and over again if the frame is frozen there. def collision_check(self): self.bullet_hit_enemy_check() self.player_hit_item_check() self.enemy_hit_player_check() #TODO TO REMOVE GODMODE def bullet_hit_enemy_check(self): for player in self.players: collide_dict = pygame.sprite.groupcollide(player.bullets, self.enemy_hitboxes, True, False) for bullet, enemies in collide_dict.items(): player.get_bullet_score() BulletExplosion(self, player.weapon_level, bullet.pos) for enemy in enemies: enemy.body.take_damage(bullet) # Remove laser if it is past impact point if isinstance(bullet, PlayerLaserBullet): # This is because homing bullets can take longer to hit something, # and when they do, may cut off laser. if player.weapon_2: for b in player.bullets: if b.pos.y < bullet.pos.y: b.kill() # if self.player_1.alive(): # collide_dict = pygame.sprite.groupcollide(self.player_1.bullets, self.enemy_hitboxes, True, False) # for bullet, enemies in collide_dict.items(): # self.player_1.get_bullet_score() # BulletExplosion(self, self.player_1.weapon_level, bullet.pos) # for enemy in enemies: # enemy.body.take_damage(bullet) # # Remove laser if it is past impact point # if self.player_1.weapon_2: # for b in self.player_1.bullets: # if b.pos.y < bullet.pos.y: # b.kill() # if self.player_2.alive(): # collide_dict = pygame.sprite.groupcollide(self.player_2.bullets, self.enemy_hitboxes, True, False) # for bullet, enemies in collide_dict.items(): # self.player_2.get_bullet_score() # BulletExplosion(self, self.player_2.weapon_level, bullet.pos) # for enemy in enemies: # enemy.body.take_damage(bullet) # # Remove laser if it is past impact point # if self.player_2.weapon_2: # for b in self.player_2.bullets: # if b.pos.y < bullet.pos.y: # b.kill() def player_hit_item_check(self): for player in self.players: if player.explosion: continue collide_dict = pygame.sprite.spritecollide(player, self.items, True) for item in collide_dict: item.apply_effect(player) def enemy_hit_player_check(self): for player in self.players: if pygame.sprite.spritecollideany( player.hitbox, self.enemy_hitboxes) or pygame.sprite.spritecollideany( player.hitbox, self.enemy_bullets, collided=pygame.sprite.collide_circle): if not player.invincible: player.explosion = True def player_choose_update(self): if self.player_1_choose: self.player_1_choose_time -= 1 if self.player_1_choose_time <= 0: self.player_1 = Player(self, self.choice['1p'], PVector(150, 700)) self.player_1_choose = False self.player_1_choose_time = 20 # Redundant since keyboard input also resets choose time if self.player_2_choose: self.player_2_choose_time -= 1 if self.player_2_choose_time <= 0: self.player_2 = Player(self, self.choice['2p'], PVector(450, 700)) self.player_2_choose = False self.player_2_choose_time = 20 # Redundant since keyboard input also resets choose time def check_continue(self): if not self.players and self.player_1_choose == self.player_2_choose == False: # If everyone's dead and no one is spawning self.show_continue = True self.continue_time -= 1 if self.continue_time <= 0: self.done = True self.next = 'GAME OVER' else: self.show_continue = False self.continue_time = 10 * 60 def stage_clear_effect(self): if self.player_1_choose: self.player_1 = Player(self, self.choice['1p'], PVector(150, 700)) self.player_1_choose = False self.player_1_choose_time = 20 * 60 if self.player_2_choose: self.player_2 = Player(self, self.choice['2p'], PVector(450, 700)) self.player_2_choose = False self.player_2_choose_time = 20 * 60 pygame.mixer.music.fadeout(500) if self.player_1.alive(): self.player_1.pos = PVector(150, 700) self.player_1.rect.center = tuple(self.player_1.pos) self.player_1.hitbox.rect.center = tuple(self.player_1.pos) self.player_1.direction = PVector(0, 0) self.player_1.bullets.empty() bonus = self.bonus_num * (self.player_1.lives + self.player_1.bomb_num) self.player_1.score += int(bonus / self.show_label_time) if self.player_2.alive(): self.player_2.pos = PVector(450, 700) self.player_2.rect.center = tuple(self.player_2.pos) self.player_2.hitbox.rect.center = tuple(self.player_2.pos) self.player_2.direction = PVector(0, 0) self.player_2.bullets.empty() bonus = self.bonus_num * (self.player_2.lives + self.player_2.bomb_num) self.player_2.score += int(bonus / self.show_label_time) self.show_label_timer += 1 self.event_block = True if self.show_label_timer >= self.show_label_time + 1: self.done = True self.next = f'LEVEL{self.level_num+1}' if self.level_num < self.amount_of_levels else 'GAME OVER' def event_process(self, events: List[pygame.event.Event]): if self.event_block: return # Don't take input if we are in stage transition territory keys = pygame.key.get_pressed() for event in events: if event.type == pygame.KEYDOWN: if event.key in { self.controls['1p_coin'], self.controls['2p_coin'] }: SFX['coin'].play() self.coins += 1 if event.key == self.controls['1p_start']: if not self.player_1.alive( ) and not self.player_1_choose and self.coins > 0: self.coins -= 1 self.player_1_choose = True self.choice['1p'] = 1 if event.key == self.controls['2p_start']: if not self.player_2.alive( ) and not self.player_2_choose and self.coins > 0: self.coins -= 1 self.player_2_choose = True self.choice['2p'] = 2 if event.key in [ self.controls[x] for x in ['1p_up', '1p_down', '1p_left', '1p_right'] ]: if self.player_1_choose: self.choice['1p'] = (self.choice['1p'] + 2 ) % 4 # Alternate between 1 and 3 if event.key in [ self.controls[x] for x in ['2p_up', '2p_down', '2p_left', '2p_right'] ]: if self.player_1_choose: self.choice['2p'] = self.choice[ '2p'] % 4 + 2 # Alternate between 2 and 4 if event.key == self.controls['1p_button_a']: if self.player_1.alive(): # Player 1 is actually playing self.player_1.weapon_time = pygame.time.get_ticks( ) # Counter for when to switch to strong # weapon if self.player_1_choose: self.player_1 = Player(self, self.choice['1p'], PVector(150, 700)) self.player_1_choose = False self.player_1_choose_time = 60 * 20 if event.key == self.controls['1p_button_b']: if self.player_1.alive(): self.player_1.activate_bomb() if self.player_1_choose: self.player_1 = Player(self, self.choice['1p'], PVector(150, 700)) self.player_1_choose = False self.player_1_choose_time = 60 * 20 if event.key == self.controls['2p_button_a']: if self.player_2.alive(): # Player 1 is actually playing self.player_2.weapon_time = pygame.time.get_ticks( ) # Counter for when to switch to strong # weapon if self.player_2_choose: self.player_2 = Player(self, self.choice['2p'], PVector(450, 700)) self.player_2_choose = False self.player_2_choose_time = 60 * 20 if event.key == self.controls['2p_button_b']: if self.player_2.alive(): self.player_2.activate_bomb() if self.player_2_choose: self.player_2 = Player(self, self.choice['2p'], PVector(450, 700)) self.player_2_choose = False self.player_2_choose_time = 60 * 20 elif event.type == pygame.KEYUP: if event.key == self.controls['1p_button_a']: if self.player_1.alive(): self.player_1.weapon_1 = False self.player_1.weapon_2 = False if event.key == self.controls['2p_button_a']: if self.player_2.alive(): self.player_2.weapon_1 = False self.player_2.weapon_2 = False if self.player_1.alive(): if keys[self.controls['1p_up']] and keys[self.controls['1p_down']]: self.player_1.direction.y = 0 elif keys[self.controls['1p_up']]: self.player_1.direction.y = -1 elif keys[self.controls['1p_down']]: self.player_1.direction.y = 1 else: self.player_1.direction.y = 0 if keys[self.controls['1p_left']] and keys[ self.controls['1p_right']]: self.player_1.direction.x = 0 elif keys[self.controls['1p_left']]: self.player_1.direction.x = -1 elif keys[self.controls['1p_right']]: self.player_1.direction.x = 1 else: self.player_1.direction.x = 0 if keys[self.controls['1p_button_a']]: if pygame.time.get_ticks( ) - self.player_1.weapon_charge_up_time > self.player_1.weapon_time: self.player_1.weapon_2 = True self.player_1.weapon_1 = False else: self.player_1.weapon_1 = True if self.player_2.alive(): if keys[self.controls['2p_up']] and keys[self.controls['2p_down']]: self.player_2.direction.y = 0 elif keys[self.controls['2p_up']]: self.player_2.direction.y = -1 elif keys[self.controls['2p_down']]: self.player_2.direction.y = 1 else: self.player_2.direction.y = 0 if keys[self.controls['2p_left']] and keys[ self.controls['2p_right']]: self.player_2.direction.x = 0 elif keys[self.controls['2p_left']]: self.player_2.direction.x = -1 elif keys[self.controls['2p_right']]: self.player_2.direction.x = 1 else: self.player_2.direction.x = 0 if keys[self.controls['2p_button_a']]: if pygame.time.get_ticks( ) - self.player_2.weapon_charge_up_time > self.player_2.weapon_time: self.player_2.weapon_2 = True self.player_2.weapon_1 = False else: self.player_2.weapon_1 = True
class Game: def __init__(self, gui=True): self.surface = None self.gui = gui self.file = None self.screen = curses.initscr() curses.curs_set(0) if gui: pygame.init() self.surface = pygame.display.set_mode((640, 480)) self.red_image = pygame.image.load( os.path.join(cfg.GFX_DIR, 'player-red.png')).convert_alpha() self.blue_image = pygame.image.load( os.path.join(cfg.GFX_DIR, 'player-blue.png')).convert_alpha() self.bullet_image = pygame.image.load( os.path.join(cfg.GFX_DIR, 'bullet.png')).convert_alpha() self.player = Player(self.blue_image, x=640, y=480) self.bot = Player(self.red_image, angle=180) self.bullets = pygame.sprite.RenderPlain() self.sprites = pygame.sprite.RenderPlain(self.player, self.bot) self.game_time = 0 def run(self): tick = time.clock() running = True while running: if self.gui: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False self.handle_arrow_keys(event, self.player) self.handle_wsad_keys(event, self.bot) if time.clock() - tick > 1 / 60: tick = time.clock() self.game_time += 1 self.on_render() if self.game_time % 5 == 0: self.raport() self.save_game_state('game.sav') if not self.player.alive() or not self.bot.alive(): self.raport() running = False self.file.close() pygame.quit() def handle_wsad_keys(self, event, player): input_state = player.input_state if event.type == pygame.KEYDOWN: if event.key == pygame.K_w: input_state.up = True elif event.key == pygame.K_s: input_state.down = True elif event.key == pygame.K_a: input_state.left = True elif event.key == pygame.K_d: input_state.right = True elif event.key == pygame.K_e: bullet = Bullet( self.bullet_image, x=player.rect.x + 22, # wyśrodkowanie w poziomie y=player.rect.y + (-20 if player.angle == 0 else 60), # podniesienie ponad gracza going_up=player.angle == 0, damage=cfg.BULLET_DAMAGE) self.bullets.add(bullet) if event.type == pygame.KEYUP: if event.key == pygame.K_w: input_state.up = False elif event.key == pygame.K_s: input_state.down = False elif event.key == pygame.K_a: input_state.left = False elif event.key == pygame.K_d: input_state.right = False def handle_arrow_keys(self, event, player): input_state = player.input_state if event.type == pygame.KEYDOWN: if event.key == pygame.K_UP: input_state.up = True elif event.key == pygame.K_DOWN: input_state.down = True elif event.key == pygame.K_LEFT: input_state.left = True elif event.key == pygame.K_RIGHT: input_state.right = True elif event.key == pygame.K_SPACE: # input_state.shoot = True bullet = Bullet( self.bullet_image, x=player.rect.x + 22, # wyśrodkowanie w poziomie y=player.rect.y + (-20 if player.angle == 0 else 60), # podniesienie ponad gracza going_up=player.angle == 0, damage=cfg.BULLET_DAMAGE) self.bullets.add(bullet) if event.type == pygame.KEYUP: if event.key == pygame.K_UP: input_state.up = False elif event.key == pygame.K_DOWN: input_state.down = False elif event.key == pygame.K_LEFT: input_state.left = False elif event.key == pygame.K_RIGHT: input_state.right = False # elif event.key == pygame.K_SPACE: # input_state.shoot = False def on_render(self): self.surface.fill((253, 246, 227)) self.sprites.update() self.bullets.update(self.player, self.bot) self.sprites.draw(self.surface) self.bullets.draw(self.surface) pygame.display.flip() def get_game_state(self): state = [ self.player.rect.x, self.player.rect.y, self.player.health, self.bot.rect.x, self.bot.rect.y, self.bot.health, len(self.bullets), ] bullets_going_up = [] bullets_going_down = [] for bullet in iter(self.bullets): if bullet.going_up: bullets_going_up.append(bullet) if not bullet.going_up: bullets_going_down.append(bullet) sorted(bullets_going_up) sorted(bullets_going_down) for bullet in bullets_going_up: state.append(bullet.rect.x) state.append(bullet.rect.y) for bullet in bullets_going_down: state.append(bullet.rect.x) state.append(bullet.rect.y) return state def save_game_state(self, filename): if not self.file: self.file = open(filename, 'w+') state = self.get_game_state() for item in state: self.file.write('%s ' % str(item)) self.file.write('\n') def count_fitness(self, player, opponent): return cfg.DMG_TAKEN_MULTIPLIER * (100-player.health) + \ cfg.GAME_TIME_MULTIPLIER * self.game_time + \ cfg.DMG_GIVEN_MULTIPLIER * (100-opponent.health) def raport(self): self.screen.clear() self.screen.addstr(0, 0, 'Game time: ' + str(self.game_time)) self.screen.addstr( 2, 0, 'Red health: ' + str(self.bot.health) + (' (alive)' if self.bot.alive() else ' (dead)')) self.screen.addstr( 3, 0, 'Blue health: ' + str(self.player.health) + (' (alive)' if self.player.alive() else ' (dead)')) self.screen.addstr( 2, 25, 'fitness: ' + str(self.count_fitness(self.bot, self.player))) self.screen.addstr( 3, 25, 'fitness: ' + str(self.count_fitness(self.player, self.bot))) self.screen.addstr(5, 0, 'Bullet damage: ' + str(cfg.BULLET_DAMAGE)) self.screen.addstr(5, 20, 'DMG taken multiplier: ' + str(-5)) self.screen.addstr(5, 50, 'DMG given multiplier: ' + str(10)) self.screen.addstr(5, 80, 'Game time multiplier: ' + str(2)) self.screen.addstr(6, 0, 'Bullets on screen: ' + str(len(self.bullets))) self.screen.refresh()