From 2c2020252b684e40ba5e286bc041d769a33c583c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladislavs=20Pozd=C5=86aks?= Date: Thu, 28 Mar 2024 06:42:28 +0000 Subject: [PATCH] Upload files to "/" --- settings.py | 60 +++++++++ sprite_objects.py | 309 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 369 insertions(+) create mode 100644 settings.py create mode 100644 sprite_objects.py diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..4f4e49f --- /dev/null +++ b/settings.py @@ -0,0 +1,60 @@ +import math + +# game settings +WIDTH = 1200 +HEIGHT = 800 +HALF_WIDTH = WIDTH // 2 +HALF_HEIGHT = HEIGHT // 2 +PENTA_HEIGHT = 5 * HEIGHT +DOUBLE_HEIGHT = 2 * HEIGHT +FPS = 60 +TILE = 100 +FPS_POS = (WIDTH - 65, 5) + +# minimap settings +MINIMAP_SCALE = 5 +MINIMAP_RES = (WIDTH // MINIMAP_SCALE, HEIGHT // MINIMAP_SCALE) +MAP_SCALE = 2 * MINIMAP_SCALE # 1 -> 12 x 8, 2 -> 24 x 16, 3 -> 36 x 24 +MAP_TILE = TILE // MAP_SCALE +MAP_POS = (0, HEIGHT - HEIGHT // MINIMAP_SCALE) + +# ray casting settings +FOV = math.pi / 3 +HALF_FOV = FOV / 2 +NUM_RAYS = 300 +MAX_DEPTH = 800 +DELTA_ANGLE = FOV / NUM_RAYS +DIST = NUM_RAYS / (2 * math.tan(HALF_FOV)) +PROJ_COEFF = 3 * DIST * TILE +SCALE = WIDTH // NUM_RAYS + +# sprite settings +DOUBLE_PI = math.pi * 2 +CENTER_RAY = NUM_RAYS // 2 - 1 +FAKE_RAYS = 100 +FAKE_RAYS_RANGE = NUM_RAYS - 1 + 2 * FAKE_RAYS + +# texture settings (1200 x 1200) +TEXTURE_WIDTH = 1200 +TEXTURE_HEIGHT = 1200 +HALF_TEXTURE_HEIGHT = TEXTURE_HEIGHT // 2 +TEXTURE_SCALE = TEXTURE_WIDTH // TILE + +# player settings +player_pos = (HALF_WIDTH // 4, HALF_HEIGHT - 50) +player_angle = 0 +player_speed = 3 + +# colors +WHITE = (255, 255, 255) +BLACK = (0, 0, 0) +RED = (220, 0, 0) +GREEN = (0, 80, 0) +BLUE = (0, 0, 255) +DARKGRAY = (40, 40, 40) +PURPLE = (120, 0, 120) +SKYBLUE = (0, 186, 255) +YELLOW = (220, 220, 0) +SANDY = (244, 164, 96) +DARKBROWN = (97, 61, 25) +DARKORANGE = (255, 140, 0) \ No newline at end of file diff --git a/sprite_objects.py b/sprite_objects.py new file mode 100644 index 0000000..a0a4106 --- /dev/null +++ b/sprite_objects.py @@ -0,0 +1,309 @@ +import pygame +from settings import * +from collections import deque +from ray_casting import mapping +from numba.core import types +from numba.typed import Dict +from numba import int32 + + +class Sprites: + def __init__(self): + self.sprite_parameters = { + 'sprite_barrel': { + 'sprite': pygame.image.load('sprites/barrel/base/0.png').convert_alpha(), + 'viewing_angles': None, + 'shift': 1.8, + 'scale': (0.4, 0.4), + 'side': 30, + 'animation': deque( + [pygame.image.load(f'sprites/barrel/anim/{i}.png').convert_alpha() for i in range(12)]), + 'death_animation': deque([pygame.image.load(f'sprites/barrel/death/{i}.png') + .convert_alpha() for i in range(4)]), + 'is_dead': None, + 'dead_shift': 2.6, + 'animation_dist': 800, + 'animation_speed': 10, + 'blocked': True, + 'flag': 'decor', + 'obj_action': [] + }, + 'sprite_pin': { + 'sprite': pygame.image.load('sprites/pin/base/0.png').convert_alpha(), + 'viewing_angles': None, + 'shift': 0.6, + 'scale': (0.6, 0.6), + 'side': 30, + 'animation': deque([pygame.image.load(f'sprites/pin/anim/{i}.png').convert_alpha() for i in range(8)]), + 'death_animation': [], + 'is_dead': 'immortal', + 'dead_shift': None, + 'animation_dist': 800, + 'animation_speed': 10, + 'blocked': True, + 'flag': 'decor', + 'obj_action': [] + }, + 'sprite_flame': { + 'sprite': pygame.image.load('sprites/flame/base/0.png').convert_alpha(), + 'viewing_angles': None, + 'shift': 0.7, + 'scale': (0.6, 0.6), + 'side': 30, + 'animation': deque( + [pygame.image.load(f'sprites/flame/anim/{i}.png').convert_alpha() for i in range(16)]), + 'death_animation': [], + 'is_dead': 'immortal', + 'dead_shift': 1.8, + 'animation_dist': 1800, + 'animation_speed': 5, + 'blocked': None, + 'flag': 'decor', + 'obj_action': [] + }, + 'npc_devil': { + 'sprite': [pygame.image.load(f'sprites/devil/base/{i}.png').convert_alpha() for i in range(8)], + 'viewing_angles': True, + 'shift': 0.0, + 'scale': (1.1, 1.1), + 'side': 50, + 'animation': [], + 'death_animation': deque([pygame.image.load(f'sprites/devil/death/{i}.png') + .convert_alpha() for i in range(6)]), + 'is_dead': None, + 'dead_shift': 0.6, + 'animation_dist': None, + 'animation_speed': 10, + 'blocked': True, + 'flag': 'npc', + 'obj_action': deque( + [pygame.image.load(f'sprites/devil/anim/{i}.png').convert_alpha() for i in range(9)]), + }, + 'sprite_door_v': { + 'sprite': [pygame.image.load(f'sprites/doors/door_v/{i}.png').convert_alpha() for i in range(16)], + 'viewing_angles': True, + 'shift': 0.1, + 'scale': (2.6, 1.2), + 'side': 100, + 'animation': [], + 'death_animation': [], + 'is_dead': 'immortal', + 'dead_shift': 0, + 'animation_dist': 0, + 'animation_speed': 0, + 'blocked': True, + 'flag': 'door_h', + 'obj_action': [] + }, + 'sprite_door_h': { + 'sprite': [pygame.image.load(f'sprites/doors/door_h/{i}.png').convert_alpha() for i in range(16)], + 'viewing_angles': True, + 'shift': 0.1, + 'scale': (2.6, 1.2), + 'side': 100, + 'animation': [], + 'death_animation': [], + 'is_dead': 'immortal', + 'dead_shift': 0, + 'animation_dist': 0, + 'animation_speed': 0, + 'blocked': True, + 'flag': 'door_v', + 'obj_action': [] + }, + 'npc_soldier0': { + 'sprite': [pygame.image.load(f'sprites/npc/soldier0/base/{i}.png').convert_alpha() for i in range(8)], + 'viewing_angles': True, + 'shift': 0.8, + 'scale': (0.4, 0.6), + 'side': 30, + 'animation': [], + 'death_animation': deque([pygame.image.load(f'sprites/npc/soldier0/death/{i}.png') + .convert_alpha() for i in range(10)]), + 'is_dead': None, + 'dead_shift': 1.7, + 'animation_dist': None, + 'animation_speed': 6, + 'blocked': True, + 'flag': 'npc', + 'obj_action': deque([pygame.image.load(f'sprites/npc/soldier0/action/{i}.png') + .convert_alpha() for i in range(4)]) + }, + } + + self.list_of_objects = [ + SpriteObject(self.sprite_parameters['sprite_barrel'], (7.1, 2.1)), + SpriteObject(self.sprite_parameters['sprite_barrel'], (5.9, 2.1)), + SpriteObject(self.sprite_parameters['sprite_pin'], (8.7, 2.5)), + SpriteObject(self.sprite_parameters['npc_devil'], (7, 4)), + SpriteObject(self.sprite_parameters['sprite_flame'], (8.6, 5.6)), + SpriteObject(self.sprite_parameters['sprite_door_v'], (3.5, 3.5)), + SpriteObject(self.sprite_parameters['sprite_door_h'], (1.5, 4.5)), + SpriteObject(self.sprite_parameters['npc_soldier0'], (2.5, 1.5)), + SpriteObject(self.sprite_parameters['npc_soldier0'], (5.51, 1.5)), + SpriteObject(self.sprite_parameters['npc_soldier0'], (6.61, 2.92)), + SpriteObject(self.sprite_parameters['npc_soldier0'], (7.68, 1.47)), + SpriteObject(self.sprite_parameters['npc_soldier0'], (8.75, 3.65)), + SpriteObject(self.sprite_parameters['npc_soldier0'], (1.27, 11.5)), + SpriteObject(self.sprite_parameters['npc_soldier0'], (1.26, 8.29)), + ] + + @property + def sprite_shot(self): + return min([obj.is_on_fire for obj in self.list_of_objects], default=(float('inf'), 0)) + + @property + def blocked_doors(self): + blocked_doors = Dict.empty(key_type=types.UniTuple(int32, 2), value_type=int32) + for obj in self.list_of_objects: + if obj.flag in {'door_h', 'door_v'} and obj.blocked: + i, j = mapping(obj.x, obj.y) + blocked_doors[(i, j)] = 0 + return blocked_doors + + +class SpriteObject: + def __init__(self, parameters, pos): + self.object = parameters['sprite'].copy() + self.viewing_angles = parameters['viewing_angles'] + self.shift = parameters['shift'] + self.scale = parameters['scale'] + self.animation = parameters['animation'].copy() + # --------------------- + self.death_animation = parameters['death_animation'].copy() + self.is_dead = parameters['is_dead'] + self.dead_shift = parameters['dead_shift'] + # --------------------- + self.animation_dist = parameters['animation_dist'] + self.animation_speed = parameters['animation_speed'] + self.blocked = parameters['blocked'] + self.flag = parameters['flag'] + self.obj_action = parameters['obj_action'].copy() + self.x, self.y = pos[0] * TILE, pos[1] * TILE + self.side = parameters['side'] + self.dead_animation_count = 0 + self.animation_count = 0 + self.npc_action_trigger = False + self.door_open_trigger = False + self.door_prev_pos = self.y if self.flag == 'door_h' else self.x + self.delete = False + if self.viewing_angles: + if len(self.object) == 8: + self.sprite_angles = [frozenset(range(338, 361)) | frozenset(range(0, 23))] + \ + [frozenset(range(i, i + 45)) for i in range(23, 338, 45)] + else: + self.sprite_angles = [frozenset(range(348, 361)) | frozenset(range(0, 11))] + \ + [frozenset(range(i, i + 23)) for i in range(11, 348, 23)] + self.sprite_positions = {angle: pos for angle, pos in zip(self.sprite_angles, self.object)} + + @property + def is_on_fire(self): + if CENTER_RAY - self.side // 2 < self.current_ray < CENTER_RAY + self.side // 2 and self.blocked: + return self.distance_to_sprite, self.proj_height + return float('inf'), None + + @property + def pos(self): + return self.x - self.side // 2, self.y - self.side // 2 + + def object_locate(self, player): + + dx, dy = self.x - player.x, self.y - player.y + self.distance_to_sprite = math.sqrt(dx ** 2 + dy ** 2) + + self.theta = math.atan2(dy, dx) + gamma = self.theta - player.angle + if dx > 0 and 180 <= math.degrees(player.angle) <= 360 or dx < 0 and dy < 0: + gamma += DOUBLE_PI + self.theta -= 1.4 * gamma + + delta_rays = int(gamma / DELTA_ANGLE) + self.current_ray = CENTER_RAY + delta_rays + if self.flag not in {'door_h', 'door_v'}: + self.distance_to_sprite *= math.cos(HALF_FOV - self.current_ray * DELTA_ANGLE) + + fake_ray = self.current_ray + FAKE_RAYS + if 0 <= fake_ray <= FAKE_RAYS_RANGE and self.distance_to_sprite > 30: + self.proj_height = min(int(PROJ_COEFF / self.distance_to_sprite), + DOUBLE_HEIGHT if self.flag not in {'door_h', 'door_v'} else HEIGHT) + sprite_width = int(self.proj_height * self.scale[0]) + sprite_height = int(self.proj_height * self.scale[1]) + half_sprite_width = sprite_width // 2 + half_sprite_height = sprite_height // 2 + shift = half_sprite_height * self.shift + + # logic for doors, npc, decor + if self.flag in {'door_h', 'door_v'}: + if self.door_open_trigger: + self.open_door() + self.object = self.visible_sprite() + sprite_object = self.sprite_animation() + else: + if self.is_dead and self.is_dead != 'immortal': + sprite_object = self.dead_animation() + shift = half_sprite_height * self.dead_shift + sprite_height = int(sprite_height / 1.3) + elif self.npc_action_trigger: + sprite_object = self.npc_in_action() + else: + self.object = self.visible_sprite() + sprite_object = self.sprite_animation() + + + # sprite scale and pos + sprite_pos = (self.current_ray * SCALE - half_sprite_width, HALF_HEIGHT - half_sprite_height + shift) + sprite = pygame.transform.scale(sprite_object, (sprite_width, sprite_height)) + return (self.distance_to_sprite, sprite, sprite_pos) + else: + return (False,) + + def sprite_animation(self): + if self.animation and self.distance_to_sprite < self.animation_dist: + sprite_object = self.animation[0] + if self.animation_count < self.animation_speed: + self.animation_count += 1 + else: + self.animation.rotate() + self.animation_count = 0 + return sprite_object + return self.object + + def visible_sprite(self): + if self.viewing_angles: + if self.theta < 0: + self.theta += DOUBLE_PI + self.theta = 360 - int(math.degrees(self.theta)) + + for angles in self.sprite_angles: + if self.theta in angles: + return self.sprite_positions[angles] + return self.object + + def dead_animation(self): + if len(self.death_animation): + if self.dead_animation_count < self.animation_speed: + self.dead_sprite = self.death_animation[0] + self.dead_animation_count += 1 + else: + self.dead_sprite = self.death_animation.popleft() + self.dead_animation_count = 0 + return self.dead_sprite + + def npc_in_action(self): + sprite_object = self.obj_action[0] + if self.animation_count < self.animation_speed: + self.animation_count += 1 + else: + self.obj_action.rotate() + self.animation_count = 0 + return sprite_object + + def open_door(self): + if self.flag == 'door_h': + self.y -= 3 + if abs(self.y - self.door_prev_pos) > TILE: + self.delete = True + elif self.flag == 'door_v': + self.x -= 3 + if abs(self.x - self.door_prev_pos) > TILE: + self.delete = True \ No newline at end of file