# 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.