University Adventure, un juego de plataformas 2D hecho desde cero en Unity.
Introducción:
La idea del proyecto es hacer un juego de plataforma 2D algo muy parecido a juegos como Mario Bros, el cual consiste en poder saltar y recoger objetos. Donde la idea es poder hacer todo desde cero, las animaciones, el código, los escenarios, sin implementar alguna plantilla o paquete ya creado con estos elementos y descargadas pre-hechas.
Antes de escribir una línea de código o dibujar un píxel, lo primero fue organizar el proyecto. Unity crea automáticamente la carpeta Assets, pero lo que está dentro lo define el desarrollador, y un proyecto desordenado desde el inicio cobra factura después.
La carpeta Scripts terminó con varios archivos, algunos de estos son: CamaraFollow, MenuSelector, MovimientoJugador y Volver. Cada uno tiene una sola responsabilidad.
Las escenas del proyecto muestras como es el flujo completo del juego, desde el menú inicial, la parte jugable, las instrucciones, créditos, geme over, win, escena Idle ( la cual es para la animación del personaje en movimiento) y nivel2. Se intenta mantener todas las ventanas separadas para tener una organización en Unity con respecto a las escenas.

Menú principal
El menú de University Adventure es lo primero que se ve al arrancar el juego, donde se encuentran 4 opciones Start Game, instrucciones, Créditos y Salir, donde se puede navegar con el teclado

La navegación del menú la maneja el script MenuSelector.cs. La idea es que el jugador use las flechas del teclado ( o W/S) para desplazarse entre las opciones, y Enter para confirmar. La opción seleccionada se resalta en amarillo y a un tamaño mayor que las demás para ser diferente y lograr mostrar que puede elegir el jugador.
using UnityEngine;
using UnityEngine.SceneManagement;
using TMPro;
public class MenuSelector : MonoBehaviour
{
public TextMeshProUGUI jugar;
public TextMeshProUGUI instrucciones;
public TextMeshProUGUI creditos;
public TextMeshProUGUI salir;
private TextMeshProUGUI[] opciones;
int indice = 0;
void Start()
{
opciones = new TextMeshProUGUI[]
{
jugar,
instrucciones,
creditos,
salir
};
ActualizarVisual();
}
void Update()
{
// BAJAR
if (Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.S))
{
indice++;
if (indice >= opciones.Length)
indice = 0;
ActualizarVisual();
}
// SUBIR
if (Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.W))
{
indice--;
if (indice < 0)
indice = opciones.Length - 1;
ActualizarVisual();
}
// ENTER
if (Input.GetKeyDown(KeyCode.Return))
{
Seleccionar();
}
// ESC
if (Input.GetKeyDown(KeyCode.Escape))
{
Salir();
}
}
void ActualizarVisual()
{
for (int i = 0; i < opciones.Length; i++)
{
opciones[i].color = Color.white;
opciones[i].fontSize = 40;
}
opciones[indice].color = Color.yellow;
opciones[indice].fontSize = 50;
}
void Salir()
{
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
void Seleccionar()
{
switch (indice)
{
case 0:
SceneManager.LoadScene("SeleccionPersonaje");
break;
case 1:
SceneManager.LoadScene("Instrucciones");
break;
case 2:
SceneManager.LoadScene("Creditos");
break;
case 3:
Salir();
break;
}
}
}
El script guarda las cuadro referencias de TextMeshPro en donde hay varios métodos como ActualizarVisual al momento de seleccionar una opción, seleccionar, Update para poder desplazarse en el menú.
SCRIPT VOLVER
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class Volver : MonoBehaviour
{
private Button boton;
void Start()
{
boton = GetComponent<Button>();
if (boton != null)
{
boton.onClick.AddListener(Regresar);
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.S) ||
Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.W))
{
if (boton != null)
{
boton.Select();
}
}
if (Input.GetKeyDown(KeyCode.Return))
{
Regresar();
}
}
public void Regresar()
{
SceneManager.LoadScene("MenuInicial");
}
}
Las pantallas secundarias como lo son Instrucciones y Créditos tienen un botón para regresar al menú principal. El script Volver.cs se encarga de eso, donde esta el evento onClick del botón del Canvas y también responde a ENTER desde el teclado
PERSONAJE

