Tutorial 30 - Podmínky |
Autor : Didymos |
Download = Tento tutorial + ukázka |
Muttley nás požádal o napsání tutoriálu, který
by se zabýval podmínkami. Toto je ale velmi těžký úkol, protože
podmínek může být opravdu mnoho. Z E-mailu, který Muttley napsal,
jsem pochopil, že mu jde o podmínku, kterou vyskočí z nějaké
smyčky. Na začátek bychom si mohli slovo podmínka nějakým
způsobem definovat. Podmínka je v podstatě věc, která podmiňuje
něco jiného, tudíž je na něčem jiném závislá. Bez toho
něčeho, co podmínka podmiňuje, by byla podmínka zbytečná.
Jednoduše řečeno se nestane daná věc, dokud se nenaplní určitá
podmínka nebo naopak se bude jistá věc dít, dokud se nenaplní
podmínka pro její skončení. Co se ale editace v OFP týče, tak tady
bychom našli opravdu velmi mnoho podmínek a v podstatě by se dalo
říct, že celá hra je na podmínkách založená, protože dokud
nesplníte úkol (což je také podmínka), tak se např. neukončí
mise. Teď bych mohl do nekonečna pokračovat ve výčtu podmínek. Jak
jsem ale psal na začátku, tak dotaz, který byl vznešen se týká
nějaké určité podmínky. Já bych to převedl na kamerové
podmínky, kde se to dá alespoň trochu ukázat. V této souvislosti
mě napadá asi ta nejjednodušší podmínka, kterou je podmínka
časová, vytvoříme si kameru, která bude z pozice objekt1 sledovat
objekt2:
_CameraPos = getpos objekt1
_cmx = (_CameraPos select 0)
_cmy = (_CameraPos select 1)
_cmz = (_CameraPos select 2) + 1
_cam = "camera" CamCreate [_cmx,_cmy,_cmz]
_cam CameraEffect ["Internal","back"]
_cam CamCommit 0
_cam CamSetTarget objekt2
_cam CamSetFov 0.5
_cam CamCommit 0
@camCommitted _cam
~4
To celé bude probíhat po dobu 4 sec. Což je právě podmínka úplně na konci v posledním řádku. (~4)
Budeme pokračovat dál, kdy kamera sleduje vozidlo (pojmenované
vozidlo, z pozice hacko1) a chcete, aby ho sledovala tak dlouho, dokud
ho neopustí (v tomto případě) vojak. Když hned pod to přidáte
podmínku časovou (~3), tak tam kamera vydrží ještě další tři
vteřiny. Hned máte jistotu, že se kamera nepředběhne a že tam
vydrží opravdu do doby, než se nenaplní podmínka opuštění
vozidla a následně ještě pak 3 sec. jak je vidět tady:
_CameraPos = GetPos hacko1
_cmx = (_CameraPos select 0) - 50
_cmy = (_CameraPos select 1) + 30
_cmz = (_CameraPos select 2) + 1.7
_cam CamSetPos [_cmx,_cmy,_cmz]
_cam CamSetTarget boing1
_cam CamSetFov 0.4
_cam CamCommit 0
@camCommitted _cam
@not (vojak in vozidlo)
Můžete zadat do posledního řádku kamery např.:
@neco
kde neco je proměnná, která dokud nenabude hodnoty true,
nebude vytvořena podmínka pro pokračování. Jakým způsobem, jestli
do spínače nebo scriptu nebo kamkoli jinam hodnotu něco=true zadáte
záleží už jen na Vás. Důležité ale je někde na začátku zadat
hodnotu neco na false. (neco=false) Nejlépe do "init.sqs".
Jestliže napíšete do posledního řádku tuto podmínku:
@not alive vojak
Kamera bude sledovat zadaný objekt do doby, dokud bude žít
vojak. (not alive vojak) Dalším jednoduchým příkladem je podmínka,
kdy bude kamera sledovat jednotku dem1 z pozice objekt do doby, než
splní nějaký dříve zadaný příkaz. Přímo tady jsem zadal
jednotce dem1 příkaz k položení nálože (dem1 fire ["put",
"pipebomb"] ), až to dokončí (@unitready dem1) pokračuje dalším
příkazem a to přesunem k nějakému objektu v editoru podle čísla
ID. (dem1 move [GetPOs object 137398 select 0, GetPOs object 137398
select 1]) Poté tam kamera vydrží ještě další dvě vteřiny, (~2)
než bude pokračovat.
_CameraPos = GetPos objekt
_cmx = (_CameraPos select 0) + 5
_cmy = (_CameraPos select 1) - 5
_cmz = (_CameraPos select 2) + 1
_cam CamSetPos [_cmx,_cmy,_cmz]
_cam CamSetTarget dem1
_cam CamSetFov 0.7
_cam CamCommit 0
@camCommitted _cam
dem1 fire ["put", "pipebomb"]
@unitready dem1
dem1 move [GetPOs object 137398 select 0, GetPOs object 137398 select 1]
~2
Dalším příkladem je ukončení kamery zachycené za vozidlo:
#let
_CameraPos = getpos ah
_cmx = (_CameraPos select 0) +2
_cmy = (_CameraPos select 1) - 5
_cmz = (_CameraPos select 2) + 1.7
_cam = "camera" CamCreate [_cmx,_cmy,_cmz]
_cam CameraEffect ["Internal","back"]
_cam CamSetTarget ah
_cam CamSetFov 0.7
_cam CamCommit 0
~0.01
? NOT (zrus) : goto "let"
Kamera bude sledovat vozidlo ah do doby, než se proměnná
zrus nenaplní na true. Nesmíme opět zapomenout někde na začátku
skriptu zanést: zrus=false! (init.sqs)
Na další ukázky podmínek použiji jednu starší Ruprtovu
ukázkovou misi, na které je to zcela zřejmé. Máme tu tři vozidla:
hummer, motorku a letadlo. Kamera začíná zavěšená za hummrem (v1) a
to takto:
_CameraPos = getpos v1
_cmx = _CameraPos select 0
_cmy = _CameraPos select 1
_cmz = _CameraPos select 2
_cam = "camera" CamCreate [_cmx - 20,_cmy - 200, 1.5]
_cam CameraEffect ["Internal","Front"]
_cam CamSetTarget v1
_cam CamSetFov 0.5
_cam CamCommit 0
@CamCommitted _cam
#Jizda1
_cam CamSetRelPos [0, -10, 1.5]
_cam CamCommit 0
~0.01
? (v1 Distance v2) > 35 : GoTo "Jizda1"
Jak je vidět, tato kamera bude následovat hummer a to do
doby, než se podmínka naplní. Tady ta doba nastane, když se vozidlo
v1 (hummer) přiblíží k vozidlu v2 a to na vzdálenost 35m. Po
naplnění této podmínky bude kamera sledovat vozidlo v2 v našem
případě motorku.
_cam CamSetRelPos [0, 9, 1.5]
_cam CamSetTarget v2
_cam CamCommit 1
@CamCommitted _cam
_mytime = _time
#Jizda2
_cam CamSetRelPos [0, 10, 1.5]
_cam CamCommit 0
~0.01
? _time < (_mytime + 15): GoTo "Jizda2"
Zde se podmínka naplní po uplynutí času 15 sec. Po té následuje pomalé a plynulé přiblížení k letadlu a1:
_cam CamSetTarget a1
_cam CamCommit 4
@CamCommitted _cam
dive = 0
_dy = - 300
_dz = 0 - (GetPos a1 Select 2) + 1.5
#Approach
_cam CamSetRelPos [-20, _dy, _dz]
_cam CamCommit 0
@CamCommitted _cam
~0.01
_dy = _dy + 1
_dz = _dz + 1
? _dz >= 0: _dz = 0
? _dy < -20 : GoTo "Approach"
#Loop1
_cam CamSetRelPos [-20, -20, 0]
_cam CamCommit 0
~0.01
? dive == 0 : GoTo "Loop1"
Tady ukázková mise končí. Tímto jsem chtěl naznačit, že
opravdu záleží na vaší fantazii, kolik podmínek tady vytvoříte.
Je doufám jasné, že se podmínky nevztahují pouze na kamery, už v
samotném spínači je kolonka s názvem podmínka, která je řekl bych
hodně podobná s těmito podmínkami pro kameru. Když si třeba
vytvoříte spínač, který bude mít v kolonce Podmínka:
west1 distance east1<20
a do pole Pří aktivaci zadáte:
[west1, east1] exec "poplach.sqs"
pak se stane to, že v případě, kdy se přiblíží west1 k
east1 na vzdálenost 20m., spustí se skript s názvem poplach. Co
zadáte do tohoto skriptu, už záleží na vás. Může to být třeba
pouhý text, ale s trochou důvtipu přidají podmínky tohoto typu na
kvalitě celé mise. Pozor ale na to, aby se vám jednotlivé podmínky
neprolínaly a především na to, aby nebyla nějaká podmínka
závislá na dokončení celé mise!!! Naopak, jestliže je dokončení
mise závislé na životě nějaké jiné osoby, zadáte do pole
Podmínka ve spínači:
not alive vip
a do pole Typ zadáte Prohra. Tady se stane to, že v
případě ztráty vip se mise ukončí prohrou. Pak už stačí
vytvořit scutscénu Outro - prohra.
Tohle je o podmínkách odemě vše. Teď tu mám ještě doplněk Ruprta o strukturovaných podmínkách, které jsou od verze 1.75.
Strukturovaná podmínka
S verzí hry 1.75 a vyšší nám BIStudio dalo do rukou nový nástroj na vytváření podmínek a to strukturovanou funkci If… Then …Else a While … Do.
Každý skriptovací příkaz nebo funkce v souborech skriptů
*.SQS (v to počítaje i podmínky) je vykonán pouze v případě, že
příkaz včetně jeho parametrů a argumentů je umístěn na jednom
řádku, případně může být uvedeno na jednom řádku více
příkazů, musí však být odděleny středníkem. Nelze tedy vykonat
jeden příkaz zapsaný v jednom řádku s parametrem uvedeným v jiném
řádku. Tento způsob programového zpracování příkazů se
nazývá "řádkově založený skript" (Line Based Skript). Tento
způsob však do značné míry omezuje programovací možnosti daného
jazyka.
Oproti tomu výše uvedené strukturované funkce If… Then … Else a While… Do
mohou být vykonány i když jsou zapsány na neomezeném počtu
řádků. Toto se nazývá "víceřádkově založený script"
(Multiline Based Skript) V tomto případě však je nutné funkce
umístit do souboru s příponou SQF nikoli SQS. Zároveň berte na
vědomí, že ne všechny výrazy skriptovacího jazyka hry OFP mohou
být ve skriptech funkcí vykonány, např. nelze v nich použít
prodlevu (~číslo nebo &číslo), neboť funkce je vždy vykonána
jako celek, nikoli jako soubor několika příkazů.
Tyto funkce pak mají poněkud odlišnou syntaxi :
If (podmínka) Then {výraz1} Else {výraz2}
| podmínka ->| | tělo funkce -------------->|
Přeloženo do češtiny to znamená:
Pokud (podmínka) vrátí TRUE pak(THEN) udělej {výraz1}, jinak (ELSE)
udělej {výraz2}. Výrazy 1 i 2 musí být uzavřeny v kudrnatých
závorkách (správně) nebo v uvozovkách (nedoporučuji).
While "podmínka" Do {výraz}
| podmínka ------>| | tělo funkce->|
Přeloženo do češtiny to znamená :
Pokud "podmínka" vrací TRUE vykonávej pořád dokola {výraz}.
Maximální počet opakování je stanoven na 10.000. Pokud se smyčka
zopakuje 10.000x a podmínka stále vrací TRUE, smyčka se ukončí a
je zobrazena chybová zpráva.
Příklad #1 - Funkce If … Then…Else umístěná v souboru *.SQS.
Pokud je tato podmínková funkce umístěná v souboru .SQS chová se naprosto identicky jako dosud známé ? výraz : výraz .
_query = 5
_zk = 0
_zk1 = 5
_zk2 = 10
If (_query = = 5) Then {_zk = _zk1 + _zk2} Else {_zk = _zk2 - _zk1}
Výsledkem je že : _zk = 15
Naprosto stejného výsledku však dosáhnete i použitím starého dobrého :
? _query = = 5: _zk = _zk1 + _zk2; Goto "Skip"
_zk = _zk2 - _zk1
#Skip
Příklad #2 - Funkce If … Then…Else umístěná v souboru *.SQF.
Soubor funkcí *.SQF nelze spouštět pomocí příkazu Exec.
Pro vykonání kódu zapsaného do souboru *.SQF je nutno použít též
nově implemtované příkazy PreprocessFile nebo LoadFile, který na
své místo v souboru *.SQS dosadí obsah volaného souboru *.SQF, anebo
příkaz Call v kombinaci s PreprocessFile nebo LoadFile, který rovnou
kód v souboru *.SQF vykoná.
Kód souboru *.SQS
_query = 5
_zk = 0
_zk1 = 5
_zk2 = 10
[] Call PreprocessFile "zkouska.sqf"
Kód souboru ZKOUSKA.SQF
If (_query = = 5) Then
{
_zk = zk1 + zk2
}
Else
{
_zk = _zk2 - _zk1
}
Výsledkem je že : _zk = 15
Protože v souborech funkcí *.SQF nemá konec řádku žádný
speciální význam, musíte, pokud bude výraz obsahovat více
příkazů, každý řádek výrazu ukončit středníkem, např. takto :
If (_query = = 5) Then
{
_zk = zk1 + zk2;
Player SetDamage 0
}
Else
{
_zk = _zk2 - _zk1
}
Výsledkem je že : _zk = 15 a hráč bude mít hodnotu poškození 0.
Vše co je zpracováno v souboru *.SQF je zpracováno jako
řetězec. Nelze proto použít příkaz PreprocessFile nebo LoadFile
jako samostatný příkaz v souboru scriptu, ale pouze jako část
(výraz) funkce If … Then … Else nebo While … Do, nebo jako tělo
příkazu Call. Naopak vše co je uvedeno v souboru *.SQF lze
použít jako řetězcový parametr nebo argument jakékoli skriptovací
funkce nebo příkazu, který takový argument podporuje. Jinými
slovy, pokud by jste ve svém souboru skriptu uvedli např. :
TitleText [PreprocessFile "zkouska.sqf", "PLAIN"]
Pak se vám podle předchozího příkazu vypíše na obrazovku :
If (_query = = 5) Then{ _zk = zk1 + zk2}Else{ _zk = _zk2 - _zk1}
Příklad #3 - Funkce While… Do umístěná do souboru *.SQF.
Tento příklad doplní do hráčovi skupiny tolik vojáků, aby jich celkem celá skupina obsahovala 10.
Kód souboru *.SQS :
[] Call PreprocessFile "zkouska1.sqf"
Kód souboru ZKOUSKA1.SQF :
While "(Count Units Group Player) < 10" Do
{
"SoldierWB" CreateUnit
[
[
(Position Player Select 0) + Random 5,
(Position Player Select 1) + Random 5,
Position Player Select 2
],
Group Player
]
}
Tolik tedy od Ruprta.
Jeslti pochopíte tohle, tak si myslím, že už není potřeba
pokračovat a mě už stačí vám jen popřát hodně trpělivosti. Na
závěr snad ještě poslední podmínku:
Abyste pochopili co tady píšu, musíte si to celé přečíst a zřejmě to nebude stačit jednou.
(věta účelová, ne podmínková)
Didymos
|