CyberGuardian, un videojuego 2D de ciberseguridad con Python y Pygame
El desarrollo de videojuegos puede utilizarse como una estrategia educativa para explicar conceptos técnicos de una forma más dinámica e interactiva. Con ese propósito se desarrolló CyberGuardian: Amenaza Xenon, un videojuego 2D de plataformas creado con Python y Pygame, orientado a reforzar conceptos básicos de ciberseguridad.
El proyecto combina movimiento lateral, salto, enemigos, plataformas, música, fondos con efecto parallax, retos interactivos y pantallas narrativas. El jugador controla a Cyber, un personaje que debe avanzar por tres niveles, evitar drones enemigos e interactuar con terminales para resolver desafíos relacionados con phishing, contraseñas seguras y autenticación en dos pasos.
Este artículo documenta el proceso de desarrollo como evidencia paso a paso, desde la creación del proyecto en el entorno de desarrollo hasta la generación del ejecutable final.
El objetivo principal fue construir un videojuego 2D educativo que permitiera explicar conceptos de ciberseguridad mediante una experiencia jugable.
Apertura del proyecto en IntelliJ IDEA
El primer paso fue abrir el entorno de desarrollo. Para este proyecto se utilizó un entorno compatible con Python, como IntelliJ IDEA con soporte para Python o PyCharm.
Desde el IDE se abrió el proyecto principal donde se trabajaron los archivos del videojuego. El proyecto se organizó en una carpeta base llamada pythonProject.

Creación de la estructura de carpetas
Después de abrir el proyecto, se organizó la estructura general de carpetas para separar correctamente el código fuente, los recursos gráficos, la música y la documentación.
La estructura base quedó organizada de la siguiente manera:
pythonProject/
│
├── main_menu.py
├── nivel1.py
├── nivel2.py
├── nivel3.py
│
├── assets/
│ ├── Musica/
│ └── sprites/
│ ├── Atlas/
│ ├── Cyber/
│ ├── Lana/
│ ├── Xenon/
│ └── Fondos/
│
├── requirements.txt
├── README.md
└── .gitignore
Esta organización permitió trabajar de forma más clara. Cada archivo principal cumple una función específica: main_menu.py controla la pantalla inicial, mientras que nivel1.py, nivel2.py y nivel3.py contienen la lógica de cada nivel.

Creación de carpetas para música, assets y componentes
Dentro del proyecto se creó una carpeta llamada assets, destinada a almacenar todos los recursos utilizados por el juego.
La carpeta assets se dividió principalmente en:
assets/
├── Musica/
└── sprites/
En Musica se almacenaron los archivos de audio del menú y de los niveles:
assets/Musica/
├── Manu.mp3
├── Nivel1.mp3
├── Nivel2.mp3
└── Nivel3.mp3
En sprites se almacenaron los personajes y fondos:
assets/sprites/
├── Atlas/
├── Cyber/
├── Lana/
├── Xenon/
└── Fondos/
Esta separación fue importante para que el código pudiera cargar los recursos de manera ordenada y para evitar mezclar imágenes, música y scripts en una misma ubicación.

Creación de los sprites de cada personaje
Para darle identidad visual al juego se definieron varios personajes principales.
El protagonista es Cyber, un personaje con capucha, gafas oscuras y ojos en forma de X. Sus imágenes fueron organizadas como frames de animación.
La carpeta del personaje Cyber quedó compuesta por archivos similares a:
assets/sprites/Cyber/
├── frame_1.png
├── frame_2.png
├── frame_3.png
├── frame_4.png
└── ...
También se utilizaron otros personajes dentro de la narrativa:
- Atlas, como apoyo o figura de comando.
- Lana, como aliada dentro de la historia.
- Xenon, como villano principal.
- Drones, como enemigos dentro de los niveles.
En el código, los sprites de Cyber se cargan desde la carpeta correspondiente y se escalan para ser utilizados dentro del juego:
def load_frames(self, folder):
frames = []
image_names = [
img_name for img_name in os.listdir(folder)
if img_name.lower().endswith(".png")
]
image_names.sort()
for img_name in image_names:
path = os.path.join(folder, img_name)
img = pygame.image.load(path).convert_alpha()
img = pygame.transform.smoothscale(img, (64, 64))
frames.append(img)
return frames
Esto permitió animar al personaje cambiando entre distintos frames durante el movimiento.

