Explorando el Movimiento de Objetos y Estructuras de Datos en Unity

Este artículo explora conceptos fundamentales en el desarrollo de juegos con Unity, centrándose en el movimiento de objetos y el uso de colecciones de datos en C#.

Tipos de Colecciones en C# para Unity

En C#, las colecciones son fundamentales para almacenar y manipular grupos de objetos de manera eficiente. Comprender los diferentes tipos disponibles es crucial para un desarrollo robusto en Unity.

IList

IList es una interfaz que define una lista de elementos que pueden ser accesibles por índice. Es la interfaz base para colecciones de tipo lista que permiten acceso posicional. Incluye métodos para añadir, inesrtar, remover y buscar elementos. Existen versiones genéricas (IList<T>) y no genéricas, siendo la genérica la preferida en la mayoría de los casos por su seguridad de tipo y rendimiento.

List<T>

List<T> es una implementación de la interfaz IList<T>. Es una colección genérica que almacena elementos de un tipo específico T en un array que puede crecer dinámicamente según sea necesario. Ofrece un alto rendimiento para la mayoría de las operaciones, especialmente la adición y el acceso por índice, y es la opción más común cuando se necesita una lista ordenada de elementos del mismo tipo.

ArrayList

ArrayList es una colección no genérica que puede almacenar elementos de cualquier tipo, similar a un array dinámico que implementa IList. Sin embargo, su uso se desaconseja en favor de List<T> debido a que incurre en costos de boxing/unboxing cuando se trabaja con tipos de valor, lo que afecta el rendimiento y la seguridad de tipo. Es más adecuado para proyectos antiguos o escenarios muy específicos donde la heterogeneidad de tipos es una prioridad sin preocuparse por el rendimiento de tipos de valor.

HashSet<T>

HashSet<T> es una colección genérica que almacena un conjunto de elementos únicos, lo que significa que no puede contener elementos duplicados. Los elementos en un HashSet<T> no tienen un orden específico y no se pueden acceder por índice. Proporciona operaciones de conjunto de alto rendimiento, como la adición, eliminación y verificación de existencia de un elemento, lo que lo hace ideal para situaciones donde la unicidad y la rapidez de búsqueda son esenciales.

Hashtable

Hashtable es una colección no genérica que almacena pares clave-valor. Similar a un diccionario, permite acceder a los valores utilizando una clave asociada. Al igual que ArrayList, es una colección más antigua y no genérica. Se recomienda usar Dictionary<TKey, TValue> en su lugar, que es su equivalente genérico, por razones de rendimiento, seguridad de tipo y mejores características.

Principios del Movimiento de Objetos en Juegos

¿Cuál es la esencia del movimiento de un objeto de juego?

La esencia del movimiento de un objeto de juego radica en la alteración continua de sus propiedades de transformación: la Position (posición), Rotation (rotación) y Scale (escala). Cada vez que un objeto se mueve, gira o cambia de tamaño, estas propiedades numéricas se modifican. En Unity, esto se gestiona a través del componente Transform, que es inherente a cada GameObject. Al manipular programáticamente las propiedades de Transform, como transform.position, transform.rotation o transform.localScale, se logra el efecto deseado de movimiento, rotación o redimensionamiento.

Implementación de Trayectorias Parabólicas

A continuación, se presentan tres métodos diferentes para simular un movimiento parabólico en Unity, que típicamente involucra una velocidad horizontal constante y una velocidad vertical afectada por la gravedad.

Método 1: Modificación directa de la propiedad position

Este enfoque calcula la nueva posición del objeto en cada fotograma sumando un vector de desplazamiento basado en la velocidad actual y la influencia de la gravedad.

using UnityEngine;

public class MovimientoParabolicoDirecto : MonoBehaviour
{
   public Transform objetoParabolico; // Referencia al objeto a mover
   public float velocidadHorizontalInicial = 1.0f;
   public float velocidadVerticalInicial = 3.0f;
   public float aceleracionGravitatoria = 2.0f; // Magnitud de la aceleración hacia abajo
   
   private Vector3 velocidadActual; // Almacena la velocidad del objeto