Por la parte del personaje se tomo con ayuda de Inteligencia Artificial para que nos generara los diseños en 2d donde se le pide que nos diera a el personaje jugable en diferentes posturas, estas animaciones se les debe poner al personaje, ya que sin ser solo una foto movible en le juego sin ninguna animación. Esta animación se la asigna directamente al personaje.
SCRIPT PERSONAJE
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MovimientoJugador : MonoBehaviour
{
[Header("Movimiento")]
public float velocidad = 5f;
public float fuerzaSalto = 8f;
[Header("Sprites de personajes")]
public Sprite spriteCristian;
public Sprite spriteBrayan;
[Header("Opcional: Animator (si usas animaciones)")]
public Animator animator;
private Rigidbody2D rb;
private SpriteRenderer spriteRenderer;
private bool estaEnSuelo;
void Start()
{
rb = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
int seleccion = 0;
if (PersistenciaPersonaje.Instance != null)
{
seleccion = PersistenciaPersonaje.Instance.personajeSeleccionado;
}
if (seleccion == 0 && spriteCristian != null)
{
spriteRenderer.sprite = spriteCristian;
}
else if (seleccion == 1 && spriteBrayan != null)
{
spriteRenderer.sprite = spriteBrayan;
}
if (animator != null)
{
animator.SetInteger("Personaje", seleccion);
}
}
void Update()
{
float movimiento = Input.GetAxisRaw("Horizontal");
rb.linearVelocity = new Vector2(movimiento * velocidad, rb.linearVelocity.y);
if (movimiento != 0)
{
spriteRenderer.flipX = movimiento < 0;
}
if (Input.GetKeyDown(KeyCode.Space) && estaEnSuelo)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, fuerzaSalto);
estaEnSuelo = false;
}
if (animator != null)
{
animator.SetFloat("Velocidad", Mathf.Abs(movimiento));
animator.SetBool("EnSuelo", estaEnSuelo);
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
estaEnSuelo = true;
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("Vacio"))
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
if (collision.transform.CompareTag("Coin"))
{
Destroy(collision.gameObject);
}
if (collision.transform.CompareTag("Spikes"))
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
void OnTriggerExit2D(Collider2D other)
{
if (other.CompareTag("Ground"))
{
estaEnSuelo = false;
}
}
}
En su lógica del personaje se usan los eventos OnCollisionEnter2D y OnCollisionExis2D, las cuales consisten en que el personaje entre en contacto con cualquier objeto con colisionador, como el suelo, muros, obstáculos. La interacción con el entorno funciona con estado en donde si el personaje esta en contacto con el suelo su estado es true, al saltar o ya no estar en contacto con cualquier objeto su estado va hacer false.
SEGUIMIENTO DEL JUGADOR
Para la jugabilidad, la cámara hace un seguimiento del jugador donde se hizo un script CamaraFollow.cs hace exactamente eso, en cada frame actualiza la posición de la cama para que sea igual con las del personaje, manteniendo fija la coordenada Z.
using UnityEngine;
public class CamaraFollow : MonoBehaviour
{
public Transform target;
void LateUpdate()
{
if (target != null)
transform.position = new Vector3(target.position.x, target.position.y, transform.position.z);
}
}

Se empieza ir configurando cada objeto que va a estar en el mundo, los cuales van hacer el suelo para que el personaje no se caiga al vacío, y cada uno de los obstáculos donde ya quedan como plantilla y se le asigna a los personajes que tengas físicas
NAVEGACIÓN DE PERSONAJE
using UnityEngine;
using UnityEngine.SceneManagement;
using TMPro;
public class NavegacionPersonajes : MonoBehaviour
{
[Header("Textos botones")]
public TextMeshProUGUI cristian;
public TextMeshProUGUI brayan;
[Header("Escena de juego")]
public string escenaJuego = "SampleScene";
private TextMeshProUGUI[] opciones;
private int indiceActual = 0;
private PersistenciaPersonaje persistencia;
void Start()
{
persistencia = PersistenciaPersonaje.Instance;
opciones = new TextMeshProUGUI[]
{
cristian,
brayan
};
ActualizarVisual();
}
void Update()
{
// DERECHA
if (Input.GetKeyDown(KeyCode.RightArrow) || Input.GetKeyDown(KeyCode.D))
{
indiceActual++;
if (indiceActual >= opciones.Length)
indiceActual = 0;
ActualizarVisual();
}
// IZQUIERDA
if (Input.GetKeyDown(KeyCode.LeftArrow) || Input.GetKeyDown(KeyCode.A))
{
indiceActual--;
if (indiceActual < 0)
indiceActual = opciones.Length - 1;
ActualizarVisual();
}
// ENTER o ESPACIO
if (Input.GetKeyDown(KeyCode.Return) || Input.GetKeyDown(KeyCode.Space))
{
if (persistencia != null)
{
persistencia.personajeSeleccionado = indiceActual;
SceneManager.LoadScene(escenaJuego);
}
}
}
void ActualizarVisual()
{
for (int i = 0; i < opciones.Length; i++)
{
opciones[i].color = Color.white;
opciones[i].fontSize = 40;
}
opciones[indiceActual].color = Color.yellow;
opciones[indiceActual].fontSize = 50;
}
}

Este script sirve para la elección del personaje en donde se configura el uso de las flechas para tomar la decision de que personaje elegir, en donde al elegir uno, se guarda la eleccion en el archivo de persistencia.
CRÉDITOS
Autor: Brayan Banguera – Cristian Camilo Dominguez
Editor: Carlos Ivan Pinzon Romero
Código: UCCG-9
Universidad: Universidad Central
Fuentes
LuisCanary. (2025, 31 julio). Tutorial COMPLETO de Unity 2D desde CERO | ¡Crea tu propio juego!🎮 [Vídeo]. YouTube. https://www.youtube.com/watch?v=mtA2iIGNCkA
LuisCanary. (2020, 14 abril). Juego de Plataformas 2D/Unity Tutorial/1-Capitulo/Escenario/Programacion videojuegos [Vídeo]. YouTube. https://www.youtube.com/watch?v=-m7ZaHhkDAc
Guía para el Kit de Juego en 2D - Unity Learn. (s. f.). Unity Learn. https://learn.unity.com/tutorial/2d-game-kit-walkthrough-1
Música Sin Copyright. (2020, 8 diciembre). MUSICA PARA JUEGOS (Sin copyright) ️ #8 [Vídeo]. YouTube. https://www.youtube.com/watch?v=583nbl0MnAk
Pablo. (2013, 28 abril). Musica Benny Hill Show [Vídeo]. YouTube. https://www.youtube.com/watch?v=seaG0naD-hI
