|
0. Wstęp W OFP przerywniki filmowe (Cutscenes) można tworzyć na dwa sposoby:
za pomocą wyzwalaczy i za pomocą zewnętrznych skryptów (External scripts)
, czyli programów napisanych w języku skryptowym OFP, umieszczonych w plikach
z rozszerzeniem .sqs (zwykle nazywane są "Camera.sqs" lub "Cutscene.sqs").
Osobiście jestem zwolennikiem tego drugiego rozwiązania, gdyż uważam, że dzięki
takiej formie łatwiej jest kontrolować przebieg danej scenki. Sądzę, że opanowanie
tej sztuki nie jest takie trudne jak mogłoby się z pozoru wydawać (nawet dla
kogoś kto nie ma zielonego pojęcia o programowaniu). Na dobry początek trzeba mieć wykonaną misję, w której chce się umieścić przerywnik
filmowy (tj. mieć plik z rozszerzeniem sqm) i mieć plan (choćby w zarysie) tego
jaki będzie przebieg przerywnika tj. co będzie się działo i w jakiej kolejności. Mamy więc pusty plik sqs. By powstał przerywnik filmowy konieczne jest umieszczenie w pliku paru poleceń (surprise!). Do podstawowych należą (podane w kolejności ich umieszczania): TitleCut ["tekst", "BLACK
IN", n] - polecenie to powoduje przejście ekranu z "czarnego"
do "przezroczystego" w czasie n sekund, z jednoczesnym wyświetleniem
dowolnego tekstu umieszczonego w cudzysłowie (można nic nie umieszczać, ale
cudzysłów musi być). EnableRadio false - polecenie to sprawi, że komunikaty radiowe nie będą się pojawiały w trakcie trwania przerywnika. Polecenie to można odwołać w dowolnym momencie (a nawet trzeba pod koniec przerywnika) umieszczając w skrypcie komendę EnableRadio true. _cam = "CAMERA" CamCreate [0,0,0] - polecenie to tworzy w punkcie o współrzędnych [0,0,0] kamerę, powiązując ją ze zmienną lokalną _cam (przez tą zmienną będziemy odwoływać się do kamery wydając jej polecenia). Oczywiście można stworzyć kamerę w innym miejscu, ale nie ma to znaczenia bo i tak zaraz zmienimy jej położenie. _cam CameraEffect ["INTERNAL","BACK"] - polecenie to uruchamia kamerę powiązaną ze zmienną _cam, jednocześnie określając jaka ma być i gdzie ma być położona względem filmowanego celu (ale tym się nie przejmujcie, gdyż przynajmniej mnie nie udało się tego z pożytkiem użyć. Wpiszcie tylko "INTERNAL","BACK"). Teraz to co najważniejsze, czyli treść przerywnika. Ogólnie rzecz
biorąc przerywnik powstaje w ten sposób, że: Do tego pomijając różne "bajery" sprowadza się tworzenie
przerywnika w OFP tj. do określenia: Do przekazywania kamerze powyższych informacji służą następujące polecenia: _cam CamSetTarget nazwa_obiektu
- polecenie to nakazuje kamerze "podążać wzrokiem" za obiektem o podanej
nazwie tzn. że jeżeli celem będzie jadący samochód kamera bez naszej pomocy
utrzyma go w polu widzenia (no chyba, że coś zasłoni jej widok, ale wtedy i
tak będzie wycelowana w odpowiednim kierunku) nie zmieniając przy tym swojej
pozycji. Oczywiście wydanie polecenia śledzenia innego celu odwołuje poprzednie
polecenie. _ox = GetPos nazwa_obiektu
Select 0 Pierwsze trzy linijki komend powodują przypisanie zmiennym lokalnym
_ox,_oy,_oz współrzędnych obiektu o podanej nazwie np. jednostki, markera czy
wyzwalacza. _cam CamSetPos [_x,_y,_z] - polecenie
to nakazuje kamerze zająć pozycję o współrzędnych określonych przez zmienne
lokalne _x,_y,_z. _ox = GetPos nazwa_obiektu
Select 0 Osobiście stosuję metodę polegającą na umieszczaniu wyzwalaczy
o nazwach np. pozycjakamery1, pozycjakamery2, pozycjakamery3 itd... dzięki czemu
umiejscawiam na mapie kolejne pozycje do których przemieszczać się będzie kamera
(bądź w które będzie wycelowana za pomocą CamSetTarget). _cam CamSetRelPos[i,j,k] - polecenie
to nakazuje kamerze zająć pozycję o współrzędnych celu zwiększonych o wartości
i,j,k. To oznacza, że kamera zajmie pozycję przesuniętą względem współrzędnych
celu o wektor [i,j,k]. _cam CamCommit n - bardzo ważne polecenie, o którego umieszczeniu nie można zapomnieć, gdyż w przeciwnym wypadku nic się nie zadziała. Zatwierdza ono wprowadzone wcześniej (za pomocą poleceń CamSetTarget, CamSetPos, CamSetRelPos) zmiany dotyczące kamery tj. jej położenia i celu. Wartość n określa w jakim czasie (w sekundach) ma być dokonana zmiana, co daje nam możliwość zarówno błyskawicznego "przeskoku" z jednego miejsca do drugiego jeżeli podamy n równe 0, jak i powolnego (bądź też szybkiego) przemieszczania kamery z jednego punktu do drugiego, gdy podamy określoną dodatnią wartość n. Po tym poleceniu musimy dać czas kamerze na wykonanie zmian wpisując @CamCommitted _cam co spowoduje zatrzymanie wykonania skryptu na czas podany w poleceniu CamCommit (polecenie @warunek powoduje zatrzymanie działania skryptu do momentu spełnienia warunku tj. przyjęcia wartości logicznej true). Istnieje także polecenie _cam CamSetDir n, które powoduje obrócenie kamery w danym kierunku, gdzie n to wartość w stopniach (od 0 do 360), aczkolwiek raczej rzadko się z niego korzysta. Mając tą wiedzę jesteśmy w stanie (prawie) zacząć tworzyć przerywnik.
Brakuje nam jednak wiedzy na temat sposobu w jaki określić kiedy kamera ma zmieniać
cele, położenie itd. Po pierwsze możemy spowodować zatrzymanie działania skryptu na
określony czas wpisując polecenie: ~n gdzie n to czas w sekundach, na który
wykonywanie skryptu ma być zatrzymane. Druga (nieco lepsza metoda) polega na użyciu zmiennych globalnych,
nazw obiektów i przede wszystkim wyzwalaczy. Można by pisać o tym wiele, więc
posłużę się przykładem, który (mam taką nadzieję) wyjaśni o co mi chodzi. Niezłym sposobem jest też użycie w skrypcie komendy: @(nazwa_obiektu1 Distance nazwa_obiektu2<odległość). Spowoduje to, że skrypt wstrzyma swoje działanie do chwili, aż obiekt1 znajdzie się w odległości mniejszej niż podana odległość w metrach od obiektu2 (można sprawdzić ile to będzie na mapie, stawiając wyzwalacz o określonym promieniu). Oczywiście jako warunku można użyć każdego ciągu poleceń dającego w wyniku wartość logiczną (boolean) np. @((PLAYER In truck1) AND (NOT Alive sucker1)). Podsumowując poważną wadą tego rozwiązania jest to, że jeśli z jakichś względów warunek nie zostanie spełniony (np. samochód ulegnie zniszczeniu między punktami), skrypt nie będzie mógł zakończyć swego działania. Na koniec musimy jeszcze wpisać następujące linijki kodu: TitleCut ["tekst", "BLACK OUT", n] - wpisanie tej linijki daje odwrotny efekt niż na początku przerywnika tj. przejście ekranu od "przezroczystego" do "czarnego" (dzięki zastąpieniu "BLACK IN" wyrażeniem "BLACK OUT"). Czas przejścia i wyświetlany tekst wprowadzamy tak jak poprzednio podając n (w sekundach) i wpisując dowolny tekst. Dodatkowo musimy wstawić opóźnienie w postaci ~n (o takiej samej wartości jak we wcześniejszym TitleCut). _cam CameraEffect ["TERMINATE","BACK"] - polecenie to zakończy pracę kamery związanej ze zmienną lokalną _cam. CamDestroy _cam - polecenie niszczy kamerę (!) związaną ze zmienną lokalną _cam (podejrzewam, że po prostu uwalnia procesor od obciążenia związanego z istnieniem kamery). Jeżeli wcześniej tego nie zrobiliśmy to uruchamiamy radio za pomocą EnableRadio true. Jeszcze raz wpisujemy TitleCut ["tekst", "BLACK IN", n], by po zakończeniu skryptu nie zostać z czarnym ekranem. DisableUserInput false - by gracz mógł robić cokolwiek po zakończeniu skryptu. ...i kończymy działanie skryptu wpisując Exit. 1.5 Rozruch skryptu i modyfikacja Kiedy skrypt jest już gotowy należy umieścić go w tym samym katalogu co plik mission.sqm oraz umieścić w misji komendę [] Exec "nazwa_skryptu.sqs". To gdzie powinno się umieścić tę komendę zależy od tego kiedy przerywnik ma się uruchomić. Jeżeli jest to intro, outro lub scenka rozpoczynająca misję to należy umieścić go w polu Inicjacja dowolnej jednostki odpowiednio na mapie Wstęp (Intro), Przegrana (Outro) lub mapie misji. Jeżeli natomiast przerywnik ma wystąpić w trakcie misji (np. po zakończeniu jakiegoś jej etapu) to wpis ten powinien znaleźć się w polu "Przy aktywacji" odpowiednio określonego wyzwalacza. Uwaga! Warto dobrze zastanowić się nad momentem uruchomienia przerywnika w trakcie misji (tj. tak naprawdę warunkiem aktywacji wyzwalacza), gdyż uruchomienie skryptu odbierze graczowi możliwość działania i obserwowania tego co się wokół niego dzieje, jednocześnie nie ograniczając możliwości działania jego przeciwników. Wniosek z tego jest taki, że najlepszym momentem na przerywniki w trakcie misji są chwile względnego spokoju, takie jak np. podróże jakimś środkiem transportu (misja zyskuje wiele, gdy nudną i długą podróż zastępuje się przerywnikiem). Gdy zrobimy powyższe pozostaje tylko uruchomić podgląd i obejrzeć efekt. Pewien kłopot powstaje, gdy misja jest długa, a przerywnik jest gdzieś w połowie (lub nawet na końcu). Rozwiązaniem tego problemu jest wykonanie zapisu stanu gry tuż przed uruchomieniem skryptu i (jeżeli coś nie gra) wczytanie stanu gry tuż po jego zakończeniu (jeżeli zmodyfikowaliśmy skrypt to przerywnik będzie zawierał naniesione poprawki tzn. nie ma potrzeby zaczynania misji od początku). Drugim sposobem jest wykonanie filmiku jako osobnej misji i scalenie jej z misją właściwą (niestety czasem jest to dosyć kłopotliwe, toteż nie polecam). Jak już pisałem wcześniej przerywnik filmowy tworzą: kamera, obiekt filmowany, ich wzajemna zmiana położenia względem siebie i czas tej zmiany. Oczywiście są to jedynie podstawowe elementy (gdyby przerywnik składał się tylko z tego byłby śmiertelnie nudny)i istnieje sporo innych czyniących przerywnik bardziej atrakcyjnym wizualnie. Do dodatkowych elementów zaliczył bym narrację (subtitles), grę aktorów (dialogi i ruch sceniczny) oraz tło (odgłosy, muzyka, pogoda). Wszystkie te elementy możemy zawrzeć w naszym przerywniku umieszczając w skrypcie odpowiednie komendy. Do umieszczania na ekranie napisów służy (oprócz wspomnianej wcześniej komendy TitleCut) komenda TitleCut["tekst_wyświetlany","PLAIN DOWN",n] która wyświetli dany tekst u dołu ekranu w czasie n sekund (można pominąć ten parametr-wtedy domyślnie przyjmowane jest n=1). Zamiast "PLAIN DOWN" możemy użyć "PLAIN" wtedy napis znajdzie się na środku ekranu. Do tej pory nasza kontrola nad przebiegiem przerywnika (z poziomu skryptu) ograniczała się do kontroli nad kamerą. Tak jednak być nie musi. Możemy wpływać na zachowanie obiektów filmowanych na tyle na ile pozwala na to język skryptowy OFP (czyli właściwie sprawujemy nad nimi kontrolę w takim samym stopniu jak tworząc misję w edytorze). Przez powyższe stwierdzenie należy rozumieć , że możemy w skrypcie umieścić każdą komendę wpływającą na istniejący obiekt (np. Jednostkę) której użylibyśmy np. w jej polu Inicjacja (Init Field), w polu "Przy aktywacji" wyzwalacza lub w polu "Przy aktywacji" punktu trasy (WayPoint). Wniosek z tego taki, że wszystkie polecenia typu : SetBehaviour, OrderGetIn, AssignAsCargo, DoMove, CommandFire ect.. ect... (pozwolę sobie nie przepisywać całego CMREFu) umieszczone w skrypcie, zadziałają w zadanym momencie. Jeżeli obiektem filmowanym jest człowiek mamy znacznie większe możliwości w zakresie gry aktorskiej, niż ma to miejsce w przypadku statycznego obiektu, czy nawet pojazdu (heh...świetny tekst...mam dziś wenę twórczą ;] ). Wynika to oczywiście z faktu, że ludzie mogą mieć coś do powiedzenia oraz z istnienia komend SetMimic zmieniającej mimikę twarzy osoby i PlayMove pozwalającej skorzystać z całej gamy animacji dostępnych w OFP. Aby zmieniła się mimika twarzy aktora należy w odpowiednim miejscu skryptu wpisać polecenie nazwa_aktora SetMimic "mimic" . Możliwe wartości parametru mimic to: "Default", "Normal", "Smile", "Hurt", "Ironic", "Sad", "Cynic", "Suprised", "Agresive" (literówka!), "Angry". Powrót do normalnego (obojętnego) wyrazu twarzy uzyskujemy parametrem "Default" lub "Normal" (jest jakaś różnica? Ja nie zauważyłem). Dialogi stanowią bardzo rozbudowane zagadnienie. Najprostsza metoda polega na użyciu omawianej wcześniej komendy TitleText czyli na wyświetleniu wyświetlenie napisu tłumaczącego/informującego co zostało powiedziane. Niestety nie mamy w tej sytuacji ani dźwięku ani ruchu warg co zmusza do unikania zbliżeń twarzy.Tak samo wygląda kwestia użycia komend radiowych tj. GlobalChat, SideChat, GroupChat, VehicleChat (należy pamiętać, by wcześniej odwołać blokowanie komunikatów radiowych ustawione za pomocą EnableRadio false). By uzyskać dźwięk lub chociaż ruch warg mówiącej osoby, musimy uciec się do bardziej skomplikowanych metod: Pierwsza (prostsza) metoda polega na użyciu istniejących w grze plików dźwiękowych (czyli niestety jesteśmy tym samym ograniczeni do około czterdziestu krótkich kwestii w dwóch językach). W tym celu wystarczy umieścić w odpowiednim miejscu skryptu polecenie nazwa_aktora Say "ID_kwestii". Istnieją następujące kwestie (jeżeli tekst się powtarza to oznacza, że jest wypowiadany przez różne osoby, co pozwala uniknąć wrażenia że wszyscy mówią jednym głosem): ENG1 Bastards! Kwestie rosyjskojęzyczne (RUS1-20) są oczywiście wypowiadane po rosyjsku. Jak widać nie mamy do wyboru zbyt zróżnicowanych zwrotów i nie za bardzo da się z tego sklecić jakąś sensowną rozmowę. Można ewentualnie spróbować nieco pokombinować umieszczając np. następujące linijki kodu: 0 FadeSound 0 Wpisując powyższe otrzymujemy co prawda bezdźwięczny dialog (w tym przypadku właściwie monolog ;), ale za to już z ruchem warg (niestety niezgodnym z wypowiadaną kwestią... no cóż w latach 80-tych dubbing nie był jeszcze na najwyższym poziomie ;). Metoda trudniejsza polega na stworzeniu własnych plików dźwiękowych o rozszerzeniu .ogg oraz związanych z nimi plików (kontrolujących ruch warg przy wypowiedzi) o rozszerzeniu .lip. Jakby tego nie było dość, musimy jeszcze stworzyć, na potrzeby obsługi dźwięku w misji, pliki description.ext i stringtable.csv. Do wykonania powyższego zadania potrzebne są programy Ogg Drop oraz Wav2Lip oraz pliki z rozszerzeniem .wav (które zawierają kwestie do umieszczenia w misji). Uwaga! Pliki te muszą dodatkowo spełniać pewne warunki tj. muszą mieć 16 bit, 44100 kilohertz, 64 kbps bit rate. Ponadto muszą być Mono (dotyczy to mowy i dźwięków, tło muzyczne może być Stereo). Musicie skorzystać z jakiegoś programu do obróbki dźwięku by zmienić ich format jeżeli jest inny niż podany. Kolejnym krokiem jest użycie Ogg Drop'a. W tym celu uruchamiamy go i klikamy na okienko z rybką (takowe powinno się pojawić) prawym klawiszem myszy otwierając menu kontekstowe. Następnie rozwijamy opcję Bitrate i wybieramy 64 kbps (niestety domyślny dla Oggdrop'a bit rate to 80,więc trzeba za każdym razem pamiętać o dokonaniu tej zmiany). Na koniec przeciągamy plik .wav na okienko z rybką (będziecie wiedzieli gdzie to jest, zresztą napisane jest tam "Drop files here"). W efekcie w katalogu w którym jest Oggdrop pojawi się plik o nazwie takiej jak .wav tyle, że z rozszerzeniem .ogg. Plik ten umieszczamy w specjalnym folderze o nazwie Sound, który tworzymy w folderze naszej misji (czyli np. C:\ Program Files\ Codemasters\ OperationFlashpoint\ Users\ Alderous\ missions\ Moja_misja\ Sound). Teraz konieczne jest stworzenie pliku description.ext, który znajdzie się w folderze z naszą misją (plik description.ext może służyć do wielu innych rzeczy, ale nie będę ich omawiał przy tej okazji). By stworzyć taki plik wystarczy notatnik (Notepad is your best friend ;). Dla opisania plików z dialogami i dźwiękami wpisujemy: (na czerwono zaznaczyłem fragment, który dotyczy jednego pliku .ogg): class CfgSounds class nazwa_klasy1 class nazwa_klasy2 Jak widać każdy { musi być zakończony
}; . Musimy opisać każdy plik tj. powtórzyć zielono
zaznaczony fragment dla każdego pliku dźwiękowego, który chcemy umieścić w misji.
Opisywanie polega na powiązaniu klas z nazwami plików (zwykle są takie same
np. class gadka1 i plik gadka1.ogg) oraz na dodaniu komentarzy (tj. titles -
aczkolwiek nie jest to konieczne, można nic nie wpisać między klamry), które
pojawiają się automatycznie (nie trzeba używać TitleText). Warto zauważyć, że
w przypadku dźwięków możliwe jest dodanie kilku komentarzy do jednego pliku
(w przypadku komunikatów radiowych nie jest to możliwe). Kolejne komunikaty
będą się pojawiały po upływie czasu podanego przy nich (w powyższym przykładzie:
pierwszy wyświetli się od razu, a drugi w 3 sekundzie po rozpoczęciu emisji
dźwięku). Jest to przydatne przy długich kwestiach, bo tekst może być wyświetlony
tylko w jednej linijce. Parametr db-40 oznacza
głośność odgrywania dźwięku, względem ustawionej w grze (można np wpisać db+30).
Z kolei 1.0 to względna barwa dźwięku (relative
pitch - popróbujcie pozmieniać ustawienia w Gracz->Edycja->Barwa głosu,
to zrozumiecie co to jest). Jeżeli dźwięki te mają być komunikatami radiowymi tj. wygenerowanymi
za pomocą komend GlobalRadio, SideRadio,
GroupRadio, VehicleRadio
(wtedy dodawany jest na końcu charakterystyczny odgłos "radiowy")
musi umieścić dla nich następny, bardzo podobny (niemal identyczny) fragment
kodu. Różni się on tylko tym, że nazwa całej klasy to class CfgRadio
(zamiast class CfgSounds) oraz tym, że przy opisie każdego pliku dźwiękowego
piszemy: titles[] = Czyli nie ma możliwości umieszczenia więcej niż jednego komentarza. Ostatnia sprawa to stworzenie pliku stringtable.csv. Plikt ten zawiera teksty potrzebne do użycia w grze (nie tylko do komentowania wypowiadanych kwestii). Dzięki jego użyciu możemy stworzyć misję, w której napisy będą wyświetlane w różnych językach, w zależności od wersji językowej gry. Ze względu na irytujący zwyczaj modyfikowania typów plików przez Exel'a proponuję stworzyć ten plik w notatniku (najlepiej było, by zmienić przypisanie rozszerzenia .csv z Exel'owskiego na Notepad'a). Piszemy więc w notatniku na przykład coś takiego (nawiązując do poprzednich przykładów): LANGUAGE,English,Polish,Comment Tylko STR jest konieczne ciąg dalszy identyfikatora może być różny np. STR_kom2 ,STRCAMP_sound23). Tak spreparowany plik wstawiamy do folderu z tworzoną misją. W komendach Say, GlobalRadio, SideRadio, GroupRadio, VehicleRadio używamy nazwy pliku. Uwaga! Umieszczając powyższe komendy w skrypcie musimy pamiętać, że skrypt nie zaczeka na dokończenie wypowiedzi więc należy umieścić pewne opóźnienie o długości równej długości wypowiadanej kwestii (za pomocą ~n). Z odtwarzaniem dźwięków wiąże się komenda t FadeSound v która powoduje ściszenie lub pogłośnienie dźwięków odtwarzanych w grze (ale nie muzyki). Parametr t określa w jakim czasie (w sekundach) ma nastąpić zmiana głośności, a z kolei parametr v określa o ile dźwięk ma być ściszony (gdy v<1, dla v=0 nie ma dźwięku), lub pogłośniony (v>1). Teraz kolej na stworzenie plików .lip które odpowiadają za ruch warg osób podczas wypowiedzi. Jak już wspominałem do tego potrzebny jest program Wav2Lip. Uruchamiamy program Wav2Lip i przeciągamy plik .wav (mam nadzieję że go nie skasowaliście po uzyskaniu ogg'a).W folderze w którym mamy plik wav pojawi się plik .lip o tej samej nazwie, który powinniśmy umieścić w tym samym katalogu co plik ogg. Uwaga! Pamiętajcie, że plik musi być w formacie 16 bit, 44100 kilohertz, 64 kbps bit rate, Mono żeby Wav2Lip zadziałał. Uwaga! Bardzo istotna. Zawartość description.ext ładuje się po wczytaniu misji (w edytorze) więc jeśli dokonamy jakichś zmian musimy wczytać misję jeszcze raz. Dołączanie własnej muzyki do misji wymaga działań podobnych jak w przypadku
dołączania dźwięków i dialogów. Podobnie jak poprzednio muzyka musi być zawarta
w pliku .wav i spełniającym określone warunki tj. 16 bit,
44100 kilohertz, 64 kbps
bit rate, tyle że tym razem może być również Stereo.
Używając Oggdrop'a uzyskujemy muzykę w formacie .ogg (pamiętajcie o zamianie
ustawień Ogg Drop'a na 64 kbps), którą tym razem kopiujemy do folderu Music
który tworzymy w folderze misji, w której ma być użyta muzyka. class CfgMusic class nazwa_pliku1 Oczywiście można tak jak poprzednio dodać tyle ścieżek dźwiękowych na ile ma
się ochotę deklarując dla każdej z nich klasę (class nazwa_plikun). Nim zacznę wyjaśniać jak używać animacji muszę zaznaczyć, że była to najdłużej opracowywana część tego poradnika. Jestem pewien, że wymaga uzupełnienia i poprawek, co mam zamiar zrealizować w kolejnych wersjach tego poradnika. Do tej pory nie spotkałem się z opracowaniem zawierającym opis wszystkich animacji (ok. 400 choć przekonałem się , że jest ich jeszcze więcej), wymienionych w CMREF'ie (zwykle omówione jest ok. 20), toteż musiałem większość sprawdzić sam (na co nie miałem niestety zbyt dużo czasu). Na dobry początek należy sobie uświadomić, że większość z 400 animacji każdy grający w OFP widział na własne oczy, chociaż może nie uświadamiał sobie tego. Animacje te po prostu są uruchamiane przez "engine" gry w odpowiedzi na nasze działania np. animacja "CombatRunF" jest używana zawsze, gdy jakiś żołnierz biegnie do przodu, z bronią w ręku (ponieważ odpowiada za przebiegnięcie ok.2m jest zapętlana). Oczywiście możemy je jednak wywołać na rządanie używając komend: nazwa_jednostki SwitchMove "nazwa_animacji" lub nazwa_jednostki PlayMove "nazwa_animacji" (w pierwszym przypadku zazwyczaj następuje natychmiastowe przejście do zadanej pozy). Jest to trochę rozczarowujące, gdyż okazuje się, że używanie jedynie 30-40 animacji ma jakiś sens, resztę można wywołać po prostu dając jednostkom rozkazy (np. po co używać, wymienionej już, animacji "CombatRunF" skoro można po prostu ustawić jednostce punkt trasy i zrobi dokładnie to samo). Wśród tych animacji znajduję się także animacje zawierające w nazwie Dead lub Dying, te oczywiście trwają aż do odwołania, ale nie oznacza to że, użycie ich wobec jednostki powoduje ich śmierć. Jest to o tyle istotne, że nie zadziałają wyzwalacze reagujące na nieobecność jednostek określonej strony. Wśród Animacji są takie, które kończą swe działanie same oraz takie, które trwają tak długo, aż nie nakażemy postaci wykonanie następnej animacji. Uwaga! Ciekawe, że jeżeli jakąś animację umieścimy tak, by uruchomiła się z chwilą rozpoczęcia misji, to nawet jeśli "normalnie" trwa bez końca (tj. nawet uruchamianie kolejnych animacji nie sprawi, że AI "odzyska wolną wolę") to w tym przypadku możemy ją odwołać (badam dokładnie tę sprawę). Ogólnie rzecz biorąc wszystkie animacje możemy podzielić na trzy grupy. Pierwszą z nich stanowią animacje odpowiadające za pozy i ruch jakie charakteryzują
załogi .(Commander, Driver, Gunner) i pasażerów (Cargo, CoDriver) pojazdów.
Nazwy tych animacji zaczynają się nazwą pojazdu, po czym następuje określenie,
którego członka załogi dotyczy animacja i na końcu co animacja powoduje (np.
"BMPCommanderOutDying" to animacja dowódcy BMP, odtwarzająca jego
śmierć, w chwili gdy jest wychylony z włazu). Animacje te możemy wywołać jedynie
za pomocą SwitchMove i trwają do odwołania (no chyba, że ktoś zastrzeli
tych biedaków). Użycie ich wobec zwykłych piechurów powoduje dosyć zabawne,
ale całkowicie nieprzydatne efekty (w stylu facet siedzący w powietrzu, albo
zanurzony po pas w ziemi). "5TCoDriverV1", "5TCoDriverDead", "5TCoDriverDying", "5TDriver", "5TDriverV1", "5TDriverDead", "5TDriverDying", "AH1Pilot", "AH1PilotV1", "AH1PilotDead", "AH1PilotDying", "AH1Gunner", "AH1GunnerV1", "AH1GunnerDead", "AH1GunnerDying", "AH1Pilot", "AH1PilotV1", "AH1PilotDead", "AH1PilotDying", "BMPCommander", "BMPCommanderV1", "BMPCommanderOut", "BMPCommanderOutV1", "BMPCommanderOutDead", "BMPCommanderOutDying", "BMPDriver", "BMPDriverV1", "BMPDriverOut", "BMPDriverOutV1", "BMPDriverOutDying", "BMPGunner", "BMPGunnerV1", "BMPGunnerOut", "BMPGunnerOutV1", "BMPGunnerOutDying", "BMPGunnerOutDead", "CesnaCargo", "CesnaCargoV1", "CesnaCargoDead", "CesnaCargoDying", "CesnaPilot", "CesnaPilotV1", "CesnaPilotDead", "CesnaPilotDying", "HRLGunner", "HRLGunnerV1", "HRLGunnerDead", "HRLGunnerDying, "JeepCoDriver", "JeepCoDriverV1", "JeepCoDriverDead", "JeepCoDriverDying", "JeepCoDriverBack", "JeepCoDriverBackV1", "JeepCoDriverBackDead", "JeepCoDriverBackDying", "JeepGunner", "JeepGunnerV1", "JeepGunnerDead", "JeepGunnerDying", "JeepDriver", "JeepDriverV1", "JeepDriverDead", "JeepDriverDying", "M113Driver", "M113DriverV1", "M113DriverOut", "M113DriverOutV1", "M113DriverOutDead", "M113DriverOutDying", "M113Gunner", "M113GunnerV1", "M113GunnerDead", "M113GunnerDying", "M113Medic", "M113MedicV1", "M1A1Commander", "M1A1CommanderV1", "M1A1CommanderOut", "M1A1CommanderOutV1", "M1A1CommanderOutDead", "M1A1CommanderOutDying", "M1A1Gunner", "M1A1GunnerV1", "M1A1DriverOut", "M1A1DriverOutV1", "M1A1DriverOutDead", "M1A1DriverOutDying", "M2Gunner", "M2GunnerV1", "M2GunnerDead", "M2GunnerDying", "M60Commander", "M60CommanderV1", "M60CommanderOut", "M60CommanderOutV1", "M60CommanderOutDead", "M60CommanderOutDying", "M60Driver", "M60DriverV1", "M60DriverOut", "M60DriverOutV1", "M60DriverOutDying", "M60DriverOutDead", "M60Gunner", "M60GunnerV1", "Mi17Pilot", "Mi17PilotV1", "Mi17PilotDead", "Mi17PilotDying", "Mi24Gunner", "Mi24GunnerV1", "Mi24GunnerDying", "Mi24PilotV1", "Mi24PilotDead", "Mi24PilotDying", "Para", "ParaV1", "ParaDead", "ParaDying", "PBRDriver", "PBRDriverV1", "PBRDriverDead", "PBRDriverDying", "PBRGunner", "PBRGunnerV1", "PBRGunnerDead", "PBRGunnerDying", "ScudCoDriver", "ScudCoDriverV1", "ScudCoDriverDead", "ScudCoDriverDying", "ScudDriver", "ScudDriverV1", "ScudDriverDead", "ScudDriverDying", "SkodaCoDriver", "SkodaCoDriverV1", "SkodaCoDriverDead", "SkodaCoDriverDying", "SkodaCoDriverBack", "SkodaCoDriverBackV1", "SkodaCoDriverBackDead", "SkodaCoDriverBackDying", "SkodaDriver", "SkodaDriverV1", "SkodaDriverDead", "SkodaDriverDying", "T55Commander", "T55CommanderV1", "T55CommanderOut", "T55CommanderOutV1", "T55CommanderOutDead", "T55CommanderOutDying", "T55DriverOut", "T55DriverOutV1", "T55DriverOutDead", "T55DriverOutDying", "T55Gunner", "T55GunnerV1", "T72Commander", "T72CommanderV1", "T72CommanderOut", "T72CommanderOutV1", "T72CommanderOutDead", "T72CommanderOutDying", "T72DriverOut", "T72DriverOutV1", "T72DriverOutDead", "T72DriverOutDying", "T72Gunner", "T72GunnerV1", "T72GunnerOut", "T72GunnerOutV1", "T72GunnerOutDead", "T72GunnerOutDying", "T80CommanderOut", "T80CommanderOutV1", "T80CommanderOutDead", "T80CommanderOutDying", "T80GunnerOutV1", "T80GunnerOutDead", "T80GunnerOutDying", "TractorDriver", "TractorDriverV1", "TractorDriverDead", "TractorDriverDying", "UazCoDriver", "UazCoDriverV1", "UazCoDriverDead", "UazCoDriverDying", "UazDriver", "UazDriverV1", "UazDriverDead", "UazDriverDying", "UH60Gunner", "UH60GunnerV1", "UH60GunnerDead", "UH60GunnerDying", "UH60Pilot", "UH60PilotV1", "UH60PilotDead", "UH60PilotDying", "UralCoDriver", "UralCoDriverV1", "UralCoDriverDead", "UralCoDriverDying", "UralDriver", "UralDriverV1", "UralDriverDead", "UralDriverDying", "V3SCoDriver", "V3SCoDriverV1", "V3SCoDriverDead", "V3SCoDriverDying", "V3SDriver", "V3SDriverV1", "V3SDriverDead", "V3SDriverDying", "ZSUCommander", "ZSUCommanderV1", "ZSUCommanderOut", "ZSUCommanderOutV1", "ZSUCommanderOutDead", "ZSUCommanderOutDying", "ZSUDriver", "ZSUDriverV1", "ZSUDriverDead", "ZSUDriverDying", "ZSUGunner", "ZSUGunnerV1", "ZSUGunnerOut", "ZSUGunnerOutV1", "ZSUGunnerOutDead", "ZSUGunnerOutDying". Drugą grupę animacji stanowią animacje używane podczas ruchu żołnierzy i cywilów oraz przy wykonywaniu pewnych specjalnych akcji (np. leczenie, podkładanie ładunku itd). Ich nazwy nie podlegają jakiejś uniwersalnej regule, ale zwykle zawierają określenie stanu w jakim znajduje się jednostka (tj. stanu w jakim używana jest domyślnie ta animacja np. Combat, Crouch, Stand ect...) i określenie czynności. Animacje te zwykle trwają tylko chwilę (normalnie w grze są zapętlone lub w jakiś sposób zatrzymywane), przy czym użycie PlayMove powoduje odtworzenie całej animacji, a SwitchMove tylko opisanego fragmentu (niektóre czynności wymagają animacji rozpoczynającej i kończącej) np. użycie: nazwa _jednostki PlayMove "CrouchToCombat" spowoduje, że żołnierz najpierw uklęknie po czym wstanie, podczas gdy użycie nazwa _jednostki SwitchMove "CrouchToCombat" sprawi, że nagle znajdzie się w pozycji klęczącej, po czym wstanie. Ich przydatność nie jest zbyt duża z racji tego, że w większości przypadków można je zastąpić po prostu używając komend powodujących wykonanie czynności opisywanych przez te animacje (odnosi się to zwłaszcza do animacji ruchu). Oto spis animacji: "BinocCrouchToCrouch", "BinocLyingToLying", "BinocStandToStand", "BinocToCombat" - różne (w zależności od stanu jednostki) animacje zakończenia używania lornetki (przy PlayMove cała sekwencja podniesienia do oczu i opuszczenia), trwają tylko chwilę. "Cargo", "CargoVer1",
"CargoVer2", "CargoVer3",
"CargoVer4", "CargoVer5"
- różne wersje animacji postaci siedzących jako pasażerowie (zwykle widzicie
to w ciężarówce), niektóre poruszają się. Animacje te wywołuje tylko komenda
SwitchMove, trwają bez końca. Mogą być przydatne, bo żołnierzy można posadzić
gdziekolwiek (nie muszą być w pojeździe). "Commander", "Driver", "Gunner", "Pilot" - wbrew nazwie animacje te zachowują się tak jak animacja "Cargo". "CivilDead", "CivilDeadVer2",
"CivilDying", "CivilDyingVer2"
- dwie animacje martwych i umierających cywili, trwją oczywiście bez końca. Uwaga! Animacje dotyczące cywili można stosować również do żołnierzy (i na odwrót). "CombatDead", "CombatDeadVer2",
"CombatDeadVer3", "CombatDying",
"CombatDyingVer2", "CombatDyingVer3",
"CombatRelaxedDeadVer2", "CombatRelaxedDying",
"CombatRelaxedDyingVer2" - różne animacje
martwego i umierającego żołnierza, trwają bez końca. Uwaga! Animacje "Combat..." pokazują żołnierzy w trybie "AWARE", "COMBAT" albo "STEALTH". "CrouchDying" - animacja umierania w
pozycji klęczącej. Trwa bez końca. "LyingCrawlF", "LyingCrawlL",
"LyingCrawlR" - animacje czołgania się
naprzód (F) na lewo (L) i na prawo (R). Trwa tylko chwilę. Uwaga! Przy użyciu polecenia SwitchMove w stosunku do animacji typu "Crouch..." lub "Lying..." spowoduje, że postacie nagle znajdą się w pozycji klęczącej lub leżącej. Przy użyciu PlayMove płynnie przejdą do tej pozy. "MedicToCombat" - animacja kończąca udzielanie pomocy medycznej. Przy użyciu PlayMove odtwarzana jest cała sekwencja. Trwa tylko chwilę. "PutDownLyingToLying" - animacja zakończenia
podkładania ładunku wybuchowego z pozycji leżącej. Trwa tylko chwilę. Uwaga! Zauważ, że animacje "LyingToPutDownLying" i "PutDownLyingToLying" oraz "Combat ToPutDown" i "PutDownToCombat" przy użyciu PlayMove wyglądają tak samo (przy użyciu SwitchMove uzupełniają się). "StandBase" - nie wiem co to daje (przy
użyciu SwitchMove postać tylko drgnęła). Uwaga! Animacje "Stand..." pokazują żołnierzy w trybie "SAFE" albo "CARELESS". "TreatedLyingToLying" - animacja zakończenia
otrzymywania pomocy medycznej z pozycji leżącej. Trwa tylko chwilę. Uwaga! Zauważ, że animacje "LyingToTreatedLying" i "TreatedLyingToLying" oraz "CombatToTreated" i "TreatedToCombat" przy użyciu PlayMove wyglądają tak samo (przy użyciu SwitchMove uzupełniają się). "Weapon" - ? Wreszcie trzecią najważniejszą grupę animacji stanowią animacje stworzone na
potrzeby przerywników filmowych (lub z jakichś powodów nie umieszczone wśród
animacji grupy drugiej). "EffectCombatStand", "CombatStillV1"
- Animacja żołnierza celującego przez chwilę w postawie pełnej napięcia (kiwa
się lekko przestępując z nogi na nogę). "FXangel", "FXangel2"
- animacje które zastosowano w kampanii 1985 w stosunku do Angeliny (u innych
postaci wygląda to dziwnie). Wywoływane jedynie za pomocą SwitchMove. Trwają
bez końca. Uwaga! W przypadku większości animacji FX... postacie nie da się zabić podczas ich trwania (wyjątkiem są np. animacje siedzących postaci i salutowania). Zwykle też animacje nie kończą się same. "OnChair" - animacja postaci siedzącej na krześle (prosto). Wywoływana jedynie SwitchMove. Trwa bez końca. Postaci podczas trwania animacji nie da się zabić. "StandStrokeFist", "StandStrokeFistEnd"
- animacje rozpoczęcia i zakończenia wymierzania ciosu ręką. W przypadku użycia
PlayMove wyglądają tak samo. Trwają tylko chwilę. "LyingStillV1" - animacja leżącej postaci, która zerka w bok. Trwa tylko chwilę. "CombatStrokeGunEnd" - animacja kończąca cios kolbą, przy użyciu SwitchMove, lub pełną sekwencję ciosu przy użyciu PlayMove. "CivilStillV1" - ciekawa animacja stojącego cywila (wgląda trochę jak naćpany, ręce opuszczone, kiwa lekko na boki), trwa bez końca. "CommandEngageAtWill" - animacja dowódcy
zezwalającego na atak wedle własnego uznania (Engage at will). Sygnalizuje on
to ręką, machając do przodu i na boki. Działa tylko ze SwitchMove. Nie kończy
się sama. Podczas trwania animacji postaci nie da się zabić. Elementy dodatkowe stanowią różne triki (zwykle w postaci komend lub pętli). Przejścia między ujęciami uzyskujemy umieszczając w skrypcie opisane na początku komendy: TitleCut["","BLACK IN",n] Zamiast "BLACK..." można użyć "WHITE...", co daje efekt flasza aparatu fotograficznego (dawajcie krótki czas). Zalecam stosowanie przy krótkich dynamicznych ujęciach. Zmiany pory dnia uzyskujemy komendą SkipTime n gdzie n oznacza przesunięcie czasu wyrażone w godzinach. Zmienia się jedynie pogoda (zgodnie z prognozą) i pora dnia, jednostki pozostają na swoich miejscach. 3.12 Zmiany warunków atmosferycznych Zmiany warunków pogodowych uzyskujemy komendami: t SetFog v - zmienia stopień zamglenia
do poziomu v (zakres od 0 do 1) w czasie t sekund. 3.13 Przyspieszanie i spowalnianie upływu czasu Zmiany prędkości upływu czasu uzyskujemy komendą SetAccTime
v. Wartości v od 0 do 1 spowalniają upływ czasu, a wartości większe
niż jeden przyspieszają (v=1 przywraca normalny upływ czasu). W OFP mamy możliwość nałożenia kilku rodzajów nakładek (overlays) w postaci telewizora, widoku z lornetki czy nakładki dającej efektu zdjęcia (czarno-białego). Do wywołania tych efektów należy użyć komend: CutObj ["TvSet","PLAIN"]
lub TitleObj ["TvSet","PLAIN"]
- nakładka typu telewizor. Powrót do normalnego widoku uzyskujemy wpisując komendę odpowiednio: CutObj ["default","PLAIN"]
lub TitleObj ["default","PLAIN"] 3.15 Przybliżanie i oddalanie widoku Zbliżenia (zoom) i oddalenia (unzoom) kamery uzyskujemy komendą _cam
CamSetFOV z, która powoduje ustawienie zbliżenia z (gdzie dla
z od 0 do 1 otrzymujemy zbliżenie, a dla z większych o 1 oddalenie. Użycie z=1
przywraca domyślne zbliżenie) dla kamery skojarzonej ze zmienną lokalną skryptu
_cam. 3.16 Ustawianie kamery względem obiektu Gdy nie jesteśmy w stanie przewidzieć jak będzie zwrócony obiekt, a chcemy np. mieć ujęcie z przodu przydaje się następujący fragment kodu: _dir = GetDir obiekt Umieści on kamerę 2 metry przed obiektem na wysokości pół metra. 3.17 Obracanie kamery wokół punktu Obrót kamery wokół obiektu realizuje następująca pętla: _cam CamSetTarget obiekt Pętla zostanie wykonana 180 razy co potrwa około 3,6 sekundy (180*0,02sek). Ciekawym efektem jest kamera towarzysząca obiektowi będącemu w ruchu. Efekt ten uzyskujemy za pomocą następującej pętli: _cam CamSetTarget obiekt Pętla ta będzie utrzymywać kamerę w punkcie (względem obiektu) ustalonym za
pomocą komendy CamSetRelPos. _i=0 Niestety w przypadku pojazdów z wieżą kierunek dotyczy kierunku jazdy a nie
kierunku ustawienia wieży. 3.19 Kamera towarzysząca wykonująca obrót Możliwe jest połączenie dwóch poprzednich efektów w jeden za pomocą pętli: _cam CamSetTarget obiekt Pętla zostanie wykonana 180 razy co potrwa około 3,6 sekundy (180*0,02sek). Kamera wykona pół obrót tj. przejdzie z jednej strony obiektu na drugą. Przykłady: Napisał: ALDEROUS |
|