   void Start()
   {
       // Establecer la posición inicial (opcional, puede configurarse en el editor)
       // objetoParabolico.position = new Vector3(0, 0, 0); 
       velocidadActual = new Vector3(velocidadHorizontalInicial, velocidadVerticalInicial, 0);
   }

   void Update()
   {
       // Aplicar la fuerza de la gravedad a la componente Y de la velocidad
       velocidadActual.y -= aceleracionGravitatoria * Time.deltaTime;

       // Actualizar la posición del objeto usando la velocidad actual
       objetoParabolico.position += velocidadActual * Time.deltaTime;

       // Debug.Log($"Velocidad Y actual: {velocidadActual.y}"); // Para monitorear la velocidad vertical
   }
}
   

Método 2: Uso del método transform.Translate

Este método utiliza la función Translate para mover el objeto. Translate toma un vector de desplazamiento y lo aplica a la posición actual del objeto.

using UnityEngine;

public class MovimientoParabolicoTranslate : MonoBehaviour
{
   public Transform entidadMovil; // Referencia al objeto a mover
   public float velocidadInicialX = 1.0f;
   public float velocidadInicialY = 3.0f;
   public float gravedadConstante = 2.0f;
   
   private Vector3 velocidadActualEntidad; // Velocidad para el cálculo de Translate

   void Start()
   {
       // Inicializar la velocidad
       velocidadActualEntidad = new Vector3(velocidadInicialX, velocidadInicialY, 0);
   }

   void Update()
   {
       // Aplicar la gravedad a la componente Y de la velocidad
       velocidadActualEntidad.y -= gravedadConstante * Time.deltaTime;

       // Calcular el desplazamiento basado en la velocidad y el tiempo
       Vector3 desplazamiento = velocidadActualEntidad * Time.deltaTime;

       // Mover el objeto utilizando el método Translate
       entidadMovil.Translate(desplazamiento);

       // Debug.Log($"Velocidad Y Translate: {velocidadActualEntidad.y}");
   }
}
   

Método 3: Modificación de transform.position con un vector de desplazamiento calculado

Similar al primer método, pero aquí se calcula explícitamente el desplazamiento para cada eje y se construye un nuevo vector para sumarlo a la posición.

using UnityEngine;

public class MovimientoParabolicoCalculado : MonoBehaviour
{
   public Transform objetoConTrayectoria; // Referencia al objeto
   public float velocidadXConstante = 1.0f;
   public float velocidadYInicio = 3.0f;
   public float fuerzaGravedad = 2.0f;
   
   private float velocidadYActual; // Velocidad vertical

   void Start()
   {
       velocidadYActual = velocidadYInicio;
       // objetoConTrayectoria.position = new Vector3(0, 0, 0); // Establecer posición inicial si es necesario
   }

   void Update()
   {
       // Calcular el desplazamiento vertical antes de actualizar la velocidad
       float desplazamientoY = velocidadYActual * Time.deltaTime;
       // Actualizar la velocidad vertical con la gravedad
       velocidadYActual -= fuerzaGravedad * Time.deltaTime; 

       // Calcular el desplazamiento horizontal (constante)
       float desplazamientoX = velocidadXConstante * Time.deltaTime;

       // Aplicar el desplazamiento al objeto sumando un nuevo Vector3
       objetoConTrayectoria.position += new Vector3(desplazamientoX, desplazamientoY, 0);

       // Debug.Log($"Velocidad Y Calculada: {velocidadYActual}");
   }
}
   

Simulación de un Sistema Solar

La función RotateAround de Unity es excelente para simular movimientos orbitales. Permite que un GameObject gire alrededor de un punto central (el "centro del círculo") a lo largo de un "eje de rotación" con una "velocidad angular". El plano de rotación es perpendicular al eje de rotación y pasa por el objeto y el centro del círculo.

using UnityEngine;

public class SimulacionSistemaSolar : MonoBehaviour
{
   // Referencias a los objetos Transform de los cuerpos celestes
   public Transform centroSol;
   public Transform planetaMercurio;
   public Transform planetaVenus;
   public Transform planetaTierra;
   public Transform planetaMarte;
   public Transform planetaJupiter;
   public Transform planetaSaturno;
   public Transform planetaUrano;
   public Transform planetaNeptuno;
   public Transform sateliteLuna;

