From a1739d25645c01cdb09f95a81c1f72ff0ab4554f Mon Sep 17 00:00:00 2001 From: Aleksandrs Karpovs Date: Thu, 28 Mar 2024 08:30:03 +0000 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=B2=20=C2=AB?= =?UTF-8?q?plagiats=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plagiats/camera.py | 41 +++++++ plagiats/entity.py | 269 +++++++++++++++++++++++++++++++++++++++++++++ plagiats/game.py | 76 +++++++++++++ plagiats/main.py | 7 ++ plagiats/map.py | 246 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 639 insertions(+) create mode 100644 plagiats/camera.py create mode 100644 plagiats/entity.py create mode 100644 plagiats/game.py create mode 100644 plagiats/main.py create mode 100644 plagiats/map.py diff --git a/plagiats/camera.py b/plagiats/camera.py new file mode 100644 index 0000000..24c572b --- /dev/null +++ b/plagiats/camera.py @@ -0,0 +1,41 @@ +import pygame + + +class Camera: + def __init__(self, game): + self.game = game + self.map = game.map + self.player = game.player + self.enemies = game.enemies + self.projectiles = game.projectiles + self.settings = game.settings + + self.map.add_enemies(self.enemies) + + def move_up(self): + self.map.move_up() + self.player.move_up() + + def move_down(self): + self.map.move_down() + self.player.move_down() + + def move_left(self): + self.map.move_left() + self.player.move_left() + + def move_right(self): + self.map.move_right() + self.player.move_right() + + 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() diff --git a/plagiats/entity.py b/plagiats/entity.py new file mode 100644 index 0000000..43efa91 --- /dev/null +++ b/plagiats/entity.py @@ -0,0 +1,269 @@ +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) diff --git a/plagiats/game.py b/plagiats/game.py new file mode 100644 index 0000000..a7e245e --- /dev/null +++ b/plagiats/game.py @@ -0,0 +1,76 @@ +import random +import pygame +import pygame.font + +from settings import GameSettings +from map import Map +from entity import Enemy, Player +from projectiles import Projectiles +from camera import Camera + +class Game: + def __init__(self): + self.settings = GameSettings() + self.screen = pygame.display.set_mode((self.settings.screen_width, self.settings.screen_height)) + pygame.display.set_caption(self.settings.caption) + + self.clock = pygame.time.Clock() + + self.map = Map(self, 0, 0) + player_spawn_block = self.map.player_spawn + offset = [ + (self.settings.screen_width // 2) - player_spawn_block.x - (self.settings.block_size // 2), + (self.settings.screen_height // 2) - player_spawn_block.y - (self.settings.block_size // 2) + ] + self.map.change_coords(offset[0], offset[1]) + + self.enemies = pygame.sprite.Group() + + self.projectiles = Projectiles(self) + d = (self.settings.block_size - self.settings.entity_size) // 2 + self.player = Player(self, self.map.player_spawn.x + d, self.map.player_spawn.y + d) + self.camera = Camera(self) + self.score = 0 + + + def run(self): + while self.settings.running: + #FPS control + self.clock.tick(self.settings.fps) + + #Events + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.settings.running = False + + self.camera.update() + self.enemies.update() + + #Spawn enemies + if self.settings.enemy_spawn_rev < self.settings.enemy_spawn_rev_thresh: + self.settings.enemy_spawn_rev -= self.settings.enemy_spawn_rev_delta + + if random.randint(1, self.settings.enemy_spawn_rev) == 1: + self.spawn_enemy() + + #Render + self.screen.fill((0, 0, 0)) + self.map.update() + #print(map) + self.player.update() + self.enemies.draw(self.screen) + self.projectiles.update() + self.draw_score() + + pygame.display.flip() + + return self.score + + def spawn_enemy(self): + es = random.choice(self.map.enemy_spawns) + self.enemies.add(Enemy(self, es.x, es.y)) + + def draw_score(self): + fnt = pygame.font.SysFont("calibri", 40, True) + score = fnt.render("Score: " + str(self.score), True, (255, 255, 255), (0, 0, 0)) + self.screen.blit(score, (0, 0)) diff --git a/plagiats/main.py b/plagiats/main.py new file mode 100644 index 0000000..127f765 --- /dev/null +++ b/plagiats/main.py @@ -0,0 +1,7 @@ +import pygame +pygame.init() + +from game import Game + +g = Game() +print(g.run()) \ No newline at end of file diff --git a/plagiats/map.py b/plagiats/map.py new file mode 100644 index 0000000..01367bc --- /dev/null +++ b/plagiats/map.py @@ -0,0 +1,246 @@ +import os +from pygame import Rect, image +import pygame + +from utils import load_image + +class Block: + BRICK = "brick" + GRASS = "grass" + KUST = "kust" + STONE = "stone" + WATER = "water" + PLAYER_SPAWN = "player_spawn" + ENEMY_SPAWN = "enemy_spawn" + + def __init__(self, game, x, y, i, j, type: str): + self.game = game + self.settings = self.game.settings + + self.height = self.settings.block_size + self.width = self.settings.block_size + self.image_folder = os.path.join(self.settings.img_folder, "map") + + self.type = type + self.passable = self.is_passable() + self.projectile_passable = self.is_projectile_passable() + + #print(os.path.join(self.image_folder, self.type, ".png")) + self.image = load_image(self.settings, os.path.join(self.image_folder, self.type + ".png")) + #print(os.path.join(self.image_folder, self.type + ".png")) + + self.x = x + self.y = y + self.i = i + self.j = j + + self.update() + + def update(self): + self.rect = self.game.screen.blit(self.image, (self.x, self.y)) + + def is_passable(self): + if self.type == "brick" or self.type == "stone" or self.type == "water": + return False + else: + return True + + def is_projectile_passable(self): + if self.type == "brick" or self.type == "stone": + return False + else: + return True + + def __str__(self): + return "{} block on x: {}, y: {}".format(self.type, self.x, self.y) + + +class Map: + def __init__(self, game, lc_x: int, lc_y: int): + self.game = game + self.settings = game.settings + self.x = lc_x + self.y = lc_y + + + self.charmap = self.load_map("BattleCity.txt") + + self.blockmap = [] + self.enemy_spawns = [] + k = 0 + i = self.y + j = self.x + for line in self.charmap: + self.blockmap.append([]) + j = self.x + + l = 0 + for block in line: + self.blockmap[k].append(self.get_block_by_char(block, j, i, k, l)) + + if block == "P": + self.player_spawn = self.blockmap[k][-1] + + if block == "E": + self.enemy_spawns.append(self.blockmap[k][-1]) + + j += self.settings.block_size + l += 1 + + k += 1 + i += self.settings.block_size + + self.enemies = None + es = self.settings.entity_size + self.tank_rect = Rect(self.settings.c_x - es // 2, self.settings.c_y - es // 2, es, es) + + def load_map(self, filename: str) -> list: + f = open(os.path.join(self.settings.map_folder, filename)) + lines = f.readlines() + f.close() + + i = 0 + result = [] + for line in lines: + result.append([]) + for c in line: + if c in "BGKSWPE": + result[i].append(c) + + i += 1 + + #print(result) + return result + + def get_block_by_char(self, char, x, y, i, j): + tp = None + + if char == "B": + tp = Block.BRICK + elif char == "G": + tp = Block.GRASS + elif char == "K": + tp = Block.KUST + elif char == "S": + tp = Block.STONE + elif char == "W": + tp = Block.WATER + elif char == "P": + tp = Block.PLAYER_SPAWN + elif char == "E": + tp = Block.ENEMY_SPAWN + + if tp != None: + return Block(self.game, x, y, i, j, tp) + else: + return False + + def add_enemies(self, enemies): + self.enemies = enemies + + def update(self): + for line in self.blockmap: + for block in line: + block.update() + + def change_coords(self, x = None, y = None): + if self.enemies != None: + dx = self.x - x if x != None else 0 + dy = self.y - y if y != None else 0 + for enemy in self.enemies.sprites(): + enemy.change_coords_by_delta(dx, dy) + + for projectile in self.game.projectiles.projectiles: + projectile.change_coords_by_delta(dx, dy) + + k = 0 + self.x = x if x != None else self.x + self.y = y if y != None else self.y + j = self.x + i = self.y + + for line in self.blockmap: + j = self.x + + for block in line: + block.x = j + block.y = i + + j += self.settings.block_size + + k += 1 + i += self.settings.block_size + + + + def get_block_collision_vars(self): #cx, cy, tsh + return self.settings.c_x, self.settings.c_y, self.settings.block_size // 2 + + + def move_up(self): + cx, cy, tsh = self.get_block_collision_vars() + cp1 = (cx - tsh + 2, cy - tsh) + cp2 = (cx + tsh - 2, 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.change_coords(None, self.y + self.settings.move_speed) + + def move_down(self): + cx, cy, tsh = self.get_block_collision_vars() + cp1 = (cx - tsh + 2, cy + tsh) + cp2 = (cx + tsh - 2, 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.change_coords(None, self.y - self.settings.move_speed) + + def move_left(self): + cx, cy, tsh = self.get_block_collision_vars() + cp1 = (cx - tsh, cy - tsh + 2) + cp2 = (cx - tsh, cy + tsh - 2) + + 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.change_coords(self.x + self.settings.move_speed, None) + + def move_right(self): + cx, cy, tsh = self.get_block_collision_vars() + cp1 = (cx + tsh, cy - tsh + 2) + cp2 = (cx + tsh, cy + tsh - 2) + + 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.change_coords(self.x - self.settings.move_speed, None) + + def check_on_moveability(self, x, y, dx, dy): + #print(x, y, dx, dy) + #print(self.find_block_on_coords(x + dx, y + dy)) + if self.find_block_on_coords(x, y).passable: + return True + else: + return False + + def find_block_on_coords(self, x, y): + block_line = None + + for line in self.blockmap: + if line[0].y <= y and y < line[0].y + self.settings.block_size: + block_line = line + break + + + if block_line != None: + for block in line: + if block.x <= x and x < block.x + self.settings.block_size: + return block + + return False + + def __str__(self): + res = "" + for line in self.blockmap: + for block in line: + res += str(block) + "; " + + res += "\n" + + return res + +