Creación de los fondos del juego
El juego utiliza diferentes fondos para el menú y para cada nivel. Estos fondos ayudan a reforzar la estética digital y cyber del proyecto.
La estructura de fondos quedó organizada así:
assets/sprites/Fondos/
├── menu1.png
├── menu2.png
├── Nivel1/
│ ├── CAPA1.png
│ └── CAPA2.png
├── Nivel2/
│ ├── CAPA1.png
│ └── CAPA2.png
└── Nivel3/
├── CAPA1.png
└── CAPA2.png
Para los niveles se utilizaron dos capas por escenario, lo cual permitió crear un efecto parallax. Este efecto genera sensación de profundidad al mover las capas del fondo a velocidades diferentes.
La clase encargada de dibujar el fondo fue:
class ParallaxBackground:
def __init__(self, capa1_path, capa2_path):
self.capa1 = pygame.image.load(capa1_path).convert_alpha()
self.capa2 = pygame.image.load(capa2_path).convert_alpha()
self.capa1 = pygame.transform.scale(self.capa1, (WIDTH, HEIGHT))
self.capa2 = pygame.transform.scale(self.capa2, (WIDTH, HEIGHT))
def draw(self, screen, player_y):
offset1 = int(player_y * 0.05)
offset2 = int(player_y * 0.15)
y1 = -offset1 % HEIGHT
y2 = -offset2 % HEIGHT
screen.blit(self.capa1, (0, y1 - HEIGHT))
screen.blit(self.capa1, (0, y1))
screen.blit(self.capa2, (0, y2 - HEIGHT))
screen.blit(self.capa2, (0, y2))
Gracias a esto, los niveles no se ven planos, sino que tienen una sensación visual más dinámica.

Selección de música para cada nivel
La música fue organizada según la pantalla o nivel donde se reproduce.
Los archivos seleccionados fueron:
Manu.mp3 → menú principal
Nivel1.mp3 → nivel 1
Nivel2.mp3 → nivel 2
Nivel3.mp3 → nivel 3
En cada nivel se carga la pista correspondiente usando pygame.mixer.music:
pygame.mixer.music.load("assets/Musica/Nivel1.mp3")
pygame.mixer.music.set_volume(0.5)
pygame.mixer.music.play(-1)
El parámetro -1 indica que la música se reproduce en bucle mientras el jugador permanece en esa pantalla o nivel.

Creación de la pantalla inicial
La pantalla inicial se desarrolló en el archivo:
main_menu.py
Esta pantalla contiene el nombre del juego, el fondo principal, la música del menú y los botones de navegación.
El título visual definido fue:
CyberGuardian: Amenaza Xenon
La pantalla principal incluye los botones:
- Iniciar misión.
- Controles.
- Créditos.
- Salir.
El fondo principal se carga desde:
assets/sprites/Fondos/menu1.png
El menú fue mejorado con un panel central translúcido, botones estilo neón y una presentación visual acorde con la temática del juego.

Creación de la pantalla de controles
La pantalla de controles permite al jugador conocer las teclas necesarias antes de iniciar la partida.
Los controles principales son:
A / D Moverse
W / SPACE Saltar
E Interactuar con terminales
1 / 2 / 3 Responder retos
ESC Volver
Durante el desarrollo se detectó que algunos caracteres de flechas se mostraban como cuadros. Para evitar ese problema, las flechas fueron dibujadas directamente con figuras geométricas en Pygame.
def draw_arrow_key(surface, direction, x, y):
key_rect = pygame.Rect(x, y, 70, 55)
pygame.draw.rect(surface, (7, 32, 48), key_rect, border_radius=12)
pygame.draw.rect(surface, CYAN, key_rect, width=2, border_radius=12)
cx, cy = key_rect.center
if direction == "left":
points = [(cx + 14, cy - 15), (cx - 15, cy), (cx + 14, cy + 15)]
elif direction == "right":
points = [(cx - 14, cy - 15), (cx + 15, cy), (cx - 14, cy + 15)]
elif direction == "up":
points = [(cx, cy - 17), (cx - 16, cy + 12), (cx + 16, cy + 12)]
pygame.draw.polygon(surface, WHITE, points)
Esto permitió que la pantalla de controles se viera más limpia y compatible con diferentes equipos.

Creación de niveles en la jerarquía del proyecto
Aunque Pygame no maneja una jerarquía visual como Unity, el proyecto se organizó mediante archivos separados para cada nivel.
Los archivos principales fueron:
nivel1.py
nivel2.py
nivel3.py
Cada nivel contiene:
- Fondo.
- Música.
- Plataformas.
- Enemigos.
- Terminal.
- Puerta.
- Reto.
- HUD.
- Pantalla de finalización.
Esta separación facilita la lectura del código y permite modificar un nivel sin afectar directamente los demás.

Implementación del jugador
El jugador se implementó mediante una clase Player, encargada de controlar el movimiento, la gravedad, las colisiones, la animación y el daño recibido.
El movimiento se controla con el teclado:
def handle_input(self):
keys = pygame.key.get_pressed()
self.vel_x = 0
if keys[pygame.K_a] or keys[pygame.K_LEFT]:
self.vel_x = -self.speed
self.facing_right = False
if keys[pygame.K_d] or keys[pygame.K_RIGHT]:
self.vel_x = self.speed
self.facing_right = True
if (keys[pygame.K_w] or keys[pygame.K_SPACE] or keys[pygame.K_UP]) and self.on_ground:
self.vel_y = self.jump_power
La gravedad se aplica en cada actualización:
def apply_gravity(self):
self.vel_y += 0.5
if self.vel_y > 12:
self.vel_y = 12
Gracias a esta lógica, Cyber puede desplazarse, saltar y caer de forma natural sobre las plataformas.

