Panel Logowania

Pierwszy skrypt

napisał : Michalek
10
lutego
2013
Znając podstawy pythona zabierzmy się za napisanie naszego pierwszego skryptu!
tagi : przewodnik python skrypt tutorial programowanie kod jak napisać

Na początek kilka przydatnych linków, które pozwolą nam rozwijać umiejętność posługiwania się pyhton'em:

http://www.blender.org/documentation/blender_python_api_2_63_17/
http://pl.wikibooks.org/wiki/Zanurkuj_w_Pythonie
http://pl.python.org/kursy,jezyka.html

Jeżeli jakiś termin związany z Blender Game Engine wyda wam się niejasny to odsyłam was do tego przewodnika: http://troman.pl/przewodnik/wprowadzenie-do-blender-game-engine_ID1 . Tutaj znajdziecie wszystkie zagadnienia związane z BGE.

Zanim zaczniemy pisać przygotujmy nasze stanowisko pracy. Uruchamiamy blendera. 

Z menu kontekstowego które znajduje się w górnej części ekranu wybieramy standardowo zdefiniowany układ okien pomocny przy pisaniu skryptów - "Scripting". 

Następna czynność to włączenie konsoli. Będzie ona nas informowała o ewentualnych błędach w kodzie.

Warto też zmienić widok konsoli w dolnym oknie na "Logic Editor". Przyda nam się to w późniejszym czasie. Klikamy na przycisk "New" - zaczynamy pisanie naszego pierwszego skryptu.

Aby napisać jakikolwiek skrypt ingerujący w nasz silnik gry musimy zaimportować odpowiednie moduły. Pierwszy który nas interesuje to "logic", pozwoli on nam na przypisanie kontrolera uruchamiającego skrypt, do zdeklarowanej przez nas zmiennej. Dzięki temu zdeklarujemy też zmienną do której przypiszemy obiekt używający skryptu. Drugi moduł to "events" - dzięki niemu będziemy mogli wyodrębniać przyciski klawiatury i używać ich w skrypcie. Aby nie pogubić się w kodzie możemy pisać komentarze (jak to robić opisane jest w artykule "Python - język programowania") .

Kod - podstawa:

# z silnika gry importujemy modul logic, events
from bge import logic, events

"""zmiennej cont (mozemy nazwac ja jak chcemy)
przypisujemy kontroler(sensor)"""
cont = logic.getCurrentController()

#zmiennej own przypisujemy wlasciciela skryptu (obiekt na ktorym bedzie wykonywany kod)
own = cont.owner

Teraz przedstawię i opiszę kilka poleceń dzięki którym będziemy mogli między innymi dostać się za pomocą kodu do sensora lub aktuatora podłączonego do skryptu, przemieścić czy obrócić obiekt.

Klawiatura i mysz

Na początek zajmiemy się klawiaturą. Najpierw importujemy moduł "events" (zarówno jest on dla myszy jak i klawiatury). Następnie tworzymy zmienną w której przechowamy naszą klawiaturę. Tworzymy także zmienną (w tym wypadku listę) która będzie przechowywała cztery możliwe statusy przycisków klawiatury i myszki. Pozwoli nam to określić czy dany kod ma zostać wykonany gdy przycisk został właśnie wciśnięty, odciśnięty, przytrzymany czy nieaktywny. Aby dostać się do odpowiedniego przycisku używamy takiego kodu: nazwa_zmiennej.events[events.konkretny_klawiszKEY]. "Nazwa zmiennej" to nazwa zmiennej przechowującej naszą klawiaturę. "Konkretny klawisz" to odpowiedni klawisz na klawiaturze. Nazwy wszystkich przycisków klawiatury i myszki znajdują się pod tym linkiem: http://www.blender.org/documentation/blender_python_api_2_63_17/bge.events.html. W przypadku myszy jest prawie tak samo. Różnica polega na tym że do nowej zmiennej przypisujemy mysz. A odwołując się do przycisku używamy kodu: nazwa_zmiennej.events[events.konkretny_przyciskMOUSE]. Przykład kodu (bez podstawy): 

#dowolna nazwa zmiennej
klawiatura = logic.keyboard 
mysz = logic.mouse #lista statusow status = (logic.KX_SENSOR_INACTIVE, logic.KX_INPUT_ACTIVE, logic.KX_INPUT_JUST_RELEASED, logic.KX_INPUT_JUST_ACTIVATED) #przyklad wykorzystania klawiatury w instrukcji warunkowej if klawiatura.events[events.SPACEKEY] == status[1]: print ("spacja przytrzymana - warunek spelniony")

