Guía de Scripting en Unity: Fundamentos y Manipulación de Objetos

Este documento detalla los pasos iniciales y conceptos clave para trabajar con scripts en Unity, abarcando la creación, el comportamiento de los objetos, el movimiento, la rotación y la interacción básica.

Creación del Primer Script

Para comenzar a programar en Unity, sigue estos pasos:

  1. Añadir un script: Haz clic derecho en la ventana del Proyecto, selecciona Create > C# Script. El nombre del archivo definirá la clase del script (ej. GestorMovimiento).

  2. Verificar la concordancia: Abre el script en tu editor de código (como Visual Studio). Asegúrate de que el nombre de la clase coincida exactamente con el nombre del archivo.

  3. Escribir código inicial: Dentro del método Start(), que se ejecuta una vez al inicio, puedes añadir una instrucción de registro. Por ejemplo: ```

    using UnityEngine;

    public class GestorMovimiento : MonoBehaviour { void Start() { Debug.Log("¡Mi primer script ha sido ejecutado!"); } }

    
     `Debug.Log()` es una herramienta útil de la API de Unity para mostrar mensajes en la consola.
    
  4. Guardar y compilar: Guarda el archivo (Ctrl+S) y cierra el editor. Unity compilará automáticamente el script al detectar cambios.

  5. Asignar el script a un objeto: Puedes adjuntar el script a un GameObject de dos maneras:

    • Selecciona el GameObject, haz clic en Add Component y busca tu script en la sección Scripts.
    • Arrastra directamente el archivo del script desde la ventana del Proyecto a la ventana del Inspector del GameObject seleccionado.
  6. Ejecutar y observar: Presiona el botón de Play en Unity. Si la ventana de Console no está visible, puedes abrirla desde Window > General > Console. Deberías ver el mensaje que añadiste. Detén la ejecución para continuar.

Posicionamiento y Movimiento de Objetos

Unity maneja las coordenadas de los objetos en un espacio 3D. El movimiento se puede lograr de diversas formas, incluyendo el movimiento relativo y la dirección basada en la orientación del objeto.

Movimiento Basado en la Orientación y Distancia

El siguiente código hace que un objeto se mueva hacia un objetivo específico, ajustando su dirección y distancia.


using UnityEngine;

public class SeguidorObjeto : MonoBehaviour
{
    public string nombreObjetivo = "Objetivo"; // Nombre del objeto a seguir
    private Transform transformObjetivo;

    void Start()
    {
        // Busca el objeto por su nombre
        GameObject objObjetivo = GameObject.Find(nombreObjetivo);
        if (objObjetivo != null)
        {
            transformObjetivo = objObjetivo.transform;
            // Orienta el objeto hacia el objetivo al inicio
            this.gameObject.transform.LookAt(transformObjetivo);
        }
        else
        {
            Debug.LogError($"No se encontró el objeto con el nombre: {nombreObjetivo}");
        }
    }

    void Update()
    {
        if (transformObjetivo != null)
        {
            // Mueve el objeto hacia adelante en su espacio local
            float velocidadMovimiento = 3.0f;
            float distanciaEsteFrame = velocidadMovimiento * Time.deltaTime;
            this.gameObject.transform.Translate(0, 0, distanciaEsteFrame, Space.Self);
        }
    }
}
        

Ejercicio: Seguir hasta una Distancia Detreminada

Este ejemplo extiende el anterior para que el objeto se detenga cuando esté lo suficientemente cerca del objetivo.


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SeguidorConDistancia : MonoBehaviour
{
    public string nombreObjetivo = "Objetivo";
    public float distanciaMinima = 0.3f; // Distancia para detenerse
    private Transform transformObjetivo;

    void Start()
    {
        GameObject objObjetivo = GameObject.Find(nombreObjetivo);
        if (objObjetivo != null)
        {
            transformObjetivo = objObjetivo.transform;
            this.gameObject.transform.LookAt(transformObjetivo);
        }
        else
        {
            Debug.LogError($"No se encontró el objeto con el nombre: {nombreObjetivo}");
        }
    }

    void Update()
    {
        if (transformObjetivo != null)
        {
            Vector3 posicionActual = this.gameObject.transform.position;
            Vector3 posicionObjetivo = transformObjetivo.position;
            Vector3 diferenciaVector = posicionActual - posicionObjetivo;
            float distanciaAlObjetivo = diferenciaVector.magnitude;

            if (distanciaAlObjetivo > distanciaMinima)
            {
                float velocidadMovimiento = 3.0f;
                float distanciaEsteFrame = velocidadMovimiento * Time.deltaTime;
                this.gameObject.transform.Translate(0, 0, distanciaEsteFrame, Space.Self);
            }
        }
    }
}
        

Nota: La función GameObject.Find() es sensible a mayúsculas y minúsculas y puede ser lenta si se usa repetidamente. Para objetos con nombres duplicados o en jerarquías complejas, es preferible usar otros métodos de obtención.

Truco: Al seleccionar la opción "Lock View" en la ventana de Scene, la cámara seguirá al objeto seleccionado automáticamente.

Rotación de Objetos

Los objetos en Unity pueden rotar sobre sus propios ejes o en relación con otros objetos.

Rotación Continua en el Eje Y (Local)

Este script hace que un objeto rote continuamente alrededor de su eje Y local.


using UnityEngine;

public class RotadorLocal : MonoBehaviour
{
    void Start()
    {
        // Limita la tasa de frames a 60 por segundo
        Application.targetFrameRate = 60;
    }

    void Update()
    {
        float velocidadRotacion = 60.0f; // Grados por segundo
        // Rota el objeto en su eje Y local
        this.gameObject.transform.Rotate(0, velocidadRotacion * Time.deltaTime, 0, Space.Self);
    }
}
        

Sistema Tierra-Luna (Rotación Relativa)

Simula el movimiento orbital y de rotación de planetas.


// Script para el Planeta (ej. Tierra)
using UnityEngine;

public class LogicaPlaneta : MonoBehaviour
{
    void Start()
    {
        Application.targetFrameRate = 60;
    }

    void Update()
    {
        float velocidadRotacionPlaneta = 10.0f;
        // Rota el planeta sobre sí mismo
        this.transform.Rotate(0, velocidadRotacionPlaneta * Time.deltaTime, 0, Space.Self);
    }
}
        

// Script para la Luna
using UnityEngine;

public class LogicaLuna : MonoBehaviour
{
    void Start()
    {
        Application.targetFrameRate = 60;
    }

    void Update()
    {
        float velocidadOrbitaLuna = 30.0f;
        // Rota el objeto padre (que contiene al planeta y la luna)
        Transform padre = this.transform.parent;
        if (padre != null)
        {
            padre.Rotate(0, velocidadOrbitaLuna * Time.deltaTime, 0, Space.Self);
        }
    }
}
        

Para este sistema, la Luna debería ser un hijo del Planeta en la jerarquía, y el script de la Luna se aplicaría al objeto padre (el Planeta) para simular la órbita.

Parámetros y Referencias en Scripts

Los scripts pueden exponer variables públicamente para ser configuradas desde el Inspector de Unity.

Parámetros Públicos y Tooltips

Las variables declaradas como public aparecen en el Inspector. La directiva [Tooltip()] añade una descripción emergente al pasar el ratón sobre el parámetro.


using UnityEngine;

public class ParametrosRotacion : MonoBehaviour
{
    [Tooltip("Velocidad de rotación en grados por segundo.")]
    public float velocidadRotacion = 50.0f;

    void Update()
    {
        this.transform.Rotate(0, velocidadRotacion * Time.deltaTime, 0, Space.Self);
    }
}
        

Tipos de Referencia

Se pueden asignar referencias a otros componentes u objetos de Unity directamente en el Inspector, arrastrando el objeto deseado al campo correspondiente.

Depuración y Modificación de Parámetros en Tiempo de Ejecución

Unity permite modificar los valores de las variables públicas mientras el juego está en ejecución, pero estos cambios se pierden al detener la simulación. Para conservarlos temporalmente, se puede copiar y pegar los valores entre la ejecución y la edición.

Entrada del Usuario (Teclado y Ratón)

Entrada del Ratón

Los eventos del ratón se activan al hacer clic en la ventana de Game.

Posición del Ratón

Se puede obtener la posición del cursor en coordenadas de pantalla.

Entrada del Teclado

Detectar pulsaciones de teclas permite controlar acciones en el juego.


using UnityEngine;

public class ControlMovimientoTeclado : MonoBehaviour
{
    public float velocidadMovimiento = 0f;
    public float velocidadBase = 5.0f; // Velocidad base de movimiento

    void Update()
    {
        velocidadMovimiento = 0;
        // Detecta si la tecla 'W' está siendo presionada continuamente
        if (Input.GetKey(KeyCode.W))
        {
            velocidadMovimiento = velocidadBase;
        }
        // Detecta si la tecla 'S' está siendo presionada continuamente
        else if (Input.GetKey(KeyCode.S))
        {
            velocidadMovimiento = -velocidadBase;
        }

        // Mueve el objeto hacia adelante/atrás en su eje Z local
        this.gameObject.transform.Translate(0, 0, velocidadMovimiento * Time.deltaTime, Space.Self);
    }
}
        

Nota: Input.GetKey() detecta la pulsación cotninua, mientras que Input.GetKeyDown() solo se activa una vez al presionar la tecla.

Invocación de Componentes y Métodos

Referencia a Componentes de Audio

Se puede obtener una referencia a un componente AudioSource para reproducir sonidos.

Play() vs PlayOneShot():

Característica audio.Play() audio.PlayOneShot()
Exclusividad Interrumpe el audio que se está reproduciendo en el mismo AudioSource. No interrumpe, se reproduce superpuesto al audio actual.
Control de Volumen Controla el volumen global del AudioSource mediante audio.volume. Controla el volumen de la reproducción actual mediante el parámetro volumeScale, sin afectar el volumen base.
Casos de Uso Adecuado para sonidos únicos y exclusivos (música de fondo, diálogos principales). Ideal para sonidos cortos, frecuentes y superponibles (disparos, pasos, clics de UI).

Usar PlayOneShot() es beneficioso para reproducir múltiples efectos de sonido sin interrupciones.


using UnityEngine;

public class ReproductorSonidos : MonoBehaviour
{
    public AudioClip clipExito; // Clip de audio para el éxito
    public AudioClip clipFallo; // Clip de audio para el fallo

    void Update()
    {
        AudioSource fuenteAudio = GetComponent<audiosource>();

        // Reproduce el clip de éxito al presionar 'A'
        if (Input.GetKeyDown(KeyCode.A))
        {
            if (fuenteAudio != null && clipExito != null)
            {
                fuenteAudio.PlayOneShot(clipExito);
            }
        }

        // Reproduce el clip de fallo al presionar 'B'
        if (Input.GetKeyDown(KeyCode.B))
        {
            if (fuenteAudio != null && clipFallo != null)
            {
                fuenteAudio.PlayOneShot(clipFallo);
            }
        }
    }
}
        </audiosource>

Arrays de Recursos (AudioClips)

Se pueden gestionar múltiples recursos, como canciones, en un array.


using UnityEngine;

public class CajaMusical : MonoBehaviour
{
    public AudioClip[] listaCanciones; // Array de clips de audio
    private AudioSource reproductor;

    void Start()
    {
        reproductor = GetComponent<audiosource>();
        if (listaCanciones == null || listaCanciones.Length == 0)
        {
            Debug.LogWarning("No hay canciones asignadas en la lista.");
        }
    }

    void Update()
    {
        // Cambia de canción al hacer clic con el ratón izquierdo
        if (Input.GetMouseButtonDown(0))
        {
            CambiarCancionAleatoria();
        }
    }

    void CambiarCancionAleatoria()
    {
        if (listaCanciones != null && listaCanciones.Length > 0 && reproductor != null)
        {
            int indiceAleatorio = Random.Range(0, listaCanciones.Length);
            AudioClip cancionSeleccionada = listaCanciones[indiceAleatorio];

            reproductor.clip = cancionSeleccionada;
            reproductor.Play(); // Usa Play() para reemplazar la canción actual
            Debug.Log($"Reproduciendo: {cancionSeleccionada.name} (Índice: {indiceAleatorio})");
        }
    }
}
        </audiosource>

Llamadas Temporizadas

Unity permite ejecutar métodos después de un cierto retardo o de forma repetida.


using UnityEngine;

public class TemporizadorAcciones : MonoBehaviour
{
    void Start()
    {
        Debug.Log($"Inicio del juego. Tiempo actual: {Time.time}");

        // Llama a DoSomething después de 1 segundo
        // this.Invoke("DoSomething", 1.0f);

        // Llama a DoSomething cada 0.5 segundos, comenzando después de 1 segundo
        this.InvokeRepeating("DoSomething", 1.0f, 0.5f);
    }

    void Update()
    {
        // El método Update se ejecuta en cada frame
    }

    private void DoSomething()
    {
        Debug.Log($"Acción ejecutada. Tiempo actual: {Time.time}");
    }
}
        

Ejercicio: Semáforo (Cambio de Luces)

Simula el ciclo de luces de un semáforo.


using UnityEngine;

public class LogicaSemaforo : MonoBehaviour
{
    public Material[] materialesLuces; // Array de materiales para Rojo, Amarillo, Verde
    private int indiceActual = 0;
    private MeshRenderer renderizador;

    void Start()
    {
        renderizador = GetComponent<meshrenderer>();
        if (materialesLuces == null || materialesLuces.Length == 0)
        {
            Debug.LogError("Materiales de luces no asignados.");
            return;
        }
        CambiarLuz(); // Inicia el ciclo
    }

    void Update()
    {
        // El ciclo de luces se maneja mediante Invoke
    }

    private void CambiarLuz()
    {
        if (renderizador != null && materialesLuces.Length > 0)
        {
            renderizador.material = materialesLuces[indiceActual];
            Debug.Log($"Luz cambiada a: {materialesLuces[indiceActual].name}. Tiempo: {Time.time}");

            float tiempoEspera;
            // Determina el tiempo de espera según el color
            switch (indiceActual)
            {
                case 0: // Rojo
                    tiempoEspera = 4.0f;
                    break;
                case 1: // Amarillo
                    tiempoEspera = 1.5f;
                    break;
                case 2: // Verde
                    tiempoEspera = 4.0f;
                    break;
                default:
                    tiempoEspera = 1.0f; // Por seguridad
                    break;
            }

            // Programa el próximo cambio de luz
            Invoke("CambiarLuz", tiempoEspera);
        }

        // Avanza al siguiente índice, ciclando si es necesario
        indiceActual++;
        if (indiceActual >= materialesLuces.Length)
        {
            indiceActual = 0;
        }
    }
}
        </meshrenderer>

Importante: La llamada inicial a CambiarLuz() debe estar en Start(), no en Update().

Ejercicio: Aceleración y Deceleración (Ventilador)

Controla la velocidad de rotación de un objeto, simulando aceleración y desaceleración.


using UnityEngine;

public class LogicaVentilador : MonoBehaviour
{
    public float velocidadActual = 0f;
    public float velocidadMaxima = 720f; // RPM máximas
    public bool acelerando = false; // Indica si está acelerando o desacelerando

    // Intervalo de tiempo para ajustar la velocidad
    public float intervaloJustaVelocidad = 0.1f;
    // Incremento/decremento de velocidad por intervalo
    public float cambioVelocidadPorIntervalo = 10f;

    void Start()
    {
        // Programa la función para ajustar la velocidad periódicamente
        InvokeRepeating("JustificarVelocidad", intervaloJustaVelocidad, intervaloJustaVelocidad);
    }

    void Update()
    {
        // Cambia el estado de aceleración al hacer clic
        if (Input.GetMouseButtonDown(0))
        {
            acelerando = !acelerando;
        }

        // Aplica la rotación si la velocidad es mayor que cero
        if (velocidadActual > 0)
        {
            this.transform.Rotate(0, velocidadActual * Time.deltaTime, 0, Space.Self);
        }
    }

    void JustificarVelocidad()
    {
        if (acelerando)
        {
            // Acelera hasta la velocidad máxima
            if (velocidadActual < velocidadMaxima)
            {
                velocidadActual += cambioVelocidadPorIntervalo;
                // Asegura que no exceda la máxima
                velocidadActual = Mathf.Min(velocidadActual, velocidadMaxima);
            }
        }
        else
        {
            // Desacelera hasta cero
            if (velocidadActual > 0)
            {
                velocidadActual -= cambioVelocidadPorIntervalo;
                // Asegura que no sea negativa
                velocidadActual = Mathf.Max(velocidadActual, 0f);
            }
        }
    }
}
        

Vectores en Unity

Los vectores son fundamentales para representar direcciones y magnitudes en el espacio 3D.

  • Un vector (0,0,0) normalizado sigue siando (0,0,0).
  • Permiten realizar operaciones como suma, resta y escalado.
  • Se utilizan para calcular distancias y direcciones entre puntos.

Uso de Vectores para el Movimiento

Se puede definir una velocidad como un vector y aplicarla al movimiento del objeto.


using UnityEngine;

public class MovimientoVectorial : MonoBehaviour
{
    // Define la velocidad como un vector editable en el Inspector
    public Vector3 velocidadTranslacion;

    void Update()
    {
        // Aplica el vector de velocidad para trasladar el objeto en su espacio local
        // Multiplicado por Time.deltaTime para que sea independiente de la tasa de frames
        this.transform.Translate(velocidadTranslacion * Time.deltaTime, Space.Self);
    }
}
        

Al definir un parámetro de tipo Vector3 como público, Unity proporciona campos para editar los componentes X, Y y Z directamente en el Inspector.

Etiquetas: Unity C# scripting programación Game Development

Publicado el 8-15 10:08