Procedural Animator
Movimiento procedural independiente del motor que compone contribuciones aditivas de PoseDelta a partir de capas ponderadas, acciones con ciclo de vida y secuencias de activación de un solo disparo — en cinco canales declarados — sobre cualquier rig, prop o elemento de UI.
Para qué sirve este sistema
La animación esquelética y el movimiento procedural no son opuestos: funcionan mejor juntos. Un personaje puede reproducir un clip de locomoción y respirar, balancearse y estremecerse al mismo tiempo, porque todas esas contribuciones son desplazamientos aditivos superpuestos a lo que el animador haya creado. La dificultad está en hacerlo de forma limpia, sin que el código procedural conozca nada sobre transformadas de Unity, renderers ni el bucle de actualización.
El sistema Procedural Animator de Serenity resuelve eso. Define un modelo de composición construido alrededor de PoseDelta, separa la matemática de evaluación de la aplicación de transformadas a través de IRigApplier, y dirige todo el pipeline desde un perfil de ScriptableObject para que la configuración viva en assets, no en código.
El problema en Unity
La mayoría de proyectos Unity añaden el movimiento procedural tarde: un MonoBehaviour que rota directamente un hueso de columna para la respiración, otro que interpola una transformada de cabeza para el seguimiento de objetivo, y una corrutina que sacude la cámara para el retroceso. Cada uno lee de las transformadas de Unity, escribe de vuelta en ellas y pisa a todos los demás scripts que también las tocan. El resultado son bugs de orden de operaciones, conflictos de animación y un sistema que nadie quiere extender.
Cuando una reacción a golpe, una capa de respiración y un offset de apuntado escriben en los mismos huesos de forma independiente, la pose final depende del orden de ejecución de scripts y de qué Update se ejecutó en último lugar. No hay un presupuesto de composición, ningún sistema de pesos ni forma alguna de previsualizar el resultado combinado sin entrar en modo de reproducción.
Cómo lo aborda Serenity
Procedural Animator introduce dos contratos de participación. IProceduralLayer<TContext> es para contribuciones continuas —respiración, vaivén, seguimiento de objetivo— que evalúan cada fotograma y escriben en un PoseDelta ponderado por el peso actual de la capa. IProceduralAction<TContext> es para disparos únicos discretos con ciclo de vida —retroceso, estremecimiento, tambaleo— que implementan CanStart, OnStart, Tick, IsFinished y OnStop. Ambos escriben desplazamientos aditivos en el mismo acumulador PoseDelta para que sus contribuciones se compongan correctamente. Además, cada capa declara cuáles de los cinco canales escribe realmente —Pose, Material, Transform, Activation y UiColor— mediante un flag DrivenChannels, de modo que un consumidor aplica solo los canales que le interesan en lugar de adivinarlo por el tipo concreto de la capa.
IRigApplier<TRigDefinition> aísla la manipulación real de transformadas de la matemática de evaluación. El pipeline de composición acumula un PoseDelta, un MaterialDelta, un TransformDelta y un ActivationDelta, y luego los entrega al applier. TransformRigApplier y UnityMaterialApplier proporcionan las implementaciones de Unity, pero la lógica de dominio nunca toca un tipo de Unity. RuleSO conecta condiciones con pesos de capa o disparadores de acción para que el comportamiento se configure en assets a través de ProceduralAnimatorProfileSO.
Cómo encaja en Serenity
Procedural Animator vive en el namespace Serenity.ProceduralAnimator y sigue la estructura por capas de la foundation. La capa de Dominio define PoseDelta, MaterialDelta, TransformDelta, ActivationDelta, BoneId, MaterialId e IStateReader, todos independientes del motor. La capa de Aplicación declara IProceduralLayer<TContext>, IProceduralAction<TContext> e IRigApplier<TRigDefinition>. La capa de Infraestructura provee las clases base ProceduralLayerSO y ProceduralActionSO, capas y acciones concretas, proveedores de peso, tipos de condición, implementaciones de applier, herramientas de editor y ProceduralAnimatorComponent como driver en tiempo de ejecución.
ProceduralAnimatorProfileSO es la raíz de composición: agrupa BaseLayers, Rules, MaterialTargets y TransformTargets en un único asset. Las reglas vinculan árboles de Condition a un efecto SetLayerWeight o TriggerAction para que la pose activa sea completamente data-driven. Las implementaciones de WeightProviderSO —ConstantWeightProviderSO y StateKeyWeightProviderSO— permiten que los pesos de capa respondan a valores de estado en tiempo de ejecución en StateBusComponent. Más allá del movimiento continuo de rig, una capa puede ejecutarse en modo de fase ON_ACTIVATE —una secuencia de un solo disparo con un número de repeticiones configurado que se reinicia con cada disparo en lugar de seguir el reloj de animación compartido— y una ActivationSequenceLayerSO puede encender y apagar un GameObject como parte de esa secuencia. El sistema se integra de forma natural con los sistemas de input y armas para retroceso y vibración, y con el sistema de secuencias para cambios de expresión en cinemáticas.
Flujo de trabajo práctico
- Añade ProceduralAnimatorComponent y UnityRigDefinition al prefab del personaje y enlaza las transformadas de hueso por nombre — o desactiva drivesRig para un animador sin rig que dirija solo materiales, transformadas u objetivos de activación con su propio reloj manual, como un elemento de UI o un prop.
- Crea un asset ProceduralAnimatorProfileSO y asigna capas continuas como PeriodicOscillationLayerSO para la respiración o PerlinDriftLayerSO para el vaivén.
- Crea assets RuleSO que vinculen árboles de Condition con objetivos de peso de capa o disparadores de acción; usa ThresholdCondition o RangeCondition con valores de state key.
- Crea assets ProceduralActionSO para reacciones discretas —StunRecoilActionSO, FlinchActionSO o StumbleActionSO— y referéncialos desde reglas.
- Usa StateBusComponent como almacén de estado en tiempo de ejecución; empuja valores desde el código de gameplay usando assets UnityStateKey para que capas y condiciones reaccionen automáticamente.
- Usa el asistente ProceduralAnimatorSetupWindow (Tools ▸ Serenity ▸ Create ▸ Procedural Animator ▸ Setup Minimal Idle) para generar un scaffold con StateKeys, capas, proveedores de peso y un perfil de idle mínimo en un solo paso.
Qué incluye
- Contrato IProceduralLayer<TContext> para contribuciones continuas ponderadas (respiración, vaivén, seguimiento de objetivo, ruido)
- Contrato IProceduralAction<TContext> para disparos únicos discretos con ciclo de vida (retroceso, estremecimiento, tambaleo)
- Acumuladores PoseDelta, MaterialDelta, TransformDelta y ActivationDelta compositados antes de tocar ninguna transformada
- IRigApplier<TRigDefinition> aísla la aplicación de huesos de la matemática de evaluación para portabilidad total del motor
- ProceduralAnimatorProfileSO como raíz de composición data-driven que agrupa capas, reglas y objetivos
- Cada capa declara sus DrivenChannels (Pose, Material, Transform, Activation, UiColor) para que el consumidor aplique solo los canales que realmente escribe
- Modo de fase ON_ACTIVATE con repeticiones configuradas para secuencias de un solo disparo redisparables, más una capa de secuencia de activación que enciende y apaga GameObjects
- Los animadores sin rig corren con reloj manual para elementos de UI y props — el mismo pipeline impulsa los presets de animación del HUD Builder y el simulador procedural en vivo del Animation Hub (play/pausa/paso, un deslizador por state key)
- RuleSO conecta árboles de Condition con cambios de peso de capa o disparadores de acción sin código
- Implementaciones WeightProviderSO con mapeo de curva guiado por state key para pesos de capa reactivos
- StateBusComponent como bus de estado en tiempo de ejecución con suavizado opcional para publicación desacoplada de estado
- Capas concretas integradas: PeriodicOscillationLayerSO, PerlinDriftLayerSO, HighFrequencyNoiseLayerSO, StateModulatedOffsetLayerSO, RandomImpulseLayerSO, ActivationSequenceLayerSO
- Acciones concretas integradas: StunRecoilActionSO, FlinchActionSO y StumbleActionSO con ataque y recuperación guiados por curva
Cuándo usarlo
- Personajes que necesitan respiración, vaivén de idle o seguimiento de objetivo ejecutándose junto a locomoción basada en clips sin conflictos de animación.
- Sistemas de armas que necesitan retroceso, estremecimiento por golpe o reacciones de tambaleo como contribuciones aditivas discretas sobre la animación base.
- Elementos de HUD y otros elementos de UI o props sin rig que necesitan el mismo movimiento data-driven por capas que un rig de personaje — pulsos, parpadeos y secuencias de activación de un solo disparo sin código extra.
- Proyectos que quieren el movimiento procedural configurado en assets en lugar de codificado en MonoBehaviours dispersos por las escenas.
- Bases de código que necesitan que la misma lógica de composición funcione independientemente de cómo se apliquen los huesos o transformadas en el rig de destino.
Sistemas relacionados
Usa Serenity cuando quieras movimiento procedural que se componga de forma limpia con la animación esquelética — o anime elementos de UI y HUD sin ella —, responda al estado en tiempo de ejecución a través de reglas data-driven y no toque ninguna transformada de Unity hasta que el delta completo esté listo.
English
Español
Català