diff --git a/README.md b/README.md index e88f538..589b05f 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ El Vortex avanza automáticamente de forma constante hacia arriba. Si encuentra 1. Clona este repositorio: ```bash - git clone https://gitea.soloconlinux.org.es/luisgulo/Hightway_Vector.git - cd highway-vector + git clone https://gitea.soloconlinux.org.es/luisgulo/Highway_Vector.git + cd Highway_Vector ``` 2. Crea y activa un entorno virtual para las librerias de Python: ```bash diff --git a/highway_vector.py b/highway_vector.py new file mode 100644 index 0000000..1096105 --- /dev/null +++ b/highway_vector.py @@ -0,0 +1,239 @@ +import sys +import pygame + +# Inicialización de Pygame +pygame.init() + +# Constantes de Pantalla +SCREEN_WIDTH = 800 +SCREEN_HEIGHT = 600 +FPS = 60 + +# Configuración de Cuadrícula e Isometría +TILE_WIDTH = 64 +TILE_HEIGHT = 32 +GRID_SIZE_X = 8 +GRID_SIZE_Y = 100 # Largo de la autopista + +# Colores (Paleta Retro Spectrum/Amstrad) +COLOR_BG = (10, 10, 15) +COLOR_GRID = (40, 40, 60) +COLOR_ROAD = (60, 60, 80) +COLOR_VORTEX = (0, 255, 200) +COLOR_PLAYER = (255, 200, 0) +COLOR_BLOCK = (200, 50, 50) +COLOR_WALL = (100, 100, 120) + + +def grid_to_iso(gx, gy, gz=0): + """Convierte coordenadas de cuadrícula 3D (x, y, z) a coordenadas de pantalla 2D.""" + iso_x = (gx - gy) * (TILE_WIDTH // 2) + iso_y = (gx + gy) * (TILE_HEIGHT // 2) - (gz * 16) + return iso_x, iso_y + + +class Entity: + + def __init__(self, gx, gy, color, is_solid=True): + self.gx = float(gx) + self.gy = float(gy) + self.gz = 0 + self.color = color + self.is_solid = is_solid + self.radius = 0.4 + + def draw(self, surface, camera_offset_x, camera_offset_y): + screen_x, screen_y = grid_to_iso(self.gx, self.gy, self.gz) + draw_x = screen_x + camera_offset_x + draw_y = screen_y + camera_offset_y + + # Dibujar un bloque o personaje estilo isométrico + points = [ + (draw_x, draw_y - 20), + (draw_x + TILE_WIDTH // 2, draw_y - 20 + TILE_HEIGHT // 2), + (draw_x, draw_y - 20 + TILE_HEIGHT), + (draw_x - TILE_WIDTH // 2, draw_y - 20 + TILE_HEIGHT // 2), + ] + pygame.draw.polygon(surface, self.color, points) + pygame.draw.polygon( + surface, (255, 255, 255), points, 2 + ) # Borde brillante + + +class PushBlock(Entity): + + def __init__(self, gx, gy): + super().__init__(gx, gy, COLOR_BLOCK, is_solid=True) + + def push(self, dx, dy, entities): + new_gx = self.gx + dx + new_gy = self.gy + dy + + # Comprobar límites de la carretera + if not (0 <= new_gx < GRID_SIZE_X and 0 <= new_gy < GRID_SIZE_Y): + return False + + # Comprobar colisión con otras entidades + for entity in entities: + if entity != self and entity.is_solid: + if ( + abs(entity.gx - new_gx) < 0.6 + and abs(entity.gy - new_gy) < 0.6 + ): + return False + + self.gx = new_gx + self.gy = new_gy + return True + + +class Player(Entity): + + def __init__(self, gx, gy): + super().__init__(gx, gy, COLOR_PLAYER, is_solid=True) + self.speed = 0.08 + + def update(self, keys, entities): + dx, dy = 0, 0 + if keys[pygame.K_LEFT] or keys[pygame.K_a]: + dx -= self.speed + if keys[pygame.K_RIGHT] or keys[pygame.K_d]: + dx += self.speed + if keys[pygame.K_UP] or keys[pygame.K_w]: + dy -= self.speed + if keys[pygame.K_DOWN] or keys[pygame.K_s]: + dy += self.speed + + if dx != 0 or dy != 0: + target_gx = self.gx + dx + target_gy = self.gy + dy + + # Limites horizontales + if not (0 <= target_gx < GRID_SIZE_X): + dx = 0 + if not (0 <= target_gy < GRID_SIZE_Y): + dy = 0 + + # Intento de movimiento y colisión con bloques + for entity in entities: + if entity != self and entity.is_solid: + if ( + abs(entity.gx - (self.gx + dx)) < 0.6 + and abs(entity.gy - (self.gy + dy)) < 0.6 + ): + # Intentar empujar si es un PushBlock + if isinstance(entity, PushBlock): + push_dx = 0.1 if dx > 0 else (-0.1 if dx < 0 else 0) + push_dy = 0.1 if dy > 0 else (-0.1 if dy < 0 else 0) + if not entity.push(push_dx, push_dy, entities): + return + else: + return # Bloqueado + + self.gx += dx + self.gy += dy + + +class Vortex(Entity): + + def __init__(self, gx, gy): + super().__init__(gx, gy, COLOR_VORTEX, is_solid=True) + self.speed = 0.015 # Avance constante automático + + def update(self, entities): + target_gy = self.gy - self.speed + + # Verificar si hay algún obstáculo al avanzar + blocked = False + for entity in entities: + if entity != self and entity.is_solid: + if ( + abs(entity.gx - self.gx) < 0.7 + and abs(entity.gy - target_gy) < 0.7 + ): + blocked = True + break + + if not blocked and target_gy >= 0: + self.gy = target_gy + + +class Game: + + def __init__(self): + self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) + pygame.display.set_caption("Highway Encounter Python Remake") + self.clock = pygame.time.Clock() + + self.vortex = Vortex(3.5, 95) + self.player = Player(3.5, 92) + + self.entities = [self.vortex, self.player] + + # Generar bloques de prueba a lo largo de la autopista + for y in range(10, 90, 5): + self.entities.append(PushBlock(y % GRID_SIZE_X, y)) + self.entities.append(PushBlock((y + 3) % GRID_SIZE_X, y + 2)) + + def run(self): + running = True + while running: + self.clock.tick(FPS) + + # 1. Procesar Eventos + for event in pygame.event.get(): + if event.type == pygame.QUIT: + running = False + + # 2. Actualizar Estado + keys = pygame.key.get_pressed() + self.player.update(keys, self.entities) + self.vortex.update(self.entities) + + # 3. Calcular desplazamiento de cámara (centrada en el VORTEX o el jugador) + iso_x, iso_y = grid_to_iso(self.player.gx, self.player.gy) + camera_offset_x = SCREEN_WIDTH // 2 - iso_x + camera_offset_y = SCREEN_HEIGHT // 2 - iso_y + 100 + + # 4. Renderizado + self.screen.fill(COLOR_BG) + + # Dibujar suelo (Autopista) + for gy in range(0, GRID_SIZE_Y): + for gx in range(0, GRID_SIZE_X): + sx, sy = grid_to_iso(gx, gy) + draw_x = sx + camera_offset_x + draw_y = sy + camera_offset_y + + # Solo dibujar si está visible en pantalla + if -100 < draw_x < SCREEN_WIDTH + 100 and -100 < draw_y < SCREEN_HEIGHT + 100: + pts = [ + (draw_x, draw_y), + ( + draw_x + TILE_WIDTH // 2, + draw_y + TILE_HEIGHT // 2, + ), + (draw_x, draw_y + TILE_HEIGHT), + ( + draw_x - TILE_WIDTH // 2, + draw_y + TILE_HEIGHT // 2, + ), + ] + pygame.draw.polygon(self.screen, COLOR_ROAD, pts) + pygame.draw.polygon(self.screen, COLOR_GRID, pts, 1) + + # Ordenar entidades por coordenada 'gy' descendente para renderizar correctamente la profundidad + sorted_entities = sorted( + self.entities, key=lambda e: e.gy, reverse=True + ) + for entity in sorted_entities: + entity.draw(self.screen, camera_offset_x, camera_offset_y) + + pygame.display.flip() + + pygame.quit() + sys.exit() + + +if __name__ == "__main__": + Game().run() diff --git a/img-versiones/version_0.1.png b/img-versiones/version_0.1.png new file mode 100644 index 0000000..171eba2 Binary files /dev/null and b/img-versiones/version_0.1.png differ