Temario: patrones de diseño, Singleton, máquinas de estados, interfaces, localización y editor multimedia interactivo en Unity
Alumno: ______________________ Fecha: __ / __ / _____
Duración orientativa: 1 h 30 min
PARTE 1 – Teoría (10 × 1 punto)
Responde de forma breve y clara.
- Explica con tus palabras en qué se diferencia un Singleton de una clase estática en C# dentro de Unity.
- Cita dos casos de uso adecuados para aplicar el patrón Singleton en un videojuego y justifica por qué.
- En el contexto de una máquina de estados para un personaje o una herramienta de editor, ¿qué entendemos por:
- Estado
- Transición
- ¿Qué ventaja tiene separar los estados en clases distintas (patrón State con clases/Interfaces) frente a tener toda la lógica en un único
Update()con muchosif/else? - Define qué es una interfaz en C# y explica por qué son útiles cuando tenemos objetos del juego que comparten comportamientos (por ejemplo, objetos que se pueden seleccionar, mover o rotar).
- ¿Qué es el patrón Observer (u “observador”) y cómo podría aplicarse a un sistema de UI que reacciona a cambios en el estado del juego?
- Explica qué es la localización en juegos y qué diferencia hay entre “internacionalización” (i18n) y “localización” (l10n).
- ¿Por qué es una mala práctica escribir directamente los textos (“Crear”, “Move”, “Eliminar”) dentro del código en vez de usar un sistema de localización o tablas de texto?
- En el Editor Multimedia Interactivo, ¿por qué es recomendable que el EditorManager no sea responsable de reproducir audio directamente, sino apoyarse en un
AudioManageru otro sistema? - ¿Qué entendemos por “feedback” o “juiciness” en un editor o videojuego? Da un ejemplo sonoro y un ejemplo visual.
PARTE 2 – Código / Desarrollo (5 × 2 puntos)
11. Singleton con acceso desde otros scripts
Completa el siguiente Singleton para un GameManager que controle el estado general del editor:
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
public bool IsPaused { get; private set; }
private void Awake()
{
// TODO: implementar patrón Singleton (solo una instancia)
}
public void SetPaused(bool paused)
{
IsPaused = paused;
// TODO: aquí podríamos notificar a otros sistemas
}
}
a) Completa Awake para aplicar el patrón Singleton.
b) Escribe un ejemplo de cómo otro script podría comprobar si el juego está en pausa usando este Singleton.
12. Estados del editor con enum y switch
Crea un enum llamado ToolState con los valores: None, Create, Move, Rotate, Delete.
Dentro de un EditorManager, escribe un método HandleInput() que utilice un switch sobre ToolState para:
- En
Create→ llamar aHandleCreateMode() - En
Move→ llamar aHandleMoveMode() - En
Rotate→ llamar aHandleRotateMode() - En
Delete→ llamar aHandleDeleteMode() - En
None→ no hacer nada especial
(No hace falta implementar los métodos, solo llamarlos.)
13. Interfaces para herramientas del editor
Diseña una interfaz ITool para representar una herramienta de editor (Crear, Mover, Rotar, Eliminar) con al menos:
void OnEnterTool();
void OnExitTool();
void OnUpdateTool();
Después escribe la cabecera de una clase CreateTool que implemente la interfaz.
14. Interfaz para objetos localizables
Crea una interfaz ILocalizableText que se pueda usar en componentes de UI para actualizar su texto cuando cambie el idioma. Debe tener un método como:
void UpdateText();
Después, escribe un ejemplo de componente LocalizedLabel que implemente ILocalizableText, y que tenga un campo public string key; para la clave de localización.
15. Localización usando un diccionario
Plantea una implementación sencilla de un LocalizationManager que:
- Tenga un diccionario
<string, string>con claves y textos. - Tenga un método
LoadLanguage(string code)que rellene el diccionario (puedes simularlo). - Tenga un método
GetText(string key)que devuelva el texto o la propia clave si no existe.
No hace falta que cargues ficheros reales; basta con simularlo en código.
PARTE 3 – Caso práctico: Editor Multimedia Interactivo (5 × 3 puntos)
Basado en el documento de “Realización de un Editor Multimedia Interactivo”.
16. Diseño del Menú de Acciones (inferior)
Describe cómo debe comportarse el Menú de Acciones (inferior) según la práctica:
- ¿Qué botones contiene?
- ¿Cómo se muestra y oculta?
- ¿Qué relación tiene con el estado actual de la herramienta en el editor?
17. Flujo de uso del Menú de Objetos (lateral) en modo Crear
Explica paso a paso qué ocurre cuando el usuario:
- Pulsa el botón
Crearen el menú de acciones. - Aparece el menú de objetos (lateral).
- Selecciona un prefab del listado.
- Coloca el objeto en el escenario.
Menciona el papel del raycast y del objeto “fantasma” (preview).
18. Control de rotación de un objeto
Diseña un posible flujo para la herramienta Rotar:
- Cómo se selecciona un objeto para rotar.
- Qué input del ratón o teclado usarías para rotar (por ejemplo, mover el ratón horizontalmente).
- Cómo se confirma la rotación.
- Cómo se vuelve al estado neutro.
19. Integración de audio en el editor
Explica cómo integrarías un AudioManager (Singleton) con los estados/herramientas del editor para:
- Reproducir un sonido al cambiar de herramienta.
- Reproducir un sonido al colocar un objeto.
- Reproducir un sonido al eliminar un objeto.
No hace falta código completo, pero sí una descripción clara de quién llama a quién.
20. Mejora de la experiencia mediante feedback
Propón cuatro mejoras concretas de feedback (visuales o sonoras) sobre la base del enunciado de la práctica.
Ejemplos: animaciones en la UI, partículas al colocar objetos, sombreado del objeto seleccionado, etc. Indica en qué momento se activan.
SOLUCIONES ORIENTATIVAS – SIMULACRO 2
Parte 1 – Teoría
- Singleton vs clase estática
- Singleton: instancia única, pero es un objeto real (
MonoBehaviour), puede tener estado asociado a la escena, usarStart(),Update(), corutinas, etc. - Clase estática: no se instancia, no puede heredarse de
MonoBehaviour, no puede estar asociada directamente a GameObjects ni usar corutinas de Unity.
- Singleton: instancia única, pero es un objeto real (
- Casos de uso adecuados Singleton
AudioManager: gestiona música y efectos sin duplicarse entre escenas.GameManageroSceneManagerpropio: controla estado global de la partida.
Justificación: se necesita un único punto de acceso y una única instancia.
- Estado / Transición
- Estado: modo actual del sistema (ej.:
Create,Move,Rotating,Idle). - Transición: cambio de un estado a otro provocado por un evento (botón pulsado, input del jugador, condición lógica…).
- Estado: modo actual del sistema (ej.:
- Ventaja de separar estados en clases
- Cada estado tiene su propia clase y responsabilidad → código más limpio, mantenible y extensible.
- Evita un único
Update()enorme lleno deif/elseoswitchque mezclan lógica muy distinta.
- Interfaz en C#
- Contrato que define métodos/propiedades sin implementación.
- Útil para que distintos objetos compartan capacidades: por ejemplo, todos los objetos que se pueden seleccionar implementan
ISelectable, independientemente de su tipo concreto.
- Patrón Observer
- Hay un sujeto (subject) que notifica a varios observadores cuando cambia su estado.
- En un sistema de UI: el
GameManagerpuede notificar a paneles de HUD cuando cambia el modo de herramienta, y estos actualizan iconos y textos sin que el manager conozca los detalles de cada panel.
- Localización vs Internacionalización
- Internacionalización (i18n): preparar el juego para que pueda traducirse fácilmente (separar textos, evitar hardcodear cadenas).
- Localización (l10n): adaptar el juego a un idioma/cultura concreto (traducciones, formatos, símbolos).
- Mala práctica de textos incrustados
- Dificulta traducir y mantener el juego.
- Obliga a modificar código para cambiar una simple cadena.
- Rompe el principio de separación de responsabilidades (lógica ≠ presentación).
- Separar EditorManager de Audio
- EditorManager debería controlar lógica de estados, no detalles de audio.
- Un
AudioManagerdedicado se encarga de colas de sonido, volúmenes, cambios de música, etc. → código más limpio, más fácil de reutilizar.
- Feedback / Juiciness
- Conjunto de detalles visuales y sonoros que hacen la interacción más clara y satisfactoria.
- Ejemplo sonoro: efecto “click” al pulsar un botón de UI.
- Ejemplo visual: ligera animación de escala del botón al pasar el ratón o al pulsarlo.
Parte 2 – Código
11. Singleton y acceso
public class GameManager : MonoBehaviour
{
public static GameManager Instance { get; private set; }
public bool IsPaused { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
}
public void SetPaused(bool paused)
{
IsPaused = paused;
// aquí podríamos notificar a otros sistemas (Observer)
}
}
Ejemplo de uso desde otro script:
if (GameManager.Instance != null && GameManager.Instance.IsPaused)
{
// no actualizar lógica porque el juego está en pausa
}
12. Máquina de estados con enum y switch
public enum ToolState
{
None,
Create,
Move,
Rotate,
Delete
}
public class EditorManager : MonoBehaviour
{
public ToolState currentTool = ToolState.None;
private void Update()
{
HandleInput();
}
private void HandleInput()
{
switch (currentTool)
{
case ToolState.Create:
HandleCreateMode();
break;
case ToolState.Move:
HandleMoveMode();
break;
case ToolState.Rotate:
HandleRotateMode();
break;
case ToolState.Delete:
HandleDeleteMode();
break;
case ToolState.None:
default:
// no hay herramienta activa
break;
}
}
void HandleCreateMode() { /* ... */ }
void HandleMoveMode() { /* ... */ }
void HandleRotateMode() { /* ... */ }
void HandleDeleteMode() { /* ... */ }
}
13. Interfaz ITool y CreateTool
public interface ITool
{
void OnEnterTool();
void OnExitTool();
void OnUpdateTool();
}
public class CreateTool : ITool
{
public void OnEnterTool()
{
// Mostrar mensaje de ayuda, activar menú lateral
}
public void OnExitTool()
{
// Ocultar menú lateral, limpiar preview
}
public void OnUpdateTool()
{
// Lógica de preview + raycast + colocación de objeto
}
}
14. Interfaz ILocalizableText y LocalizedLabel
public interface ILocalizableText
{
void UpdateText();
}
using UnityEngine;
using UnityEngine.UI;
public class LocalizedLabel : MonoBehaviour, ILocalizableText
{
public string key;
private Text uiText;
private void Awake()
{
uiText = GetComponent<Text>();
}
private void OnEnable()
{
UpdateText();
}
public void UpdateText()
{
if (uiText == null) return;
string value = LocalizationManager.Instance.GetText(key);
uiText.text = value;
}
}
15. LocalizationManager simple
using System.Collections.Generic;
using UnityEngine;
public class LocalizationManager : MonoBehaviour
{
public static LocalizationManager Instance { get; private set; }
private Dictionary<string, string> table;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
LoadLanguage("es");
}
public void LoadLanguage(string code)
{
// Simulación de carga
table = new Dictionary<string, string>();
if (code == "es")
{
table["ui_create"] = "Crear";
table["ui_move"] = "Mover";
table["ui_rotate"] = "Rotar";
table["ui_delete"] = "Eliminar";
}
else if (code == "en")
{
table["ui_create"] = "Create";
table["ui_move"] = "Move";
table["ui_rotate"] = "Rotate";
table["ui_delete"] = "Delete";
}
}
public string GetText(string key)
{
if (table != null && table.TryGetValue(key, out string value))
return value;
return key; // fallback
}
}
Parte 3 – Caso práctico
16. Menú de Acciones (inferior)
- Contiene los botones principales:
Crear,Mover,Rotar,Eliminar(y opcionalmenteCancelar/Neutral). - Está parcialmente oculto por defecto, mostrando solo una pestaña o borde.
- Cuando el usuario pasa el ratón o hace click sobre la pestaña, el panel se despliega con una animación de deslizamiento.
- Al pulsar uno de los botones:
- Se activa la herramienta correspondiente (cambia el estado del EditorManager).
- Se actualiza el aspecto del botón seleccionado (resaltado).
- Otros botones se desactivan visualmente.
17. Flujo Menú de Objetos (lateral) en modo Crear
- El usuario pulsa
Crearen el menú inferior → estado del editor pasa aCreate. - Se muestra el menú de objetos (lateral) con una lista de prefabs (sillas, mesas, lámparas…).
- El usuario hace click sobre un prefab, por ejemplo “Mesa”.
- El editor instancia un objeto preview de “Mesa” que sigue la posición del ratón:
- Se lanza un raycast desde la cámara a través de la posición del ratón.
- Si el raycast impacta en el suelo, la posición del preview se ajusta a
hit.point.
- Mientras el usuario mueve el ratón, el objeto preview se mueve suavemente por el suelo.
- Cuando el usuario hace click izquierdo:
- El objeto preview se “fija” y se convierte en un objeto definitivo de la escena.
- Se puede volver automáticamente al estado neutro o permitir seguir colocando más objetos del mismo tipo según el diseño.
- La UI puede ocultar el menú lateral o dejarlo abierto según el flujo que se desee.
18. Control de rotación de un objeto
Posible flujo:
- Usuario pulsa
Rotar→ estado del editorRotate. - Mensaje de ayuda: “Haz click en un objeto para rotarlo”.
- Click en un objeto: se detecta con raycast, se guarda como
objetoSeleccionadoy se resalta. - Mientras se mantenga pulsado el botón del ratón o una tecla (por ejemplo, botón derecho):
- El movimiento horizontal del ratón (
deltaX) se convierte en un ángulo de giro sobre el eje Y:objetoSeleccionado.transform.Rotate(0, deltaX * rotationSpeed, 0);
- El movimiento horizontal del ratón (
- Al soltar el botón del ratón o confirmar con click izquierdo:
- Se fija la rotación.
- Se quita el resaltado.
- Si el usuario hace click en el suelo o pulsa un botón de “Cancelar”, se vuelve al estado
Neutral.
19. Integración de audio
AudioManageres Singleton con métodos como:PlayUIHover()PlayUIClick()PlayPlaceObject()PlayDeleteObject()
- Al cambiar de herramienta:
EditorManagerllama aAudioManager.Instance.PlayUIClick()y quizá a un sonido específico de herramienta,PlayToolChange().
- Al colocar un objeto:
- El código que fija definitivamente el objeto (en el modo
Create) llama aAudioManager.Instance.PlayPlaceObject();.
- El código que fija definitivamente el objeto (en el modo
- Al eliminar un objeto:
- Tras confirmar en el popup y antes o justo después del
Destroy, se llama aAudioManager.Instance.PlayDeleteObject();.
- Tras confirmar en el popup y antes o justo después del
De esta forma, la lógica de estados no sabe cómo se cargan ni gestionan los clips de audio; solo invoca métodos del AudioManager.
20. Mejora de experiencia (ejemplos)
Cuatro propuestas:
- Animación de botones de herramienta
- Al seleccionar una herramienta, el botón hace una pequeña animación de escala (1 → 1.1 → 1).
- Refuerza visualmente que ha cambiado el modo.
- Outline o halo en el objeto seleccionado
- Cuando un objeto está seleccionado para mover o rotar, se le aplica un outline o cambia ligeramente su color.
- El jugador sabe qué objeto está activo.
- Partículas al colocar un objeto
- Al fijar un objeto en el escenario, se instancia un pequeño efecto de partículas (chispa suave) en su base.
- Da sensación de “aparición” o “colocación satisfactoria”.
- Animación de paneles de UI
- Panel inferior y lateral no aparecen/desaparecen de golpe, sino con animaciones de deslizamiento y fade.
- La UI se siente más “viva” y coherente con el resto del editor.
Texto para post (Academia San Roque) – Simulacro 2
Puedes usarlo en la web o en el aula virtual como complemento del primero.
Título:
Segundo simulacro de examen Unity: patrones, estados, interfaces y editor multimedia
Contenido:
Como refuerzo para el examen de Programación de Videojuegos, hemos preparado un segundo simulacro centrado en:
- Patrón Singleton y su diferencia con clases estáticas en Unity.
- Diseño de máquinas de estados con
enumy con interfaces/clases de estado. - Uso de interfaces para herramientas del editor y objetos seleccionables.
- Implementación básica de un sistema de localización con diccionarios y componentes de UI localizables.
- Análisis detallado del Editor Multimedia Interactivo: menús de acciones y de objetos, flujo de creación/rotación/eliminación, integración de audio y feedback visual.
Este simulacro incluye:
- Preguntas teóricas cortas.
- Ejercicios de código en C#.
- Un caso práctico basado en el documento de la práctica, con propuestas de diseño y mejoras de usabilidad.
Además, se proporcionan soluciones orientativas, de manera que el alumnado pueda autocorregirse y detectar en qué puntos necesita repasar antes del examen.
Contenido restringido
Comments are closed