Sprites de espalda del entrenador y el lanzamiento
Al comenzar una batalla 2D, el personaje del jugador (y un entrenador aliado, en una batalla doble) se queda en la esquina de la pantalla de espaldas a la cámara, lanza la bola y se desliza fuera de la imagen. Un solo componente dibuja todo eso: BattleTrainerSprite, una instancia por cada espacio de entrenador en la escena de batalla (AllyTrainerSprites, EnemyTrainerSprites).
Esta página explica cómo se crea ese sprite y qué hace el componente por ti, para que el lanzamiento se vea bien en cualquier pantalla.
Qué es un sprite de espalda
La espalda de un personaje se guarda en su asset CharacterType:
| Campo | Tipo | Significado |
|---|---|---|
BackSprite | Material | La espalda animada del personaje: un material que contiene una hoja de fotogramas (_SpriteSheet) dispuesta en columnas por filas (_Flipbook) y que dibuja el shader de flipbook de MCE |
BackSpriteTimeline | FlipbookTimeline | Las celdas del lanzamiento y cuánto dura cada una. Vacío para los sprites propios del motor |
Un tipo de personaje sin material de espalda (el jugador de un juego importado, por ejemplo) simplemente no se dibuja: el renderizador se apaga en lugar de mostrar el cuadrado de marcador.
El flipbook y su línea de tiempo
Por defecto el lanzamiento recorre las celdas de la hoja a ritmo uniforme. El componente reparte AnimationDuration (1 segundo a velocidad 1) en partes iguales entre las celdas que el material declara en _Flipbook (si declara una celda o ninguna, se usa FlipbookSteps serializado, 5 por defecto), se detiene en el último fotograma en lugar de volver al inicio y suelta la bola a los 0,4 segundos.
Eso está bien para un sprite que dibujas tú. Un cartucho, en cambio, mantiene algunas celdas un par de ticks y una durante cincuenta. Un FlipbookTimeline registra exactamente eso:
| Campo | Significado |
|---|---|
cells | La celda que se muestra en cada entrada |
seconds | Cuánto dura cada entrada, a velocidad 1 |
releaseEntry | La entrada en la que la bola sale de la mano (negativo si no hay ninguna) |
La tabla es utilizable solo si tiene al menos una entrada, un tiempo para cada entrada y todos los tiempos por encima de cero. Cualquier otra cosa (incluida la tabla vacía que una escena crea por defecto) es "no utilizable", y el entrenador conserva el flipbook uniforme.
Con una tabla utilizable:
- cada celda se muestra durante su propio tiempo (la celda que se muestra en el segundo t es
CellAt(t)); - la bola se suelta cuando empieza la entrada de suelta (
ReleaseSeconds: la suma de las entradas anteriores); - todo el lanzamiento dura
TotalSeconds, y la última celda se mantiene después.
Puedes construir una tabla con los números de un cartucho mediante FlipbookTimeline.FromTicks(cells, ticks, ticksPerSecond, releaseEntry). Como ejemplo, el lanzamiento de HeartGold es de 8, 16, 6, 2, 4, 2, 2, 52 y 2 ticks de 1/60 s, y la bola sale cuando empieza la cuarta entrada: tras 8 + 16 + 6 = 30 ticks, medio segundo después.
El lanzamiento corre con su propio reloj
El lanzamiento no está atado al deslizamiento. ThrowAndSlide(speed, callback) inicia ambos, pero el lanzamiento avanza en el Update del propio componente (TickThrow): muestra la celda de la tabla para el tiempo transcurrido, llama a tu callback una sola vez, cuando la bola sale, y termina cuando acaba la tabla. La velocidad de la batalla escala ambos.
Esa separación importa. Con la velocidad de deslizamiento del original, el deslizamiento (0,45 s) es más corto que el lanzamiento (la bola solo sale a los 0,5 s), así que un lanzamiento controlado por la finalización del deslizamiento soltaba la bola antes de tiempo y cortaba la animación. Otras garantías:
- un lanzamiento que empieza mientras otro está en curso lo reemplaza, y el reemplazado nunca suelta su bola;
- si el objeto del entrenador está inactivo y no puede actualizarse, el final del deslizamiento suelta la bola como último recurso, de modo que la batalla nunca espera para siempre.
El deslizamiento siempre termina justo fuera de pantalla
Tras el lanzamiento, el entrenador se desliza fuera de la imagen. Dos cosas se calculan por ti:
Velocidad. El deslizamiento es lineal a SlideUnitsPerSecond unidades de mundo por segundo (3,125 por defecto: los 5 píxeles de DS por fotograma del original). Ponlo en 0 para usar en su lugar la SlideDuration fija (2 segundos a velocidad 1).
Destino. La escena de batalla tiene un marcador (SlideTarget) en una x fija. Una x fija no puede ser correcta para todas las pantallas: en una imagen 16:9 el borde está mucho más cerca que en 21:9 o 32:9, donde un entrenador que se deslizara hasta un marcador fijo se detendría dentro de la imagen. Por eso el destino se calcula para la cámara que dibuja al entrenador: justo pasado el borde de la pantalla del lado del marcador, el alcance propio de la figura (cuánto se extiende su dibujo más allá de su pivote hacia ese borde) más un pequeño margen (SlideExitMargin, 0,1 unidades) más allá. La altura y la profundidad son las del marcador. Con una cámara que no es ortográfica, o en el escenario 3D, decide el marcador de la escena.
Dibujo con píxeles perfectos
Una hoja de espalda hecha de pixel art, con filtro de punto y dibujada al tamaño con el que se creó, muestra sus píxeles en dos anchos distintos (algunos ocupan un píxel de pantalla más que otros), y la figura se ve áspera. Para estas hojas, BattleTrainerSprite ajusta el tamaño de modo que cada píxel de la hoja cubra un número entero de píxeles de pantalla (nunca menos de uno), y coloca los pies de la figura donde los tenía el original:
- el tamaño es la escala de píxeles enteros más cercana a la creada (
PixelPerfectHeight); - la altura se elige de modo que la última fila dibujada de la figura de pie quede sobre el borde inferior de la pantalla (las filas vacías bajo el primer fotograma se cuentan desde la textura y quedan por debajo del borde, como el cuerpo del original que se sale por la parte inferior de la pantalla). Una hoja cuya textura no se puede leer conserva la altura que le dio la escena;
- la posición horizontal no se toca: es del deslizamiento.
La regla solo se aplica cuando tiene sentido: una hoja con filtro de punto, una cámara ortográfica y la batalla 2D. El arte dibujado con filtrado bilineal (una espalda ilustrada grande) no tiene píxeles que conservar enteros y se deja exactamente como se creó; lo mismo ocurre con el escenario 3D. Si la hoja desaparece, vuelve el tamaño original.
El cálculo se ejecuta justo antes de que cada cámara dibuje, enganchado al evento propio del pipeline de renderizado (beginCameraRendering en URP), de modo que usa el zoom final de la cámara y no el valor de un fotograma anterior.
En el escenario 3D
Cuando la batalla usa el escenario 3D, el entrenador se queda donde lo pone el original durante toda la batalla: sus deslizamientos lo mantienen en su sitio, sus fotogramas de reposo se repiten con el reloj del juego y reproduce el lanzamiento cuando envía un monstruo (ThrowOnStage). El dibujo se escala para que uno de sus píxeles sea el tamaño de píxel del escenario.
La sombra
El entrenador recibe una sombra como la de los monstruos: un hijo del dibujo llamado Shadow, pintado con el gris de sombra del shader, tendido en el suelo con su centro a los pies de la figura, con la misma imagen y el mismo reflejo que el dibujo.
Configuración
- Crea el Material de espalda con el shader de flipbook, asigna la hoja a
_SpriteSheety establece_Flipbooken las columnas y filas de la hoja. Las hojas de pixel art deben usar filtrado Point. - Asígnalo al campo Back Sprite del
CharacterType. - Opcional, para un lanzamiento con tiempos propios: rellena Back Sprite Timeline (la lista de celdas, los segundos de cada una y la entrada de suelta). Déjalo vacío para el lanzamiento uniforme.
- En la batalla,
BattleManagerCharactersModuleentrega el material y la línea de tiempo alBattleTrainerSpritedel espacio (SetMaterial(material, timeline)).
Los juegos importados de un cartucho no necesitan nada de esto: los importadores establecen el material de espalda y la tabla de tiempos de cada personaje jugador a partir de los datos del cartucho (ver Juegos importados y perfiles de juego).
Referencia
| Tipo | Namespace | Función |
|---|---|---|
BattleTrainerSprite | OpenMon.MCE.Battle | Dibuja y anima a un entrenador en batalla: lanzamiento, deslizamiento, dibujo con píxeles perfectos, sombra |
FlipbookTimeline | OpenMon.MCE.Battle | Celdas, tiempos y entrada de suelta de un lanzamiento |
CharacterType | OpenMon.MCE.Characters | Contiene BackSprite y BackSpriteTimeline |