import os from pygame.sprite import Sprite import pygame import math import random import time from utils import load_entity_image from projectile import Projectile class Tank(Sprite): MOVE_UP = "up" MOVE_DOWN = "down" MOVE_LEFT = "left" MOVE_RIGHT = "right" color = "blue" def __init__(self, settings, x: int, y: int): super().__init__() self.settings = settings image_folder = os.path.join(self.settings.img_folder, "tanks", self.color) self.IMAGES = { self.MOVE_UP: (load_entity_image(self.settings, os.path.join(image_folder, "tile004.png")), load_entity_image(self.settings, os.path.join(image_folder, "tile006.png"))), self.MOVE_DOWN: (load_entity_image(self.settings, os.path.join(image_folder, "tile010.png")), load_entity_image(self.settings, os.path.join(image_folder, "tile008.png"))), self.MOVE_LEFT: (load_entity_image(self.settings, os.path.join(image_folder, "tile012.png")), load_entity_image(self.settings, os.path.join(image_folder, "tile014.png"))), self.MOVE_RIGHT: (load_entity_image(self.settings, os.path.join(image_folder, "tile000.png")), load_entity_image(self.settings, os.path.join(image_folder, "tile002.png"))) } self.image = self.IMAGES[self.MOVE_UP][0] self.rect = self.image.get_rect() self.now_move = self.MOVE_UP self.now_frame = 0 self.move_stage = 0 self.animation_tick_change = 3 self.frame_quantity = 2 self.animation_max_tick = self.animation_tick_change * self.frame_quantity self.x = x self.y = y self.rect.x = self.x self.rect.y = self.y self.last_shot = time.time() def update_move_state(self, triggered: str): if triggered == self.now_move: self.move_stage += 1 self.now_frame = math.floor(self.move_stage / self.animation_tick_change) if self.now_frame > self.frame_quantity - 1: self.move_stage = 0 self.now_frame = 0 else: self.now_move = triggered self.move_stage = 0 del self.rect self.image = self.IMAGES[self.now_move][self.now_frame] self.rect = self.image.get_rect() self.rect.y = self.y self.rect.x = self.x def update(self): keystate = pygame.key.get_pressed() if keystate[pygame.K_w]: self.move_up() elif keystate[pygame.K_a]: self.move_left() elif keystate[pygame.K_s]: self.move_down() elif keystate[pygame.K_d]: self.move_right() def get_rect(self): return pygame.Rect(self.x, self.y, self.settings.entity_size, self.settings.entity_size) def create_new_projectile(self): if self.now_move == Tank.MOVE_UP: sx = self.x + self.settings.block_size / 2 - self.settings.projectile_size / 2 + 1 sy = self.y - self.settings.projectile_size / 2 - 1 elif self.now_move == Tank.MOVE_DOWN: sx = self.x + self.settings.block_size / 2 - self.settings.projectile_size / 2 + 1 sy = self.y + self.settings.block_size + 1 elif self.now_move == Tank.MOVE_LEFT: sy = self.y + self.settings.block_size / 2 - self.settings.projectile_size / 2 + 1 sx = self.x - self.settings.projectile_size / 2 - 1 elif self.now_move == Tank.MOVE_RIGHT: sy = self.y + self.settings.block_size / 2 - self.settings.projectile_size / 2 + 1 sx = self.x + self.settings.block_size + 1 self.last_shot = time.time() self.game.projectiles.add(Projectile(self.game, sx, sy, self.now_move)) class Player(Tank): color = "blue" def __init__(self, game, x, y): self.game = game super().__init__(self.game.settings, x, y) def move_up(self): self.update_move_state(self.MOVE_UP) def move_down(self): self.update_move_state(self.MOVE_DOWN) def move_left(self): self.update_move_state(self.MOVE_LEFT) def move_right(self): self.update_move_state(self.MOVE_RIGHT) def update(self): keystate = pygame.key.get_pressed() if keystate[pygame.K_SPACE]: if time.time() - self.last_shot > self.settings.recharge_time: self.create_new_projectile() self.game.screen.blit(self.image, (self.x, self.y)) class Enemy(Tank): color = "red" last_movement = Tank.MOVE_UP prev_variants = set() prev_prev_variants = set() could_move = True def __init__(self, game, x, y): super().__init__(game.settings, x, y) self.game = game self.settings = game.settings self.map = game.map def update(self): tsh = self.map.settings.block_size // 2 #tile size half block = self.map.find_block_on_coords(self.x + tsh, self.y + tsh) i, j = block.i, block.j if abs(self.x - block.x) < 0.6 and abs(self.y - block.y) < 0.6: #print(block) variants = self.get_possible_movements(i, j) if variants == self.prev_variants or variants == self.prev_variants: next_movement = self.last_movement else: next_movement = random.choice(list(variants)) self.last_movement = next_movement self.prev_prev_variants = self.prev_variants self.prev_variants = variants #print(variants) else: if self.could_move: next_movement = self.last_movement else: variants = self.get_possible_movements(i, j) next_movement = random.choice(list(variants)) self.last_movement = next_movement self.prev_variants = variants #Shot if random.randint(1, self.settings.enemy_shot_rev) == 1: self.create_new_projectile() if next_movement == Tank.MOVE_UP: self.move_up() elif next_movement == Tank.MOVE_LEFT: self.move_left() elif next_movement == Tank.MOVE_DOWN: self.move_down() elif next_movement == Tank.MOVE_RIGHT: self.move_right() def get_possible_movements(self, i, j): variants = set() if self.map.blockmap[i - 1][j].passable: variants.add(Tank.MOVE_UP) if self.map.blockmap[i + 1][j].passable: variants.add(Tank.MOVE_DOWN) if self.map.blockmap[i][j + 1].passable: variants.add(Tank.MOVE_RIGHT) if self.map.blockmap[i][j - 1].passable: variants.add(Tank.MOVE_LEFT) return variants def change_coords_by_delta(self, dx=None, dy=None): #print(dx, dy) self.x = self.x - dx self.y = self.y - dy self.rect.x = self.x self.rect.y = self.y def move_up(self): cx, cy, tsh = self.get_block_collision_vars() cp1 = (cx - tsh + 1, cy - tsh) cp2 = (cx + tsh - 1, cy - tsh) if self.check_on_moveability(cp1[0], cp1[1], 0, self.settings.move_speed) and self.check_on_moveability(cp2[0], cp2[1], 0, self.settings.move_speed): self.y -= self.settings.move_speed self.rect.y = self.y self.update_move_state(self.MOVE_UP) self.could_move = True else: self.could_move = False def move_down(self): cx, cy, tsh = self.get_block_collision_vars() cp1 = (cx - tsh + 1, cy + tsh) cp2 = (cx + tsh - 1, cy + tsh) if self.check_on_moveability(cp1[0], cp1[1], 0, -self.settings.move_speed) and self.check_on_moveability(cp2[0], cp2[1], 0, -self.settings.move_speed): self.y += self.settings.move_speed self.rect.y = self.y self.update_move_state(self.MOVE_DOWN) self.could_move = True else: self.could_move = False def move_left(self): cx, cy, tsh = self.get_block_collision_vars() cp1 = (cx - tsh, cy - tsh + 1) cp2 = (cx - tsh, cy + tsh - 1) if self.check_on_moveability(cp1[0], cp1[1], self.settings.move_speed, 0) and self.check_on_moveability(cp2[0], cp2[1], -self.settings.move_speed, 0): self.x -= self.settings.move_speed self.rect.x = self.x self.update_move_state(self.MOVE_LEFT) self.could_move = True else: self.could_move = False def move_right(self): cx, cy, tsh = self.get_block_collision_vars() cp1 = (cx + tsh, cy - tsh + 1) cp2 = (cx + tsh, cy + tsh - 1) if self.check_on_moveability(cp1[0], cp1[1], -self.settings.move_speed, 0) and self.check_on_moveability(cp2[0], cp2[1], -self.settings.move_speed, 0): self.x += self.settings.move_speed self.rect.x = self.x self.update_move_state(self.MOVE_RIGHT) self.could_move = True else: self.could_move = False def get_block_collision_vars(self): tsh = self.map.settings.block_size // 2 return self.x + tsh, self.y + tsh, tsh def check_on_moveability(self, x, y, dx, dy): return self.map.check_on_moveability(x, y, dx, dy)