182 lines
7.4 KiB
Markdown
182 lines
7.4 KiB
Markdown
# Nazwy i długości animacji w VS Code
|
|
|
|
W `ue_workshop.animations` są statycznie zapisane enumy `FighterAnimations` i
|
|
`CreatureAnimations`. Działają w zwykłym Pythonie, bez `unreal`. Po wpisaniu kropki
|
|
VS Code może podpowiedzieć wszystkie klipy. Opisy członków podają długość w sekundach.
|
|
Nazwy odpowiadają nazwom plików; nie ma skrótów typu `attack`.
|
|
|
|
```python
|
|
from ue_workshop.animations import FighterAnimations, CreatureAnimations
|
|
|
|
draw = FighterAnimations.DRAW_A_GREAT_SWORD_1
|
|
attack = FighterAnimations.GREAT_SWORD_ATTACK
|
|
|
|
draw.key # "draw_a_great_sword_1"
|
|
draw.seconds # 0.5 sekundy
|
|
draw.frames(24) # 12 klatek przy 24 FPS
|
|
attack.seconds # około 1.2 sekundy
|
|
attack.frames(24) # 29 klatek przy 24 FPS, zaokrąglone w górę
|
|
attack.frames(24, speed=2)
|
|
|
|
# Bez end klip wybrany enumem gra raz, z automatycznie policzonym końcem.
|
|
shot.animation(character_fighter, draw, start=0)
|
|
next_start = draw.frames(shot.fps) - 6
|
|
shot.animation(character_fighter, attack, start=next_start)
|
|
```
|
|
|
|
W tym przykładzie przejście trwa 6 wspólnych klatek. Przy zmianie klipu albo FPS
|
|
nie trzeba pamiętać jego długości. `speed` jest uwzględniane zarówno przez `frames`,
|
|
jak i przez automatyczny koniec w `shot.animation`.
|
|
|
|
Podanie `end` nadal ustawia własny zakres i pozwala zapętlić klip:
|
|
|
|
```python
|
|
shot.animation(character_fighter, FighterAnimations.GREAT_SWORD_IDLE, start=0, end=120)
|
|
```
|
|
|
|
Dotychczasowe nazwy tekstowe nadal działają. Dla tekstu lub bez wskazania klipu
|
|
pominięte `end` zachowuje dotychczasowe znaczenie: gra do końca sekwencji.
|
|
Koniec sekcji musi mieścić się w `Sequence(..., frames=...)`.
|
|
|
|
## Zachowanie pozycji po ataku
|
|
|
|
Jeśli klip przesuwa postać do przodu, włącz opcję na tym klipie:
|
|
|
|
```python
|
|
shot.animation(character_fighter, FighterAnimations.GREAT_SWORD_SLASH_2,
|
|
start=57, keep_end_position=True)
|
|
shot.animation(character_fighter, FighterAnimations.GREAT_SWORD_SLASH_3, start=161)
|
|
```
|
|
|
|
`animation()` przenosi poziomy ruch kości głównej do zwykłych kluczy pozycji
|
|
aktora na ścieżce Transform. Ostatni klucz zachowuje osiągnięte przesunięcie,
|
|
więc następny atak zaczyna się w nowym miejscu. Klucze możesz edytować w Sequencerze.
|
|
Ruch pionowy i obroty kości pozostają w animacji.
|
|
|
|
### Pozostawienie postaci na ziemi po śmierci
|
|
|
|
```python
|
|
shot.animation(character_creature, CreatureAnimations.MUTANT_DYING,
|
|
start=150, keep_end_pose=True)
|
|
```
|
|
|
|
Enum bez `end` odtwarza klip raz. `keep_end_pose=True` dodaje po nim odcinek
|
|
z zamrożoną końcową pozą aż do końca sekwencji. Postać pozostaje na ziemi także
|
|
przy renderowaniu pojedynczej późniejszej klatki. Kolejna animacja tej samej
|
|
postaci kończy utrzymywanie pozy. Oryginalny klip nie jest zmieniany.
|
|
|
|
`keep_end_pose` dotyczy ułożenia kości; `keep_end_position` dotyczy przesunięcia
|
|
aktora. Można włączyć obie opcje. Jeśli jawnie wydłużysz zakres przez `end`,
|
|
klip nadal może się zapętlać w tym zakresie — dla śmierci pozostaw pojedynczy przebieg.
|
|
|
|
Aby uniknąć podwójnego przesuwania, sekcja korzysta z wygenerowanej kopii klipu
|
|
bez jego poziomego przesunięcia. Oryginalny asset animacji pozostaje bez zmian.
|
|
Opcja domyślnie jest wyłączona. Jeśli chcesz własne klucze pozycji, dodaj je po
|
|
wywołaniach `animation()` — zastąpią wygenerowane wartości na tych samych klatkach.
|
|
|
|
### Ruch względem aktualnej pozycji
|
|
|
|
Po `keep_end_position` nie musisz obliczać nowych współrzędnych ręcznie:
|
|
|
|
```python
|
|
# Po wywołaniach shot.animation(...): przesunięcie o 50 cm w osi Y.
|
|
shot.move(character_creature, start=80, end=120, offset=(0, 50, 0))
|
|
```
|
|
|
|
Helper odczyta pozycję aktora w klatce 80 z krzywych Sequencera, doda klucz
|
|
początkowy, a w klatce 120 klucz przesunięty o `offset`. To współrzędne świata
|
|
w centymetrach. Ostatnia klatka ruchu jest kluczem, więc musi być mniejsza od
|
|
`shot.frames`. Dodawaj ruch po animacjach. `move()` zastępuje klucze pozycji wewnątrz
|
|
odcinka, także wygenerowane przez `keep_end_position`. Późniejsze klucze pozycji są
|
|
przesuwane o wynikową różnicę, żeby zachować dalszy ruch. Klucze rotacji i skali zostają.
|
|
|
|
### Cofanie podczas chodzenia
|
|
|
|
`reverse=True` odtwarza klip od końca. W połączeniu z `keep_end_position=True`
|
|
odwraca także przesunięcie zapisane w klipie i zachowuje nową pozycję:
|
|
|
|
```python
|
|
shot.animation(character_creature, CreatureAnimations.MUTANT_WALKING,
|
|
start=80, end=120, reverse=True, keep_end_position=True)
|
|
```
|
|
|
|
Postać odtwarza kroki do tyłu bez zmiany kierunku, w którym patrzy. Jeśli chcesz
|
|
ustalić odległość cofnięcia samodzielnie, dopisz po animacjach:
|
|
|
|
```python
|
|
shot.move(character_creature, start=80, end=120, offset=(0, -200, 0))
|
|
```
|
|
|
|
To ustawia cofnięcie o 200 cm w osi Y; `reverse` odpowiada za kierunek odtwarzania
|
|
ruchu nóg, a `move` zastępuje trasę pozycjami wybranymi przez autora sceny.
|
|
|
|
Do własnych obliczeń służy:
|
|
|
|
```python
|
|
x, y, z = shot.position(character_creature, frame=80)
|
|
```
|
|
|
|
Odczyt uwzględnia klucze Transform, `keep_end_position` i interpolację. Nie przestawia
|
|
kursora w Sequencerze. Dotyczy pozycji aktora; ruchy samych kości wewnątrz klipu
|
|
bez `keep_end_position` nie zmieniają pozycji jego aktora. Odczyt wykonuje się w UE
|
|
podczas uruchamiania skryptu, więc VS Code nie musi znać liczbowych współrzędnych.
|
|
|
|
Listę z danymi też można odczytać bez UE:
|
|
|
|
```python
|
|
for clip in FighterAnimations:
|
|
print(clip.key, clip.seconds, clip.frames(24))
|
|
```
|
|
|
|
## Własny model studenta — generowanie automatyczne
|
|
|
|
Każde `scene.skeletal_model(...)` automatycznie zapisuje nazwy i długości jego
|
|
zaimportowanych klipów do `Content/Python/ue_workshop/animations.py`. Dotyczy to
|
|
także modeli pobranych przez studentów, FBX z animacją w środku i `.blend`.
|
|
|
|
Umieść model i jego animacje FBX w osobnym folderze, np. `source_assets/ninja`.
|
|
Przy pierwszym uruchomieniu w UE:
|
|
|
|
```python
|
|
character = scene.skeletal_model(
|
|
PROJECT / "source_assets/ninja/model.fbx",
|
|
name="Ninja",
|
|
reimport=False,
|
|
)
|
|
```
|
|
|
|
Powstanie `NinjaAnimations` — nazwa enuma wynika z `name`. VS Code zobaczy nowy
|
|
statyczny kod i będzie mógł go podpowiadać. W kolejnej edycji skryptu możesz użyć:
|
|
|
|
```python
|
|
from ue_workshop.animations import NinjaAnimations
|
|
|
|
# Jeśli w folderze był walking.fbx:
|
|
clip = NinjaAnimations.WALKING
|
|
clip.seconds
|
|
clip.frames(shot.fps)
|
|
shot.animation(character, clip, start=0)
|
|
```
|
|
|
|
Pierwszy import w UE jest potrzebny do odczytania rzeczywistych długości.
|
|
Późniejsze pisanie sceny korzysta z zapisanego katalogu i nie wymaga komend w UE.
|
|
Różnym modelom nadaj różne `name` — to również nazwa ich assetów w projekcie.
|
|
|
|
Po dodaniu FBX do folderu uruchom swój skrypt ponownie: brakujący klip zostanie
|
|
zaimportowany i dopisany do enuma. Po zmianie istniejącego klipu użyj `REIMPORT=True`;
|
|
nowa długość zapisze się automatycznie. Nie trzeba uruchamiać osobnego generatora.
|
|
`REIMPORT=False` nadal używa istniejących assetów. Nie ma sprawdzania dat źródeł.
|
|
|
|
Katalogi innych modeli pozostają w pliku. Jawny wybór `animations={...}` aktualizuje
|
|
tylko wybrane wpisy, zachowując inne znane klipy tej postaci. Automatyczny odczyt
|
|
całego folderu odświeża pełną listę. Jeśli dane się nie zmieniły, plik nie jest
|
|
zapisywany ponownie.
|
|
|
|
Opcjonalna ręczna aktualizacja dołączonego fightera i creature:
|
|
|
|
```text
|
|
python tools/run_workshop.py tools/update_animation_catalog.py
|
|
```
|
|
|
|
To narzędzie również zachowuje katalogi własnych modeli studentów.
|