En este módulo, profundizaremos en conceptos avanzados de C# que son esenciales para desarrollar juegos complejos y eficientes en Unity. Estos conceptos te permitirán escribir código más robusto, reutilizable y mantenible.
Índice del Tema
- Delegados y Eventos
- Expresiones Lambda
- LINQ (Language Integrated Query)
- Genéricos
- Programación Asíncrona con
async
yawait
- Delegados y Eventos
Delegados
Un delegado es un tipo que representa referencias a métodos con una lista de parámetros y un tipo de retorno específico. Los delegados son útiles para definir métodos de callback y eventos.
Ejemplo de Delegado
public delegate void MyDelegate(string message); public class DelegateExample { public MyDelegate myDelegate; public void Start() { myDelegate = PrintMessage; myDelegate("Hello, Delegates!"); } void PrintMessage(string message) { Debug.Log(message); } }
En este ejemplo, MyDelegate
es un delegado que apunta al método PrintMessage
.
Eventos
Los eventos son una forma de que una clase notifique a otras clases cuando algo interesante sucede. Los eventos se basan en delegados.
Ejemplo de Evento
public class EventExample { public delegate void MyEventHandler(string message); public event MyEventHandler OnMessageReceived; public void TriggerEvent() { if (OnMessageReceived != null) { OnMessageReceived("Event Triggered!"); } } } public class EventListener { private EventExample eventExample; public void Start() { eventExample = new EventExample(); eventExample.OnMessageReceived += HandleEvent; eventExample.TriggerEvent(); } void HandleEvent(string message) { Debug.Log(message); } }
En este ejemplo, OnMessageReceived
es un evento que se dispara en el método TriggerEvent
.
- Expresiones Lambda
Las expresiones lambda son una forma concisa de escribir métodos anónimos. Son útiles para escribir código más limpio y legible.
Ejemplo de Expresión Lambda
public class LambdaExample { public delegate int Operation(int x, int y); public void Start() { Operation add = (x, y) => x + y; int result = add(3, 4); Debug.Log(result); // Output: 7 } }
En este ejemplo, (x, y) => x + y
es una expresión lambda que suma dos números.
- LINQ (Language Integrated Query)
LINQ es una poderosa característica de C# que permite realizar consultas sobre colecciones de datos de manera declarativa.
Ejemplo de LINQ
using System.Linq; public class LINQExample { public void Start() { int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; var evenNumbers = numbers.Where(n => n % 2 == 0); foreach (var num in evenNumbers) { Debug.Log(num); // Output: 2, 4, 6, 8, 10 } } }
En este ejemplo, numbers.Where(n => n % 2 == 0)
utiliza LINQ para filtrar números pares.
- Genéricos
Los genéricos permiten definir clases, métodos y delegados con un tipo de dato que se especifica en tiempo de compilación, proporcionando mayor flexibilidad y seguridad de tipos.
Ejemplo de Genéricos
public class GenericExample<T> { private T item; public void SetItem(T newItem) { item = newItem; } public T GetItem() { return item; } } public class TestGeneric { public void Start() { GenericExample<int> intExample = new GenericExample<int>(); intExample.SetItem(5); Debug.Log(intExample.GetItem()); // Output: 5 GenericExample<string> stringExample = new GenericExample<string>(); stringExample.SetItem("Hello"); Debug.Log(stringExample.GetItem()); // Output: Hello } }
En este ejemplo, GenericExample<T>
es una clase genérica que puede manejar cualquier tipo de dato.
- Programación Asíncrona con
async
y await
async
y await
La programación asíncrona permite ejecutar tareas en segundo plano sin bloquear el hilo principal, mejorando la eficiencia y la capacidad de respuesta de la aplicación.
Ejemplo de async
y await
using System.Threading.Tasks; public class AsyncExample { public async void Start() { Debug.Log("Before Delay"); await Task.Delay(2000); Debug.Log("After Delay"); } }
En este ejemplo, Task.Delay(2000)
simula una operación asíncrona que se completa después de 2 segundos.
Ejercicios Prácticos
Ejercicio 1: Delegados y Eventos
Crea un delegado y un evento que notifique cuando un jugador recoge un objeto en el juego. Implementa una clase Player
y una clase Item
para simular esta interacción.
Ejercicio 2: Expresiones Lambda y LINQ
Utiliza expresiones lambda y LINQ para filtrar una lista de objetos Enemy
que tienen menos de 50 puntos de vida. Imprime los nombres de estos enemigos.
Ejercicio 3: Genéricos
Crea una clase genérica Inventory<T>
que pueda almacenar diferentes tipos de objetos del juego (por ejemplo, armas, pociones). Implementa métodos para agregar y obtener objetos del inventario.
Ejercicio 4: Programación Asíncrona
Implementa una función asíncrona que simule la carga de datos de un servidor. Utiliza async
y await
para esperar la carga y luego imprime un mensaje en la consola.
Soluciones
Solución Ejercicio 1
public delegate void ItemCollectedHandler(string itemName); public class Player { public event ItemCollectedHandler OnItemCollected; public void CollectItem(string itemName) { Debug.Log("Item Collected: " + itemName); OnItemCollected?.Invoke(itemName); } } public class Item { private Player player; public Item(Player player) { this.player = player; player.OnItemCollected += HandleItemCollected; } void HandleItemCollected(string itemName) { Debug.Log("Player collected: " + itemName); } }
Solución Ejercicio 2
using System.Collections.Generic; using System.Linq; public class Enemy { public string Name { get; set; } public int Health { get; set; } } public class Game { public void Start() { List<Enemy> enemies = new List<Enemy> { new Enemy { Name = "Goblin", Health = 30 }, new Enemy { Name = "Orc", Health = 70 }, new Enemy { Name = "Troll", Health = 40 } }; var weakEnemies = enemies.Where(e => e.Health < 50); foreach (var enemy in weakEnemies) { Debug.Log(enemy.Name); } } }
Solución Ejercicio 3
using System.Collections.Generic; public class Inventory<T> { private List<T> items = new List<T>(); public void AddItem(T item) { items.Add(item); } public T GetItem(int index) { return items[index]; } } public class Game { public void Start() { Inventory<string> weaponInventory = new Inventory<string>(); weaponInventory.AddItem("Sword"); Debug.Log(weaponInventory.GetItem(0)); // Output: Sword Inventory<int> potionInventory = new Inventory<int>(); potionInventory.AddItem(5); Debug.Log(potionInventory.GetItem(0)); // Output: 5 } }
Solución Ejercicio 4
using System.Threading.Tasks; public class DataLoader { public async Task LoadData() { Debug.Log("Loading data..."); await Task.Delay(3000); // Simulate data loading Debug.Log("Data loaded."); } } public class Game { public async void Start() { DataLoader dataLoader = new DataLoader(); await dataLoader.LoadData(); } }
Conclusión
En este módulo, hemos explorado conceptos avanzados de C# que son cruciales para el desarrollo de juegos en Unity. Desde delegados y eventos hasta programación asíncrona, estos conceptos te permitirán escribir código más eficiente y manejable. Asegúrate de practicar estos conceptos con los ejercicios proporcionados para consolidar tu comprensión. En el próximo módulo, profundizaremos en técnicas avanzadas de física y programación de inteligencia artificial en Unity.
Curso de Unity
Módulo 1: Introducción a Unity
- Introducción a Unity e Instalación
- Descripción General de la Interfaz de Unity
- Creando Tu Primer Proyecto
- Objetos de Juego Básicos y Componentes
Módulo 2: Programación Básica en Unity
- Introducción a C# para Unity
- Creación y Adjunto de Scripts
- Entendiendo MonoBehaviour
- Manejo Básico de Entradas
Módulo 3: Trabajando con Activos
- Importación y Gestión de Activos
- Uso de la Tienda de Activos
- Creación y Uso de Prefabs
- Animación Básica
Módulo 4: Física y Colisiones
- Introducción a la Física en Unity
- Cuerpos Rígidos y Colisionadores
- Detección Básica de Colisiones
- Uso de Materiales Físicos
Módulo 5: Interfaz de Usuario (UI)
- Introducción a la UI de Unity
- Creación y Personalización de Elementos UI
- Manejo de Eventos UI
- Creación de Menús y HUDs
Módulo 6: Audio en Unity
- Introducción al Audio en Unity
- Importación y Uso de Clips de Audio
- Programación Básica de Audio
- Audio 3D y Sonido Espacial
Módulo 7: Programación Avanzada
- Conceptos Avanzados de C# para Unity
- Corutinas y Programación Asíncrona
- Objetos Scriptables
- Editores Personalizados y Gizmos
Módulo 8: Física Avanzada e IA
- Técnicas Avanzadas de Física
- Búsqueda de Caminos y Navegación
- Programación Básica de IA
- Máquinas de Estado y Árboles de Comportamiento
Módulo 9: Optimización y Rendimiento
- Técnicas de Perfilado y Optimización
- Gestión de Memoria
- Reducción de Llamadas de Dibujo
- Optimización de Física y Colisiones