basic advanced example
This commit is contained in:
1 parent
6fe57915e8
commit
bd8edf5afb
29 files changed
+1501
-38
No files matched your search
@@ -0,0 +1,181 @@
|
||||
# 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.
|
||||
Reference in new issue
Block a user