#przyklad wykorzystania myszki
if mysz.events[events.LEFTMOUSE] == status[1]:
print ("lewy klawisz myszy przytrzymany")

Sensory

Teraz dowiemy się jak dostać się do sensora podłączonego (w kostkach logiki) do naszego skryptu. Oczywiście gdy piszemy jakikolwiek skrypt musimy zacząć od naszego kodu podstawowego. W dalszej części tutoriala nie będę o tym wspominał. Zaczynamy. Najpierw deklarujemy zmienną która będzie przechowywała nasz sensor. Nazwa zmiennej może być dowolna jednak dobrze jest nazywać zmienne odpowiednio do zawartości. Sensor zapisujemy pod zmienną w taki sposób: nazwa zmiennej = own.sensors['nazwa sensora']. Dzięki takiemu rozwiązaniu możemy np. rozpoznać obiekt który wywołał dany sensor (np. dla sensora touch - obiekt którego dotknie) lub określić status sensora (zależnie od sensora jest to liczba od 0 do 3) dzięki czemu po np. dotknięciu jakiegoś obiektu wykona się dany kod. Ja użyję sensora "Ray":

sensorray = own.sensors['Ray']
#rozpoznanie obiektu na ktory "natrafil" ray i wydrukowanie jego nazwy
print (sensorray.hitObject)

#wyswietlenie pozycji "trafienia" w globalnym ukladzie wspolrzednych
print (ray.hitPosition)

 Do skryptu dołączony jest także sensor "Always" ponieważ gdyby go nie było, skrypt zostałby wykonany tylko wtedy gdy zadziałałby sensor "Ray". Gdy dołączymy sensor "Always" to skrypt zostanie wykonany bez względu na to czy zostanie wywołany sensor "Ray". W konsoli został wyświetlony obiekt na który trafił ray (ja nazwałem go "cel") oraz współrzędne punktu zetknięcia "promienia" sensora ray ze ścianą sześcianu ("celu"). Pierwsza liczba współrzędnych to pozycja na osi x, druga y i z. Y wynosi -1 ponieważ to środek sześcianu znajduje się w środku globalnego układu współrzędnych a nie jego ściana. Nie zdołam wszystkiego opisać, dlatego aby wiedzieć więcej musicie sięgać do dokumentacji API pythona (pierwszy link na górze).

 

Aktuatory 

Odwołanie się do aktuatora jest bardzo podobne jak w przypadku sensora. Różnica polega na tym że aby aktuator zadziałał należy go wywołać. Definiujemy zmienną (dowolna nazwa zmiennej) która przechowa nasz aktuator. Do aktuatora dostajemy się za pomocą kodu: nazwa_zmiennej = own.actuators['nazwa_aktuatora']. Przykład wykorzystania aktuatora "Motion" do obracania obiektu po naciśnięciu spacji:

aktuator = own.actuators['Motion']
if klawiatura.events[events.SPACEKEY] == status[1]:
#aktywowanie aktuatora
    cont.activate(aktuator)

 

Ruch i obrót 

Przyszła pora aby poruszyć naszym obiektem tylko i wyłącznie za pomocą skryptu. Obiekt możemy poruszać zmieniając jego położenie po globalnych lub lokalnych osiach x, y, z o pewną wartość lub za pomocą "pchnięcia" go po danej osi z pewną siłą. Zaczniemy od pierwszej metody:

if klawiatura.events[events.UPARROWKEY] == status[1]:
    own.applyMovement((0,0,0.1),True)

Gdy przytrzymamy strzałkę do góry to obiekt do którego należy skrypt zmieni swoje położenie względem osi z. Słowo "own" to właściciel skryptu (patrz wyżej kod - podstawa), dalej applyMovement - zatwierdzenie ruchu. Nawias z cyframi określa po jakich osiach i o jaką wartość ma zostać przesunięty obiekt. Pierwsza liczba to przesunięcie po osi x, dalej po przecinku to przesunięcie po osi y, ostatnia liczba to ruch po osi z. Główny nawias zawiera informację o tym czy obiekt ma zostać przesunięty po osiach globalnych czy lokalnych. Słowo "True" oznaczające prawdę zastrzega ruch po osiach globalnych. Słowo "False" fałsz - po osich lokalnych. Ruch za pomocą "siły pchnięcia": 

if klawiatura.events[events.LEFTARROWKEY] == status[1]:
    own.applyForce((0,5,0),True)

