Niixer

AstraCore Espace: Unity juegoAstraCore Espace: Todo el Proceso de Creación (Unity)AstraCore Espace: Unity juego

AstraCore Escape es un proyecto desarrollado con Unity que combina exploración, parkour y mecánicas de minijuego dentro de un entorno futurista. Este documento presenta el paso a paso del proceso de creación, desde los primeros elementos visuales hasta la integración de inteligencia artificial y la construcción de un minijuego interno.

El objetivo es mostrar el flujo completo de desarrollo, incluyendo decisiones técnicas, herramientas utilizadas y la evolución de los sistemas principales. Este documento sirve tanto como guía para futuros desarrollos como registro del proceso creativo y técnico detrás de AstraCore Escape.

Creación de la Interfaz (UI / Canvas)

Subimos la imagen que queremos usar como fondo del menú. Una vez importada, cambiamos su configuración inicial:

  • Texture Type: Sprite (2D and UI)
  • Sprite Mode: Single

Esto permite que Unity reconozca la imagen como un sprite adecuado para interfaces y pueda utilizarse correctamente dentro del Canvas.

Para agregar el Canvas, nos dirigimos a:
GameObject → UI → Canvas

Esto crea automáticamente un Canvas en la escena, junto con un EventSystem necesario para manejar interacciones en la interfaz.

Una vez agregado el Canvas, añadimos un Panel.
Para esto, hacemos clic derecho sobre el CanvasUI → Panel.
El Panel servirá como contenedor para los elementos visuales de nuestro menú.

Para agregar los botones, seleccionamos el panel que creamos y, sobre él, hacemos clic derecho → UI → Button (TextMeshPro).
De esta forma añadimos un botón con texto editable mediante TextMeshPro

Unity incluye algunas fuentes por defecto, sin embargo, si necesitamos usar una tipografía diferente, podemos descargarla externamente y luego importarla a Unity como cualquier otro archivo (arrastrándola a la carpeta del proyecto). Una vez importada, la podemos asignar a los textos de TextMeshPro o a cualquier elemento UI que la requiera.

Una vez aquí vamos a posicionarnos encima de las letras y con clic derecho Create → TextMeshPro → Font Asset

Ya con esto podemos modificar nuestros textos a nuestro gusto como se ve en la imagen a continuación

Ahora para modificar el botón vamos a seleccionar el botón y abriendo el botón ahora estará texto, ahí vamos a escribir lo que queremos que diga y modificarlo según nuestras necesidades

Una vez tenemos el botón configurado a nuestro gusto, podemos duplicarlo y modificar únicamente el texto para crear las demás opciones del menú. De esta manera mantenemos el mismo estilo y evitamos configurarlo desde cero cada vez.

Ahora vamos a guardar la escena

Una vez se tenga la escena guardada, la idea es que funcione los botones, para esto vamos primero a crear un script para que se redirija a una nueva escena

Una vez creado el script vamos a crear un objeto vacío y a agregar un nuevo componente

En el nuevo componente vinculamos el script que creamos

Ahora nos dirigimos al botón de iniciar y ahí a “button”

Ahí vamos a relacionar el objeto que creamos con el script, ahí vamos a relacionar la función de jugar

Para el botón de opciones, vamos a generar un nuevo panel sobre nuestro Canva

Sobre este nuevo panel vamos a agregar un nuevo texto que diga controles

Ahora en UI – IMAGE, vamos a agregar las imágenes referentes a los  controles como mouse y las letras

Y las configuramos como Sprite y Singles

Ahora sobre el panel con clic derecho vamos a UI- IMAGE y agregamos las imágenes

Para añadir texto, nos posicionamos encima de panel y con clic derecho vamos a UI – TEXT

Ahora según nuestras preferencias lo modificamos a nuestra elección

Ahora para que este panel se oculte y aparezca se crea un script para que se active y desactive según el botón que se de clic

Importación y creación del menú de personajes

El botón “opciones”, nos va a permitir escoger el personaje, por ende nosotros creamos nuestro personaje en AVATURN

Aquí vamos a descargar nuestro modelo inicial en .gbl

Esto nos va a descargar un .zip con el modelo en .fbx y los materiales, debemos subir la carpeta descomprimida a Unity

Ahora vamos a crear un nuevo panel como se indicó anteriormente y lo llamaremos personaje

Y aquí le aplicamos la textura de nuestros personajes, repetimos esto para cada uno

Ahora creamos un objeto vacío, esto es para poder escoger el personaje en el juego

En el objeto vacío ponemos el script de selección de personaje y ubicamos nuestros modelos en cada uno

Luego de esto agregamos botones de selección para cada personaje y agregamos el script a cada botón

Creación del Escenario y Mundo del Juego

Vamos a utilizar un conjunto de prefabricados que nos permitirá construir y organizar nuestro mapa de manera más rápida y eficiente.
Estos prefabs incluyen elementos ya configurados que podemos arrastrar directamente a la escena para ir dando forma al escenario. Pero también podemos insertar nuestros modelos de blender en .fbx de la misma manera arrastrándolos a la carpeta.

