Poprzedni temat «» Następny temat
[TUTORIAL] Jak tworzyć sny i CutScenki
Autor Wiadomość
Marcin 
Feniks


Wiek: 25
Posty: 93
Podziękowania: 15/3
Wysłany: 2008-10-12, 21:56   [TUTORIAL] Jak tworzyć sny i CutScenki

Jak tworzyć sny i CutScenki
Opracowanie: Marcin

Wersja 2.0

1. Co to jest cutscenka?

Cutscenka jest to zaplanowane zdarzenie warunkowane właściwym skryptem.
W grze znajduje się bardzo wiele Cutscenek. Cutscenkami są sny z Irenicusem, czy choćby torturowanie <CHARNAME> na początku gry przez Irenicusa.

2. Jak zrobić cutscenkę?

a) Cutscenkę tworzymy jak zwykły skrypt. Możemy napisać ją w notatniku, lub w DLTCEP, ale ja polecam Infinity Script editor. Przeznaczony jest właśnie do pisania skryptów i gwarantuje łatwy dostęp do plików IDS.
b) Cutscenka jak każdy skrypt składa się z bloku:

Kod:
IF
    Tutaj będą warunki, jakie muszą być spełnione
THEN
    RESPONSE #100
        Tutaj piszemy akcje, jakie mają wykonywać różne postacie
END


3. Jak rozpocząć tworzenie cutscenki.

Najczęściej cutscenki są aktywowane poprzez odpowiednią komendę w dialogu lub innym skrypcie.

W skrypcie:

Kod:
IF
    Global("cutscenka","GLOBAL",0) // Warunki konieczne do rozpoczęcia cutscenki
THEN
    RESPONSE #100
        StartCutSceneMode() // blokuje mysz, klawiaturę i powoduje zniknięcie wszystkich pasków interfejsu
        ClearAllActions()  //Wstrzymuje wszystkie akcje obecnie wykonywane (np.: atak, rzucanie czaru, chód)
        StartCutScene("cutscenka1")  //odwołanie do określonego pliku w którym mamy cutscenkę.
        SetGlobal("cutscenka","GLOBAL",1) // zmiana wartości zmiennej.
END


Tutaj warunkiem jest zmienna która tylko gdy jest ustawiona na 0 powoduje start cutscenki

W dialogu:

Kod:
IF ~~ THEN BEGIN cutscenka1
SAY ~tekst.~
IF ~~ THEN REPLY ~tekst.~ DO ~ StartCutSceneMode()   
ClearAllActions() 
StartCutScene("cutscenka1") ~ EXIT
END


Tutaj piszemy odwołanie do konkretnego pliku wcześniej blokując mysz i klawiaturę oraz przerywając wszystkie akcje.

Najważniejsze komendy, które towarzyszą zawsze cutscenką to:

StartCutSceneMode() // blokuje mysz, klawiaturę i powoduje zniknięcie wszystkich pasków interfejsu
ClearAllActions() //Wstrzymuje wszystkie akcje obecnie wykonywane (np.: atak, rzucanie czaru, chód)
StartCutScene("cutscenka1") //odwołanie do określonego pliku w którym mamy cutscenkę.

4. Następnie tworzymy skrypt w którym będą wszystkie akcje budujące nasza cutscenkę.

Zamieszczam tu przykładową cutscenke pochodzącą z nowej wersji Larshy. Pokazuje ona porwanie Larshy.

Kod:
IF
    True()  // wszystkie warunki są spełnione