Trzymając strzałkę w lewo sprawiamy że nasz obiekt zostaje "pchany" po osi y z siłą równą 5. Aby ten kod zadziałał nasz obiekt musi być obiektem dynamicznym czyli posiadać fizykę np. RigidBody. Na poruszanie obiektem tą metodą wpływ ma wiele czynników. Im większa masa obiektu, jego współczynnik tarcia tym większa siła potrzebna do jego przemieszczenia.

Wiemy już jak poruszyć obiekt. Przydałoby się teraz go obrócić. Obracać obiekt - tak jak w przypadku poruszania nim - możemy na dwa sposoby: obracając go wokół danej osi o pewną wartość lub nadając mu określony moment obrotowy. W drugim wypadku obiekt musi posiadać np. fizykę "Rigid Body" - musi móc się obracać. Metoda ta daje nam efekt "rozpędzania" obiektu o daną wartość (moment obrotowy).  Oto przykład pierwszej metody:

if klawiatura.events[events.LEFTARROWKEY] == status[1]:
    own.applyRotation((0,0,0.1),True)

Po naciśnięciu strzałki w lewo, obiekt obróci się wokół globalnej osi z w lewo o wartość 0,1 (wartość 1 to około 45 stopni). A oto kod obracający obiektem za pomocą "momentu obrotowego":

if klawiatura.events[events.LEFTARROWKEY] == status[1]:
    own.applyTorque((0,0,100),True)

Na obrót obiektem tą metodą - tak jak w wypadku poruszania nim za pomocą "siły pchnięcia" - wpływ mają jego właściwości.

 

Istota sensora "Always"

Wspominałem już wcześniej że aby skrypt został wykonany bez względu na to czy przyłączony do niego sensor zostanie wywołany należy jeszcze do skryptu "doczepić" sensor always. Ale to nie wszystko. Always po uruchomieniu silnika gry wysyła jeden pozytywny impuls. Z racji tego że to jest sensor "always"(ang. zawsze) wysyła go każdorazowo zaraz po uruchomieniu BGE. Dlatego np. gdy w skrypcie napisaliśmy że obiekt ma się obrócić po naciśnięciu spacji (if klawiatura.events[events.SPACEKEY]) a nie naciśniemy tej spacji zaraz po uruchomieniu silnika gry (mamy na to ułamek sekundy :) ) to zostanie z sensora wygenerowany impuls nie zawierający informacji o wciśniętym klawiszu. Późniejsze naciskanie spacji nic nie zdziała ponieważ sensor wysyła impuls tylko raz.

Każdy sensor posiada opcje sterujące impulsem: 1-"True Level Triggering" i 2-"False Level Triggering".

 Po wciśnięciu pierwszego przycisku sensor będzie wysyłał pozytywne impulsy z częstotliwością 60/s tylko wtedy gdy zostanie wywołany. Dla sensora "always" wywoływanie nie ma znaczenia ponieważ wywoływany jest zawsze. Jednak np. sensor "Touch" wysyłałby impulsy tylko wtedy gdyby został wywołany czyli gdy obiekt do niego podłączony dotknąłby odpowiedniego innego obiektu (opis sensorów znajduje się w przewodniku - link na górze). Drugi przycisk sprawi że sensor będzie wysyłał pozytywny impuls także z częstotliwością 60/s wtedy gdy nie zostanie on wywołany. Czyli np. dodam sobie sensor "Keyboard" z klawiszem "spacja" i ten sensor będzie wysyłał pozytywny impuls tak długo aż nie wcisnę spacji. W polu oznaczonym kolorem żółtym wpisujemy opóźnienie z jakim ma zastać wysłany kolejny impuls. Podajemy je w mili sekundach.

Wciskając przycisk "True Level Triggering" w sensorze "always" sprawimy że impuls wysyłany jest co chwile. W takim wypadku gdy wciśniemy spację później - niż zaraz po uruchomieniu BGE - kolejne impulsy zawierały będą informację o wciśniętym klawiszu. Podsumowując: jeśli chcemy aby nasz skrypt wykonywał się nieprzerwanie po uruchomieniu silnika gry należy do skryptu podłączyć sensor "always" i zaznaczyć na nim przycisk "True Level Triggering".

Property obiektu