Implementación de plataformas y colisiones
Los niveles están construidos con plataformas. Cada plataforma se representa como un sprite con un rectángulo de colisión.
class Platform(pygame.sprite.Sprite):
def __init__(self, x, y, w, h):
super().__init__()
self.image = pygame.Surface((w, h), pygame.SRCALPHA)
self.image.fill((25, 25, 38))
pygame.draw.rect(self.image, (0, 180, 255), (0, 0, w, 3))
self.rect = self.image.get_rect(topleft=(x, y))
Las plataformas se agregan a un grupo:
plats = pygame.sprite.Group()
plats.add(Platform(0, HEIGHT - 40, WIDTH, 40))
El jugador detecta colisiones con las plataformas para no atravesarlas y para poder saltar correctamente.
Implementación de enemigos
Los enemigos del juego son drones que patrullan de un lado a otro. Si el jugador entra en contacto con un drone, pierde una vida.
class Drone(pygame.sprite.Sprite):
def __init__(self, x1, x2, y):
super().__init__()
self.x1, self.x2 = x1, x2
self.rect = self.image.get_rect(midbottom=(x1, y))
self.speed = 2
self.dir = 1
def update(self, player):
self.rect.x += self.speed * self.dir
if self.rect.x < self.x1:
self.rect.x = self.x1
self.dir = 1
if self.rect.x > self.x2:
self.rect.x = self.x2
self.dir = -1
if self.rect.colliderect(player.rect):
player.take_damage(1)
Esta mecánica agrega dificultad al juego y obliga al jugador a controlar mejor sus movimientos.

Mejora del HUD del juego
Inicialmente, la información del juego se mostraba con texto plano, como:
Vidas: 3
A/D moverse | W/SPACE saltar | E interactuar
Después se mejoró el HUD para hacerlo más presentable. Se reemplazó el texto por paneles compactos y corazones para representar las vidas.
El HUD final muestra:
- Vidas con corazones.
- Objetivo del nivel.
- Paneles translúcidos.
- Colores acordes con la estética cyber.
Los corazones se dibujaron con figuras de Pygame:
def draw_heart(surface, x, y, size=8, filled=True):
color = RED if filled else (55, 60, 70)
r = size
pygame.draw.circle(surface, color, (x + r, y + r), r)
pygame.draw.circle(surface, color, (x + r * 3, y + r), r)
points = [
(x, y + r),
(x + r * 2, y + r * 4),
(x + r * 4, y + r),
]
pygame.draw.polygon(surface, color, points)
Esta mejora permitió que la interfaz del juego se viera más profesional y menos cargada.

Fin del juego
Después de completar el tercer nivel, se muestra la pantalla final del juego con Xenon. Esta pantalla representa el cierre de la historia y la culminación del recorrido educativo.
El jugador puede finalizar el juego usando:
ENTER
ESC
Botón Finalizar Juego
La pantalla final refuerza la narrativa del proyecto y muestra que Cyber logró superar las trampas de Xenon.

Instalación de PyInstaller
Para generar el ejecutable del juego se utilizó PyInstaller. Esta herramienta permite empaquetar el proyecto Python como una aplicación ejecutable de Windows.
Primero se instaló PyInstaller con:
pip install pyinstaller
También puede instalarse usando:
python -m pip install pyinstaller
Además, el archivo requirements.txt puede incluir:
pygame
pyinstaller

Generación del ejecutable
Antes de generar el ejecutable, se probó el juego desde Python con:
python main_menu.py
Luego se ejecutó el comando de PyInstaller:
python -m PyInstaller --noconfirm --clean --windowed --name CyberGuardian --add-data "assets;assets" main_menu.py
Este comando genera la carpeta:
dist/CyberGuardian/
Dentro de esa carpeta se encuentra el archivo:
CyberGuardian.exe
Para distribuir el juego, se recomienda comprimir toda la carpeta dist/CyberGuardian, ya que el ejecutable necesita los archivos internos generados por PyInstaller.

Resultado final
El resultado fue un videojuego 2D educativo llamado CyberGuardian: , desarrollado con Python y Pygame.
CyberGuardian demuestra cómo un videojuego puede convertirse en una herramienta educativa para reforzar conceptos de ciberseguridad de forma interactiva y visual.
Créditos Finales
- Autores: Eduar Ferney Rodriguez Lopez
- Editor: Carlos Iván Pinzón Romero
- Código: UCCG-10
- Universidad: Universidad Central
Repositorio de GITHUB https://github.com/eduar277/cyberguardian-pygame.git
Referencias
OpenAI. (2023). DALL·E 3. https://openai.com/index/dall-e-3/
OpenAI. (s. f.). DALL·E 3 model. OpenAI API Documentation. https://developers.openai.com/api/docs/models/dall-e-3
Pygame Community. (s. f.). Getting started. Pygame Wiki. https://www.pygame.org/wiki/GettingStarted
Pygame Community. (s. f.). pygame v2.6.0 documentation. https://www.pygame.org/docs/
PyInstaller Development Team. (s. f.). PyInstaller manual. https://www.pyinstaller.org/
Python Software Foundation. (s. f.). Python 3.14.5 documentation. https://docs.python.org/3/
Real Python. (2018). Using PyInstaller to easily distribute Python applications. https://realpython.com/pyinstaller-python/