THEN
    RESPONSE #100
        CutSceneId("kasnimf1")  // cutscenkę kontroluje kasnimf1, do niej odnoszą się wszystkie akcje. Jest to komenda zaczynająca każda cutscenke. Istota ją kontrolująca powinna się znajdować na obszarze, gdzie ma się odbywać cutscenka.
        FaceObject("Larsha")  // kasnimf1 obraca się w stronę Larshy
        MoveViewObject("kasnimf1",INSTANT) // Kamera natychmiast przeskakuje w miejsce gdzie znajduje się kasnimf1
        SmallWait(10) // To oznacza, że jest chwilowa przerwa, 1/10 sekundy, jest to zauważalne przez gracza.
        DisplayStringHead(Myself,~Nie obronisz się przede mną driado! Już po Tobie.~) // tekst wyświetla się nad postacią   
        CreateVisualEffectObject("SPCMWOUI",Myself)  //specjalny efekt animacji
        ForceSpell("Larsha",CUTSCENE_DAMAGE_1B)  //kasnimf1 rzuca na Larshę zaklęcie
        SmallWait(1)
        SetGlobal("porwanie","GLOBAL",4)  // zmiana wartości zmiennej
        SetGlobal("czas","GLOBAL",1)
        ActionOverride("Larsha",SetInterrupt(FALSE))  // zablokowanie możliwości interakcji z Larshą, jest to konieczne dla tej cutscenki.
        SmallWait(1)
        ActionOverride("Larsha",LeaveParty()) //Larsha odłącza się od drużyny, a dzięki zablokowaniu możliwości interakcji nie podchodzi do nas z gadką na odejście z drużyny.
        ActionOverride("Larsha",DropInventory()) //Larsha opuszcza na ziemie cały ekwipunek
        SmallWait(1)
        ActionOverride("Larsha",PlayDead(85)) // Teraz Larsha udaje martwą
        Wait(3)    // 3 sekundy przerwy
        DisplayStringHead("Larsha",~<CHARNAME> ratuj mnie!~) // tekst wyświetla się nad Larshą
        ForceSpell("Larsha",DRYAD_TELEPORT)  // kasnimf1 rzuca czar na larshę, który powoduje znikniecie jej z mapy
        SmallWait(20)
        MoveToObject("larsha")  //kasnimf1 podchodzi do larshy
        Wait(1)
        DestroySelf()  // kasnimf1 ulega zniszczeniu bez pozostawiania ciała ani ekwipunku
        EndCutSceneMode()  //zakończenie cutscenki odblokowanie klawiatury i myszki, ukazanie z powrotem pasków interfejsu.
END


Z tej cutscenki także można wybrać akcje, które zawsze występują w cutscenkach np.:

CutSceneId("kasnimf1") W nawiasie podajemy death variable postaci, która ma kontrolować cutscenkę i do której odnoszą się wszystkie akcje bezpośrednio. Rozpoczyna każdą cutscenkę

EndCutSceneMode() - zakończenie cutscenki, konieczne, bo inaczej wciąż klawiatura i myszka pozostaną zablokowane, a my nie będziemy mogli grać dalej. Zakańcza każda cutscenkę.

W tej cutscence pojawiła się niezwykle ważna komenda

Kod:
ActionOverride(O:Actor*,A:Action*)
jest ona bardzo przydatna w tworzeniu cutscenek, sprawia, że, pomimo że cutscenkę kontroluje jedna postać to może ona kazać innym wykonywać jakieś akcje.

W Actor wpisujemy w cudzysłowiu death variable postaci, która ma wykonać jakąś akcję znajdującą się w action. Np.:

Kod:
ActionOverride("Larsha",LeaveParty())
pomimo że Larsha nie kontroluje bezpośrednio cutscenki to dzięki ActionOverride ma nakazane, że ma się odłączyć od drużyny.

5. Dlaczego ActionOverride jest bardzo ważne i pomocne

Dzięki ActionOverride możemy umieścić całą cutscenkę w jednym bloku, co jest korzystniejsze niż umieszczać ją w kilku np.:


Kod:
IF
    True()  // wszystkie warunki są spełnione
THEN
    RESPONSE #100
        CutSceneId("kasnimf1")  // cutscenkę kontroluje kasnimf1, do niej odnoszą się wszystkie akcje..
        FaceObject("Larsha")
        MoveViewObject("kasnimf1",INSTANT)
        SmallWait(10)
        DisplayStringHead(Myself,~Nie obronisz się przede mną driado! Już po Tobie.~)
        CreateVisualEffectObject("SPCMWOUI") 
        ForceSpell("Larsha",CUTSCENE_DAMAGE_1B)
        SmallWait(1)
        SetGlobal("porwanie","GLOBAL",4)
        SetGlobal("czas","GLOBAL",1).
        SmallWait(1)
        SmallWait(1)
        Wait(3)   
        ForceSpell("Larsha",DRYAD_TELEPORT)
        SmallWait(20)
        MoveToObject("larsha") 
        Wait(1)
        DestroySelf() 
        EndCutSceneMode() 
END