cuando lo añadamos a nuestro escena nos aparecerá esto, ya con esto empezaremos a crear nuestro nivel

La idea es que se vea algo similar a la imagen de abajo

Añadimos las texturas y empezamos a modelar el nivel

Vamos a duplicar las salas y asi terminamos de crear el mapa

Ahora vamos a levantar las paredes

Para el techo vamos a duplicar el suelo y rotarlo para que se acople de manera adecuada

Creación del minijuego

Descargamos el fbx del chip para el minijuego

Añadimos el chip a las salas

Ahora creamos dos scripts,

PuzzleManager

using UnityEngine;

public class PuzzleManager : MonoBehaviour

{

    public static PuzzleManager instance;

    public bool[] piecesCollected = new bool[4];

    private void Awake()

    {

        instance = this;

    }

    public void CollectPiece(int id)

    {

        piecesCollected[id] = true;

        UnityEngine.Debug.Log("Pieza " + id + " recogida!");

    }

    public bool HasAllPieces()

    {

        for (int i = 0; i < piecesCollected.Length; i++)

        {

            if (!piecesCollected[i]) return false;

        }

        return true;

    }

}

Y PuzzlePiece

using UnityEngine;

public class PuzzlePiece : MonoBehaviour

{

    public int pieceID;

    private void OnTriggerEnter(Collider other)

    {

        if (other.CompareTag("Player"))

        {

            PuzzleManager.instance.CollectPiece(pieceID);

            UnityEngine.Debug.Log("Recogiste la pieza #" + pieceID);

            Destroy(gameObject);

        }

    }

}

Le añadimos el script de puzzle Piece al chip que hemos creado

Creamos un empty y lo nombramos PuzzleManager, a este empty le agregamos el script de PuzzleManager

Vamos a añadirle Mesh collider al piso para que nuestro personaje no atraviese el piso Y a las paredes tambien

Vamos a añadir ahora el jugador para verificar que el minijuego funcione

Vamos a añadir ahora el jugador para verificar que el minijuego funcione

Le agregamos el capsule collider

Y vamos a hacer el script para el movimiento del jugador

El script se llama PlayerMovement

using UnityEngine;

public class PlayerMovement : MonoBehaviour

{

    public float speed = 5f;

    private Rigidbody rb;

    private void Start()

    {

        rb = GetComponent<Rigidbody>();

    }

    private void FixedUpdate()

    {

        float h = Input.GetAxis(“Horizontal”);

        float v = Input.GetAxis(“Vertical”);

        Vector3 direction = new Vector3(h, 0, v) * speed;

        rb.linearVelocity = new Vector3(direction.x, rb.linearVelocity.y, direction.z);

    }

}

Y vamos a configurar la camara y su movimiento

Para el movimiento de la camara usaremos el siguiente script llamado CameraFollow

using UnityEngine;

public class CameraFollow : MonoBehaviour

{

    public Transform target;

    public Vector3 offset;

    void FixedUpdate()

    {

        if (target != null)

        {

            transform.position = target.position + offset;

        }

    }

}

Y seleccionamos en target el player para que lo siga

En consola nos muestra que recogimos la pieza

Como ya esta funcionando vamos a duplicar la pieza, y las vamos a repartir en las diferentes salas

Duplicamos con Ctrl + D, y vamos a distribuirlas en las salas

Implementación de la IA en enemigos

Descargaremos nuestro personaje (enemigo) desde mixamo, lo descargaremos en pose T y con Skin, también descargaremos las animaciones sin skin y a 60 frames.

Arrastramos el enemigo en pose T a nuestro editor de unity

Crearemos una carpeta para agregar las animaciones y las arrastramos tambien

Seleccionamos la animación y, en el Inspector, vamos a la pestaña Rig.
Allí cambiamos el Animation Type a Humanoid, lo que permite que la animación se adapte correctamente al esqueleto y diseño del enemigo.
Finalmente, hacemos clic en Apply para guardar los cambios.

Vamos a la pestaña Animation y cambiamos el nombre del clip. Luego activamos la opción Loop Time para que la animación se repita de forma continua. Finalmente, hacemos clic en Apply para guardar los cambios.

Luego moveremos la animación fuera del contenedor para poder aplicársela a nuestro personaje

Hacemos este mismo proceso con todas las animaciones que vayamos a utilizar.


Luego creamos un Animator Controller para gestionar el cambio de animaciones según las acciones que realice el personaje.

Construimos los bucles de transición entre animaciones dentro del Animator Controller, definiendo cuándo y cómo cambia cada animación según el comportamiento del personaje.

Al objeto enemigo le agregaremos el componente Animator. Dentro de este componente seleccionaremos el Animator Controller que creamos previamente y asignaremos también el Avatar (esqueleto del personaje) para que las animaciones se reproduzcan correctamente.

Agregaremos el script del enemigo, el cual se encargará de gestionar el cambio de animaciones, el patrullaje aleatorio, y el resto de comportamientos necesarios para su funcionamiento dentro del juego.

using UnityEngine;
using UnityEngine.AI;