   // Velocidades orbitales y de rotación (grados por segundo)
   public float velocidadOrbitalMercurio = 80f;
   public float velocidadOrbitalVenus = 65f;
   public float velocidadOrbitalTierra = 50f;
   public float velocidadOrbitalMarte = 40f;
   public float velocidadOrbitalJupiter = 25f;
   public float velocidadOrbitalSaturno = 20f;
   public float velocidadOrbitalUrano = 15f;
   public float velocidadOrbitalNeptuno = 10f;
   public float velocidadOrbitalLuna = 120f;
   public float velocidadRotacionTierra = 30f; // Rotación sobre su propio eje

   void Start()
   {
       // Posicionar el Sol en el origen del mundo
       centroSol.position = Vector3.zero;

       // Establecer posiciones iniciales de los planetas, espaciados en el eje X
       // Se añaden pequeñas desviaciones en Y o Z para que no estén perfectamente alineados
       planetaMercurio.position = new Vector3(3.5f, 0.2f, 0);
       planetaVenus.position = new Vector3(6.0f, -0.3f, 0);
       planetaTierra.position = new Vector3(9.5f, 0.1f, 0);
       planetaMarte.position = new Vector3(13.0f, -0.2f, 0);
       planetaJupiter.position = new Vector3(18.0f, 0.5f, 0);
       planetaSaturno.position = new Vector3(22.0f, -0.4f, 0);
       planetaUrano.position = new Vector3(26.0f, 0.3f, 0);
       planetaNeptuno.position = new Vector3(30.0f, -0.1f, 0);

       // Posicionar la Luna cerca de la Tierra
       sateliteLuna.position = planetaTierra.position + new Vector3(2f, 0.5f, 0);
   }

   void Update()
   {
       // Orbita de Mercurio alrededor del Sol
       planetaMercurio.RotateAround(centroSol.position, new Vector3(0.1f, 1f, 0.3f).normalized, velocidadOrbitalMercurio * Time.deltaTime);

       // Orbita de Venus alrededor del Sol
       planetaVenus.RotateAround(centroSol.position, new Vector3(-0.2f, 1f, 0.1f).normalized, velocidadOrbitalVenus * Time.deltaTime);

       // Orbita de la Tierra alrededor del Sol
       planetaTierra.RotateAround(centroSol.position, new Vector3(0.05f, 1f, 0.05f).normalized, velocidadOrbitalTierra * Time.deltaTime);
       // Rotación de la Tierra sobre su propio eje
       planetaTierra.Rotate(Vector3.up * velocidadRotacionTierra * Time.deltaTime);

       // Orbita de Marte alrededor del Sol
       planetaMarte.RotateAround(centroSol.position, new Vector3(0.1f, 1f, -0.2f).normalized, velocidadOrbitalMarte * Time.deltaTime);

       // Orbita de Júpiter alrededor del Sol
       planetaJupiter.RotateAround(centroSol.position, new Vector3(-0.3f, 1f, 0.4f).normalized, velocidadOrbitalJupiter * Time.deltaTime);

       // Orbita de Saturno alrededor del Sol
       planetaSaturno.RotateAround(centroSol.position, new Vector3(0.2f, 1f, -0.5f).normalized, velocidadOrbitalSaturno * Time.deltaTime);

       // Orbita de Urano alrededor del Sol
       planetaUrano.RotateAround(centroSol.position, new Vector3(0.4f, 1f, 0.1f).normalized, velocidadOrbitalUrano * Time.deltaTime);

       // Orbita de Neptuno alrededor del Sol
       planetaNeptuno.RotateAround(centroSol.position, new Vector3(-0.1f, 1f, 0.6f).normalized, velocidadOrbitalNeptuno * Time.deltaTime);

       // Orbita de la Luna alrededor de la Tierra
       sateliteLuna.RotateAround(planetaTierra.position, new Vector3(0.5f, 1f, 0.2f).normalized, velocidadOrbitalLuna * Time.deltaTime);
   }
}
   

Etiquetas: Unity C# Game Development collections Movement

Publicado el 7-27 01:45