IF
    True()  // wszystkie warunki są spełnione
THEN
    RESPONSE #100
        CutSceneId("Larsha")  // cutscenkę kontroluje Larsha, do niej odnoszą się wszystkie akcje..
        SmallWait(10)       
        SetInterrupt(FALSE)
        SmallWait(1)
        LeaveParty()
        DropInventory()
        SmallWait(1)
        PlayDead(85)
        Wait(3)   
        DisplayStringHead("Larsha",~<CHARNAME> ratuj mnie~)
        SmallWait(20)
        Wait(1)
END


Ta cutscenka odpowiada dokładnie tamtej, tyle, że tworzymy 2 osobne bloki, a w każdym są akcje dotyczące danej postaci.

Ten typ jest zawsze bardzo niepewny, co do swojej poprawności. W tym przypadku jest poprawnie, ale bardzo łatwo się pomylić, zwłaszcza, jeśli chodzi o czas pomiędzy akcjami. W rozdzielonych blokach może się okazać, że postacie za sobą nie nadążają, bo źle rozmieściliśmy odstępy pomiędzy akcjami.

Dzięki możliwości korzystania z ActionOverride możemy połączyć wszystko w jeden blok i mamy pewność, że wszyscy zakończą swoje akcje równocześnie.

Co do akcji, jakie mogą wystąpić w cutscenkach nie będę się rozpisywał, bo do tego trzeba poznać działanie większości plików IDS. W wyżej przedstawionej cutscence zamieściłem tylko te najczęściej używane.

6. Różne dziwne rzeczy w cutscenkach

W cutscenkach można stosować także rozpoczęcia dialogów.
Można wtedy tworzyć ciekawe połączenia pomiędzy Cutscenkami a dialogami.

Np.:

Kod:
IF
    Global("cutscenka","GLOBAL",0) 
THEN
    RESPONSE #100
        StartCutSceneMode()     
        ClearAllActions()
        SetGlobal("cutscenka","GLOBAL",1)
        SmallWait(10)       
        MoveToObject(player1) 
        StartDialogueNoSet(Player1) // rozpoczęcie dialogu z player1, czyli dzieckiem Bhaala
END


Ten skrypt musi być przypisany postaci, która wykona te akcje. Oczywiście można zrobić odwołanie do konkretnego pliku cutscenki, jednak przy bardzo krótkich cutscenkach można zrobić jak wyżej zamieszczając ją w skrypcie określonej postaci do której akcje się odnoszą np: chcemy zeby Larsha wykonała wszystkie akcje jakie są zamieszczone w tym skrypcie, to ten cały blo, musi się zanleźc w skrypcie, który jest jej przypisany.

Na końcu jak widać nie ma EndCutSceneMode() jest natomiast StartDialogueNoSet(Player1) który sprawia, że zaczynamy dialog z player1.
Jeśli używamy StartDialogueNoSet(Player1) to dany dialog musi być z góry przypisany postaci, która dialog rozpoczyna. Jeśli na natomiast nie jest on przypisany to należy użyć

StartDialog("dialog",Player1) wtedy dana postać której ta akcja dotyczy rozmawia z dzieckiem Bhaala wg Dialogu „dialog” i nie musi go mieć przypisanego.

Wraz z zakończeniem dialogu cutscenka się skończy, a jeśli chcemy, żeby się kontynuowała to należy zrobić konkretne odwołanie na końcu dialogu.

Kod:
IF ~~ THEN BEGIN cutscenka1
SAY ~tekst.~
IF ~~ THEN REPLY ~tekst.~ DO ~ StartCutSceneMode()   
ClearAllActions() 
StartCutScene("cutscenka2") ~ EXIT
END


W ten sposób cutscenka jest kontynuowana, jednak wprowadzenie dialogu sprawia, że musimy stworzyć nowy plik. Tzn. akcje które były przed dialogiem znajdują się w skrypcie postaci (przykładowo) a następne akcje po dialogu musza się znajdować w osobnym skrypcie (w tym przypadku "cutscenka2")


7. Teraz będzie najważniejsze, czyli tworzenie snów.

Sen składa się z 2 podstawowych elementów, a mianowicie cutscenki i nadpisania skryptu Player1d