public class Enemigo : MonoBehaviour
{
[Header(“Componentes”)]
public NavMeshAgent agent;
public Animator animator;
public string paramCorrer;
public string paramAtacar;

[Header("Jugador")]
public Transform jugador;

[Header("Percepción")]
public float radioDeteccion;
public float radioAtaque;

[Header("Patrulla")]
public float radioPatrulla;
public float tiempoIdle;

private float idleTimer;
private bool tieneDestino = false;
private bool persiguiendo = false;
private bool atacando = false;

[Header("Daño")]
public float tiempoImpacto;    // tiempo exacto del golpe
public float duracionAtaque;   // duración total de la animación
public int daño = 20;

[Header("Cooldown de daño")]
public float tiempoEntreDaños;   // cada cuánto puede hacer daño
private float ultimoDaño;


void Start()
{
    NuevoDestino();
}


void Update()
{
    float distancia = Vector3.Distance(transform.position, jugador.position);

    if (atacando)
    {
        agent.ResetPath();
        return;
    }

    // Detectar jugador
    if (distancia <= radioDeteccion && distancia > radioAtaque)
        persiguiendo = true;
    else if (distancia > radioDeteccion + 2f)
        persiguiendo = false;

    // Atacar
    if (distancia <= radioAtaque)
    {
        StartCoroutine(Atacar());
        return;
    }

    // Perseguir
    if (persiguiendo)
    {
        agent.speed=8;
        agent.SetDestination(jugador.position);
        animator.SetBool(paramCorrer, true);
        return;
    }

    // Patrulla
    animator.SetBool(paramCorrer, agent.velocity.magnitude > 0.1f);

    if (!tieneDestino)
    {
        NuevoDestino();
        return;
    }

    if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance)
    {
        idleTimer += Time.deltaTime;

        if (idleTimer >= tiempoIdle)
        {
            idleTimer = 0f;
            tieneDestino = false;
        }
    }
}



private System.Collections.IEnumerator Atacar()
{
    atacando = true;

    agent.ResetPath();
    agent.speed = 0;
    animator.SetBool(paramCorrer, false);

    animator.SetTrigger(paramAtacar);

    // Esperar al frame del golpe
    yield return new WaitForSeconds(tiempoImpacto);

    // SOLO HACER DAÑO SI YA PASÓ EL COOLDOWN
    if (Time.time - ultimoDaño >= tiempoEntreDaños)
    {
        if (Vector3.Distance(transform.position, jugador.position) <= radioAtaque)
        {
            jugador.GetComponent<VidaJugador>().RecibirDaño(daño);
            ultimoDaño = Time.time;
        }
    }

    // Esperar resto animación
    yield return new WaitForSeconds(duracionAtaque - tiempoImpacto);

    atacando = false;
}



void NuevoDestino()
{
    Vector3 randomDir = Random.insideUnitSphere * radioPatrulla + transform.position;

    NavMeshHit hit;
    if (NavMesh.SamplePosition(randomDir, out hit, radioPatrulla, NavMesh.AllAreas))
    {
        agent.SetDestination(hit.position);
        tieneDestino = true;
    }
    else
    {
        tieneDestino = false;
    }
}



private void OnDrawGizmosSelected()
{
    Gizmos.color = Color.yellow;
    Gizmos.DrawWireSphere(transform.position, radioDeteccion);

    Gizmos.color = Color.red;
    Gizmos.DrawWireSphere(transform.position, radioAtaque);
}

Aquí tienes la redacción mejorada y clara:


Lo más importante para que el enemigo pueda funcionar correctamente y desplazarse por el mapa es crear un NavMesh Surface.
Este componente permite generar la malla de navegación que define las áreas por donde el enemigo puede caminar.
Al hornear (bakear) el NavMesh, las zonas azules indicarán exactamente los lugares del escenario donde la IA puede moverse libremente.


Dentro del componente Enemy Script, debemos especificar cuál es el Player que el enemigo perseguirá dentro del mapa.
Además, en este mismo script se asigna la referencia del propio enemigo y se pueden configurar las demás variables necesarias, como velocidad, distancia de detección, radio de ataque, tiempos de espera y cualquier otro parámetro que controle su comportamiento.

Créditos

Pinzón Romero, C. I. (2025). Universidad Central
Sci-Fi Construction Kit (Modular) | 3D Sci-Fi | Unity Asset Store. (2025, 25 enero). Unity Asset Store. https://assetstore.unity.com/packages/3d/environments/sci-fi/sci-fi-construction-kit-modular-159280
20 Ground Material Sets SCI FI | 2D Textures & Materials | Unity Asset Store. (2014, 18 noviembre). Unity Asset Store. https://assetstore.unity.com/packages/2d/textures-materials/20-ground-material-sets-sci-fi-12401
Sci-Fi Texture Pack 2 | 2D Textures & Materials | Unity Asset Store. (2023, 30 junio). Unity Asset Store. https://assetstore.unity.com/packages/2d/textures-materials/sci-fi-texture-pack-2-42026

Autor:  Yhonatan Estyben Garcia Becerra /Laura Alejandra Castañeda Reina / Diana Marcela Garzon

EditorCarlos Ivan Pinzon Romero

Código: M3DV– 20252

Universidad: Universidad Central