Pewnie nie raz zetknęliście się z właściwościami (properties) obiektu łącząc kostki logiki w swoich grach. Używaliście ich np. do naliczania punktów w grze. Są to swego rodzaju zmienne których możemy użyć w skrypcie. Zwykłe zmienne mogą zmieniać się w taki sposób że do ich poprzedniej wartości zostanie dodana kolejna (np. a += 1 ) tylko w instrukcji iteracyjnej (pętli). Gdy zechcemy aby taka zmienna zmieniała się dzięki sensorowi "Always"  - czyli 60 razy na sekundę miała by do swej wartości dopisać "siebie" plus jeden - to kod nie zostanie wykonany, w konsoli wyświetlony zostanie błąd. Na szczęście "property" to potrafi. Tę cechę możemy wykorzystać np. do zrobienia systemu strzelania z łuku. Gdy będziemy trzymali lewy przycisk myszy to do property dodawana będzie liczba np. 2, property będzie zwiększało się, my wybieramy moment i puszczamy przycisk - zerujemy property. Strzała zostanie wystrzelona z siłą równą wartości property. Im dłużej trzymamy przycisk tym większa wartość - większa siła wystrzału. Property deklarujemy w kodzie w taki sposób: own['nazwa'] = 5- own to właściciel obiektu (kod podstawa), nazwa to nazwa property (obok kostek logiki). Przykład:

from bge import logic , events
cont = logic.getCurrentController()
own = cont.owner
mysz = logic.mouse
status = (logic.KX_SENSOR_INACTIVE, logic.KX_INPUT_ACTIVE, logic.KX_INPUT_JUST_RELEASED, logic.KX_INPUT_JUST_ACTIVATED)

#aktuator dodajacy strzale z drugiej warstwy
ak = own.actuators['add']
#predkosc liniowa dodanego obiektu, w nawiasie nasze zmieniajace sie property
ak.linearVelocity = [own['a'],0,0]

#100 to granica wartosci property a drugie property to czas do kolejnego wystrzalu
if mysz.events[events.LEFTMOUSE] == status[1] and own['a'] < 100 and own['time']>1.2:
    own['a'] += 2

#po puszczeniu klawisza strzala pojawia sie i otrzymuje predkosc rowna property "a" if mysz.events[events.LEFTMOUSE] == status[2] and own['time'] > 1.3: cont.activate(ak) own['time'] = 0 #przycisk myszki jest nieaktywny, sila wystrzalu jest zerowa if mysz.events[events.LEFTMOUSE] == status[0] and own['a'] > 0: own['a'] = 0

Ten skrypt nie wystarczy do stworzenia kompletnego systemu strzelania z łuku. Należy jeszcze napisać skrypt dzięki któremu strzała po natrafieniu na jakiś obiekt wbija się w niego (staje się jego "dzieckiem" oraz przesuwa się odrobinę po lokalnej osi do przodu aby wyglądała jakby się odrobinę wbiła). 

 

Scena i obiekty na scenie 

Pokażę teraz jak dostać się do obiektów na scenie, wyświetlić je w konsoli czy usunąć. Na początek musimy dostać się do naszej sceny. W tym celu tworzymy zmienną (dowolna nazwa) i przypisujemy do niej aktywną scenę czyli tą na której się znajdujemy. Kod wygląda następująco nazwa_zmiennej = logic.getCurrentScene(). Teraz gdy już mamy naszą scenę możemy manipulować obiektami znajdującymi się na niej. Jednak najpierw wyświetlmy je wszystkie w konsoli: print (nazwa_zmiennej.objects). Widzimy teraz jakie obiekty znajdują się na scenie, widzimy ich nazwy. Przykład:

#deklaracja zmiennej kryjacej scene
scena = logic.getCurrentScene()
#jest to lista (nie zmienna) zawierająca wszystkie obiekty na scenie wszystkie_obiekty = scena.objects
#wyswietlone zostana wszystkie obiekty print (wszystkie_obiekty)
#jako ze to jest lista zostanie wyswietlony jej drugi element (numeracja od 0 ) print (wszystkie_obiekty[1])

#do obiektu mozna sie odwolac takze po jego nazwie
obiekt = wszystkie_obiekty["Cube"]

#teraz możemy np. obrocic nasz obiekt, przesunac, nawet usunac
obiekt.applyRotation((0,0,0.1),True)
obiekt.applyMovement((1,0,0),True)
obiekt.endObject()

Takie rozwiązanie sprawia że aby sterować obiektem za pomocą skryptu ten obiekt nie musi wcale być "połączony" ze skryptem.

Przedstawiłem w jaki sposób zabrać się za pisanie skryptów, co zrobić aby móc używać klawiszy w kodzie oraz kilka podstawowych czynności wykonywanych z poziomu skryptu. Są to tylko podstawy. Jeśli naprawdę chcecie dobrze znać ten język programowania, pisać skrypty na wysokim poziomie, musicie spędzić wiele godzin na czytaniu dokumentacji pythona oraz API blendera.

Brak komentarzy
Dodaj komentarz
Aby dodać komentarz do newsa, musisz być zalogowany w Serwisie.. Zaloguj