a) Tworzymy sobie folder gdzie będą pliki naszego moda
b) Tworzymy plik tp2 o nazwie Setup-nazwamoda.tp2 (np.: za pomocą notatnika lub po prostu zmieniając nazwę już istniejącego pliku tp2 z innego moda, wtedy kasujemy także zawartość tego pliku.
c) Bierzemy z innego moda lub ściągamy Weidu i zmieniamy jego nazwę na setup-nazwamoda.exe
d) W folderze moda za pomocą Infinity Script Editor lub notatnika tworzymy plik Player1d.baf
e) Piszemy w nim:

Kod:
IF
    Global("sen","GLOBAL",0)
THEN
    RESPONSE #100
        SetGlobal("sen","GLOBAL",1)
        StartCutSceneMode()
        ClearAllActions() 
        StartCutScene("cutsen")
END


i zapisujemy
f) dzięki temu możliwe będzie odwołanie do pliku gdzie będzie cutscenka
g) teraz tworzymy następny plik o nazwie (w tym przypadku) cutsen.baf
h) zamieszamy w nim przykładową cutscenke, która będzie snem

Zamieszczam tutaj fragment pierwszego snu z Irenicusem i Imoen

Kod:
IF
    True()
THEN
    RESPONSE #100
        CutSceneId(Player1)  //Player1 kontroluje cutscenkę
        StorePartyLocations()  //zapamiętanie obecnego położenia drużyny
        FadeToColor([30.0],0)  // zaciemnienie ekranu
        Wait(1)  //1sekunda zaciemnienia
        Rest()  // odpoczynek dla Player1, dzięki któremu odzyskuje wszystkie czary, leczy rany itd.
        ActionOverride(Player2,Rest())
        ActionOverride(Player3,Rest())
        ActionOverride(Player4,Rest())
        ActionOverride(Player5,Rest())
        ActionOverride(Player6,Rest()) // odpoczynek reszty drużyny
        Wait(1) // 2 sekunda zaciemnienia
        LeaveAreaLUAPanic("AR0011","",[799.1579],0)
        LeaveAreaLUA("AR0011","",[799.1579],8)
        ActionOverride(Player2,LeaveAreaLUA("AR0011","",[715.1619],2))
        ActionOverride(Player3,LeaveAreaLUA("AR0011","",[733.1691],14))
        ActionOverride(Player4,LeaveAreaLUA("AR0011","",[801.1736],0))
        ActionOverride(Player5,LeaveAreaLUA("AR0011","",[700.1730],4))
        ActionOverride(Player6,LeaveAreaLUA("AR0011","",[651.1636],2)) // cała drużyna przenosi się na lokację gdzie ma się odbyć sen ( biblioteka w której się wychowaliśmy)
        MultiPlayerSync()
        MoveViewPoint([649.2036],INSTANT) //Natychmiastowe przesunięcie kamery do danego punkt na mapie
        ApplySpell(Player2,SURE_SLEEP)
        ApplySpell(Player3,SURE_SLEEP)
        ApplySpell(Player4,SURE_SLEEP)
        ApplySpell(Player5,SURE_SLEEP)
        ApplySpell(Player6,SURE_SLEEP)  // wszyscy oprócz player1 leżą na ziemi jakby spali.
        Explore()  // odsłonięcie całej mapy
        SmallWait(5)
        FadeFromColor([30.0],0)  //koniec zaciemnienia, teraz widzimy gdzie jesteśmy
        MoveViewPoint([799.1579],6)  //Player1 przemieszcza się do konkretnego punktu
        Wait(3)
        MAŁA ZMIANA W SKRYPCIE
        ActionOverride("Dream1",MoveToObject(Player1)) //Imoen idzie w naszą stronę
        ........... ciąg dalszy cutscenki............
        EndCutSceneMode()  //zakończenie cutscenki
        RestParty() //dzięki temu mamy ten filmik jak śpimy pod namiotem lub gdzieś indziej.
END


i) Jak widać sen składa się z kilku podstawowych elementów

- sen jest cutscenką i ma wszystkie komendy, które cutscenkę charakteryzują
- w snach często pojawia się

FadeToColor([30.0],0) i FadeFromColor([30.0],0) czyli zaciemnienie i odsłonięcie ekranu, bo zazwyczaj w czasie snu gdzieś się przenosimy
- komenda odpoczynku, dzięki której nasza drużyna zapamiętuje czary i leczy rany.
Rest()
ActionOverride(Player2,Rest())
ActionOverride(Player3,Rest())
ActionOverride(Player4,Rest())
ActionOverride(Player5,Rest())
ActionOverride(Player6,Rest())
oraz z RestParty() dzięki któremu nasza drużyna odpoczywa i pojawia się filmik towarzyszący odpoczynkowi.


j) Mamy już cutscenkę i zapisujemy. Tworzymy także w folderze moda pod folder Backup (musi być on pusty)
k) Teraz tworzymy instalkę, czyli edytujemy plik .tp2 notatnikiem

I wpisujemy w niej

Kod:
BACKUP ~nazwa folderu moda\Backup~
AUTHOR ~wpisujemy siebie~

BEGIN ~nazwa moda~

EXTEND_TOP ~player1d.bcs~  ~nazwa folderu moda/player1d.baf~

Dzięki temu nasz plik Player1d. baf zostanie skompilowany i dopisany do pliku player1d

COMPILE ~nazwa folderu moda /cutsen.baf~

Teraz nasza cutscenka zostanie skompilowana.


Włączamy setup-nazwa moda.exe i instalujemy.

Właśnie stworzyliśmy sen.

8. Co jeśli nie chcemy aktywowac cutscenki tylko zastosować coś innego np: ustawić timer.

- często jest tak, ze chcemy aby dopiero po jakimś czasie sen się pojawił, wtedy trzeba ustawić w pliku player1d takze blok to warunkujący np:

Kod:

IF
    Global("czas","GLOBAL",0)
THEN
    RESPONSE #100
        SetGlobalTimer("sen1","GLOBAL",TWO_DAYS) //Ustawiamy timer na czas dwóch dni wewnątrz gry.
        SetGlobal("czas","GLOBAL",1)
        Rest()
        ActionOverride(Player2,Rest())
        ActionOverride(Player3,Rest())
        ActionOverride(Player4,Rest())
        ActionOverride(Player5,Rest())
        ActionOverride(Player6,Rest())
        RestParty() // dzięki temu odbędzie się także normalny odpoczynek, z przywróceniem zapamiętanych czarów, przyczym przy okazji zostanie ustawiony timer.
END


Teraz piszemy pod spodem

Kod:
IF
    Global("czas","GLOBAL",1)
    GlobalTimerExpired("sen1","GLOBAL") // czas ustawiony w timerze minął.
THEN
    RESPONSE #100
        SetGlobal("czas","GLOBAL",2)
        StartCutSceneMode()
        ClearAllActions()
        StartCutScene("cutsen")
END


9. Dlaczego należy nadpisywać właśnie Player1d

Ponieważ tylko dzięki nadpisaniu tego skryptu będzie możliwe pokazanie cutscenki w postaci snu, tzn. normalnie gdybyśmy włączyli grę, by sprawdzić czy nasza cutscenka działa to byśmy zobaczyli, ze nie działa, bo niby wg warunków powinna się włączyć od razu po tym jak zaczęliśmy grę.

Dzięki temu, ze napisaliśmy plik player1d to cutscenka tworząca sen uaktywni się dopiero wtedy gdy klikniemy ikonkę odpoczynku.

Myślę, ze jeszcze poprawie ten tutorial, mam nadzieję, że choć trochę przybliżył wam jak tworzy się cutscenki lub sny.

Dziękuje każdemu kto przeczytał ten tutorial.
_________________
Larsha NPC - Pierwszy polski mod w którym pojawił się romans.
http://wrota.cob.netarteria.pl/dom-driada - o modzie
http://forum.cob.netarteria.pl/viewforum.php?f=126
Ostatnio zmieniony przez L`f 2014-04-27, 19:08, w całości zmieniany 4 razy  
Podziękuj autorowi tego posta
 
 
 
Więcej szczegółów
Za tę wypowiedź podziękowali:
morgan, Yochloll, Vel`Dan, Tuldor88
Wyświetl posty z ostatnich:   
Odpowiedz do tematu
Nie możesz pisać nowych tematów
Nie możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Nie możesz załączać plików na tym forum
Możesz ściągać załączniki na tym forum
Dodaj temat do Ulubionych
Wersja do druku

Skocz do:  
Powered by phpBB modified by Przemo © 2003 phpBB Group