dokumenta cj a

16
Wrocław, 16 czerwca 2011 Jakub Jędryszek, 171055 Mateusz Korżel , 171133 Wiktor Ławski , 171062 Bartłomiej Piekarski 171160 Kamil Pokładowski 170993 Michał Skuza 171172 RubiQ Cube 2011 Projekt z przedmiotu „Projekt Zespołowy” Rok akademicki 2010/2011, kierunek: INF, specjalność: INS. PROWADZĄCY: Dr inż. Andrzej Kozik Spis treści 1. Założenia projektowe ......................................................................................................2 2. Cele projektu ...................................................................................................................2 3. Szczegóły implementacyjne.............................................................................................3 4. Zasady gry..................................................................................................................... 12 5. Elementy dodatkowe ..................................................................................................... 13 6. Interfejs użytkownika .................................................................................................... 14 Bibliografia .......................................................................................................................... 15

Upload: jakubjed

Post on 08-Aug-2015

31 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Dokumenta Cj A

Wrocław, 16 czerwca 2011

Jakub Jędryszek, 171055

Mateusz Korżel, 171133

Wiktor Ławski, 171062

Bartłomiej Piekarski 171160

Kamil Pokładowski 170993

Michał Skuza 171172

RubiQ Cube 2011

Projekt z przedmiotu „Projekt Zespołowy”

Rok akademicki 2010/2011, kierunek: INF, specjalność: INS.

PROWADZĄCY:

Dr inż. Andrzej Kozik

Spis treści

1. Założenia projektowe ......................................................................................................2

2. Cele projektu ...................................................................................................................2

3. Szczegóły implementacyjne.............................................................................................3

4. Zasady gry..................................................................................................................... 12

5. Elementy dodatkowe ..................................................................................................... 13

6. Interfejs użytkownika .................................................................................................... 14

Bibliografia .......................................................................................................................... 15

Page 2: Dokumenta Cj A

2

1. Założenia projektowe

Projekt miał na celu stworzenie symulacji gry, w której gracz układa kostkę Rubika.

Zakładano stworzenie dwóch wersji gry:

gracz steruje za pomocą myszy i klawiatury,

gracz steruje za pomocą urządzenia Kinect.

Ponadto gra miała przechowywać najlepsze wyniki graczy, które będą pamiętane

lokalnie (w pliku XML) oraz globalnie – w centralnej bazie danych, gdzie będą wyniki

różnych graczy. Każdy z graczy powinien mieć możliwość utworzenia własnego profilu – na

jednym komputerze można grać na różnych profilach.

Prace nad projektem zostały podzielone na 3 moduły:

interfejs (GUI) i baza danych użytkowników wraz ze stroną WWW projektu

(Jakub Jędryszek i Mateusz Korżel),

obsługa Kinecta (Wiktor Ławski i Bartłomiej Piekarski),

przygotowanie funkcjonalnego modelu kostki Rubika (Kamil Pokładowski

i Michał Skuza).

2. Cele projektu

Celami projektu były m.in.:

nabycie praktycznych umiejętności programowania z wykorzystaniem

Windows Presentation Foundation (WPF),

zapoznanie się z językiem opisu interfejsu użytkownika XAML (eXtensible

Application Markup Language),

opanowanie komunikacji z bazą danych, z poziomu aplikacji bazującej na

.NET Framework 4.0,

zapoznanie się z urządzeniem Kinect oraz bibliotekami do komunikacji z nim,

poznanie sposobów modelowania grafiki 3D z wykorzystaniem WPF,

Page 3: Dokumenta Cj A

3

udoskonalenie umiejętności pracy w grupie i zaznajomienie z narzędziami ją

wpierającymi.

3. Szczegóły implementacyjne

3.1 Graficzny model kostki

Do uzyskania graficznej prezentacji kostki Rubika posłużono się silnikiem graficznym

WPF, bazującym na .NET 3 i wchodzącym w skład WinFX. WPF daje możliwość integracji

m.in. interfejsu użytkownika, dokumentów, grafiki zarówno 2D jaki i 3D, multimediów itd.

Na potrzeby niniejszego projektu wykorzystano interfejs użytkownika, a także elementy

grafiki trójwymiarowej. Ponadto interfejs programowania aplikacji WPF bazuje na języku

XML, a dokładniej na jego zoptymalizowanej części XAML, służącej do opisu bogatych

wizualnych interfejsów, a tym samym pozwala na odseparowanie warstwy prezentacji i logiki

biznesowej. Graficzna część GUI wykorzystuje grafikę wektorową budowaną z użyciem

akceleratorów grafiki 3D i efektów graficznych udostępnianych przez WGF (Windows

Graphics Foundation).

Model kostki został stworzony przy użyciu 27 modeli sześcianów, gdzie każdy z nich

znajduje się w 3 różnych (określonych) płaszczyznach przestrzeni, które wyznaczają ściany

obracanej kostki. W celu uzyskania w/w efektu stworzono dwie klasy:

Cube – klasa odzwierciedlająca sześcian w przestrzeni, tzn. jego graficzną

prezentację, a w szczególności jego umiejscowienie w układzie odniesienia,

rozmiar, kolory ścian;

RubikCube – klasa zawierająca tablicę 27 obiektów klasy Cube,

reprezentujących całą kostkę oraz metody służące m.in. do obrotów całej

kostki lub wybranych ścian.

3.1.1 Klasa Cube

Klasa Cube służy do graficznego przedstawienia sześcianu w układzie współrzędnych

XYZ. Podstawą do jego stworzenia było możliwość rysowania siatki, która reprezentuje

powierzchnię umiejscowioną w przestrzeni trójwymiarowej. W szczególności taką

powierzchnię można jednoznacznie zdefiniować przy użyciu współrzędnych 3 punktów, co

oznacza, że w/w siatka może być złożona z trójkątów. Dla dużych i złożonych powierzchni

Page 4: Dokumenta Cj A

4

odpowiednia ilość takich trójkątów stanowi dobre przybliżenie szukanych kształtów.

Prawidłowa reprezentacja siatki w przestrzeni składa się z :

wierzchołków trójkątów, składających się na siatkę;

wektorów normalnych do zdefiniowanych trójkątów, które stanowią iloczyny

wektorowe (rys. 1), które wykorzystywane są m.in. do prawidłowego

oświetlenia trójkąta

Rysunek 1 Iloczyn wektorowy dla jednego trójkąta siatki

określenia barwy światła rozproszenia dla powierzchni oświetlanej

Model sześcianu składa się z 12 trójkątów opisujących jego powierzchnię (po dwa na

każdą ścianę), dla których osobno obliczane są wektory normalne (przy użyciu iloczynu

wektorowego).

Konstruktor klasy Cube przyjmuje w argumentach pozycję jednego punktu sześcianu

– wierzchołek nr 1 (rys. 2), rozmiar boku oraz 6 kolorów określających ściany bryły:

public szescian(Point3D position, double rozmiar, Color c_front, Color c_back, Color c_left, Color c_right, Color c_down, Color c_up)

Page 5: Dokumenta Cj A

5

Rysunek 2 Graficzne reprezentacja sześcianu w przestrzeni

Do najważniejszych metod tej klasy należą:

public void transformByMatrix(Matrix3D matrix) – metoda odpowiedzialna za

transformację wszystkich punktów sześcianu (8 wierzchołków) w przestrzeni przez

macierz podawaną w argumencie. Jest ona niezbędna przy takich transformacjach jak

obroty całej kostki lub wybranych ścian oraz przesunięcia o wektor;

public Color GetWallColor(int wallNumber) – metoda zwracająca kolor ściany

sześcianu podany w argumencie. Wykorzystanie tej funkcji jest konieczne przy

sprawdzaniu czy model kostki Rubika jest rozwiązany, tzn. czy kolory na każdej

powierzchni całej kostki są jednakowe;

public Model3DGroup konstruuj_szescian() – wymaga się użycia tej metody po

każdej transformacji wykonanej na punktach sześcianów w celu uzyskania modelu

sześcianu dla nowo wyznaczonych współrzędnych (tworzenie siatki trójkątów oraz

wektorów normalnych dla niej);

public void correctPoint(int nr, Point3D newPoint) – metoda wykorzystywana do

manualnego wpisania nowych współrzędnych dla punktu określonego w argumencie.

Page 6: Dokumenta Cj A

6

3.1.2 Klasa RubikCube

Dzięki klasie RubikCube jest możliwe przedstawienie kostki Rubika w przestrzeni

trójwymiarowej. W tym celu klasa przechowuje tablicę 27 obiektów klasy Cube, które

odpowiednio umiejscowione w układzie współrzędnych tworzą model całej kostki.

Rysunek 3 Kostka Rubika złożona z 27 sześcianów

Domyślne ustawienia pozycji obserwatora to (60, 50 , 0), co oznacza, że znajduje się

ona nad osią OX, można zmienić przy użyciu metody SetCamera(). Jednak rekomendowane

jest pozostawienie ustawień predefiniowanych. W przypadku ich zmiany, zalecane jest, aby

zmienić również kierunek padania światła na odwrotny do przyjętej pozycji (np. dla pozycji

(10,20,30) odpowiedni kierunek to (-10, -20, -30)). Niespełnienie tej zasady może skutkować

niewłaściwym wyświetlaniem kolorów kostki.

Page 7: Dokumenta Cj A

7

RubikCube wymaga, aby w konstruktorze przekazać referencję do obiektu klasy

ViewPort3D, na którym cała scena będzie rysowana.

Metody klasy RubikCube można podzielić na 4 zasadnicze grupy:

a) Metody generalne

public void przerysujScene() – metoda „czyści” scenę, a następnie wykorzystując

bieżące współrzędne wszystkich obiektów klasy Cube.cs na nowo przerysowuje całą

scenę;

public void SetCamera

public void zmienKierunekSwiatla

b) Metody obrotów całej kostki

public void CubeRotation(int kat, bool horizontal) – metoda odpowiedzialna za obrót

całego modelu kostki. Pierwszy parametr funkcji określa kąt (w stopniach) obrotu,

natomiast drugi określa jeden z dwóch możliwych obrotów: względem osi OY oraz

względem osi OZ;

Rysunek 4 Osie obrotu kostki Rubika

Page 8: Dokumenta Cj A

8

dwie metody prywatne odpowiedzialne za faktyczną zmianę położenia wierzchołków.

Jedna z nich odpowiada za stworzenie macierzy transformacji oraz zastosowanie jej,

druga wykonuje animację obrotu o ten sam kąt, dając efekt płynnej zmiany

położenia.

c) Metody obrotów ścian

public void WallFocus(int SetNumber) – dla uzyskania obrotu wszystkie ściany kostki

Rubika wymagane było zdefiniowanie 9 płaszczyzn obrotu, z których każda jest

odpowiedzialna za obrót 9 bazowych sześcianów stworzono tablice przechowujące

numery określonych obiektów klasy Cube. WallFocus wyróżnia wskazaną

w argumencie ścianę (1-9), gdzie pierwsza trójka oznacza ściany od lewego „czoła”

kostki do tyłu, druga trójka od prawego „czoła”, pozostała odpowiada za poziome

warstwy.

Rysunek 5 Wyróżnienie ścian 1-3

Page 9: Dokumenta Cj A

9

Rysunek 6 Wyróżnienie ścian 4-6

Rysunek 7 Wyróżnienie ścian 7-9

Samo wyróżnienie ściany polega na przesunięciu 8 sześcianów o pewien, określony

wektor względem środka rozpatrywanej ściany. W ten sposób uzyskiwany jest efekt

„rozszerzania się” sześcianów, będących w danej płaszczyźnie.

public void obroc_sciane(int nr_sciany, int kat) oraz public void

obroc_scianeAnimation (int nr_sciany, int kat) – metody odpowiedzialne za

obracanie ściany podanej w argumencie o wskazany kąt. Obie metody powinny być

wywoływane jednocześnie z identycznymi argumentami, ponieważ dokonuje

kalkulacji nowego położenia punktów, natomiast druga odpowiada za samą

animację.

Page 10: Dokumenta Cj A

10

Rysunek 8 Przykłady obrotów wyróżnionych ścian

d) Metody sprawdzające

public bool isSolved() – metoda sprawdzająca, czy kostka jest ułożona

prawidłowo, tzn. wszystkie kolory są na właściwych miejscach. Zwraca wartość

true w przypadku zgodności oraz false, kiedy kostka pozostaje „nieułożona”;

public int ReturnActiveWall() – metoda zwracająca numer aktywnej (wyróżnionej)

ściany;

public void SetAnimationTime(int miliseconds) – ustawia czas animacji

przewidziany na jednorazowy obrót całej kostki, bądź wybranej ściany;

public int repairCube() – kluczowa funkcja, która naprawia błędy zaokrągleń

nakładane przez wielokrotne wywoływanie wszystkich obrotów na kostce.

Rekomendowane jest, aby używać jej przy każdym obrocie kostki. Zwraca wartość

1, gdy dokonano poprawy współrzędnych oraz 0, gdy jej nie dokonano.

Page 11: Dokumenta Cj A

11

3.2 Obsługa kinecta

Do obsługi Kinecta wykorzystana została biblioteka openNI.net. Przygotowany został

także system logowania przy pomocy bibliotek NLog.

Tworząc okno rozgrywki, pierwszym elementem jest pobranie referencji do klasy

odpowiadającej za zapis do logów, przy pomocy statycznej metody

GetCurrentClassLogger().

Aby móc wyświetlać obraz z Kinecta oraz rysować na nim punkty identyfikujące

poszczególne części ciała, należało w pliku XAML użyć znaczników typu Canvas oraz

Image. Tworząc okno rozgrywki tworzony jest obiekt klasy zaprojektowanej specjalnie na

potrzeby tego projektu – GameController. W konstruktorze przekazywana jest do niej

referencja do głównego okna, żeby móc z niej manipulować obiektami typu Canvas oraz

Image. Do obsługi biblioteki openNI jest wymagany obiekt klasy Context, do którego

przekazywana jest nazwa pliku XML z odpowiednimi ustawieniami. Na podstawie

utworzonego obiektu klasy Context można utworzyć DepthGenerator i ImageGenerator. Aby

skorzystać z możliwości tej biblioteki, należało dodatkowo utworzyć obiekty klas

UserGenerator, SkeletonCapability i PoseDetectionCapability. Do rozróżniania

poszczególnych pozycji, wymagane jest jeszcze utworzenie „słownika stawów”. Po

dokonaniu preferowanych ustawień, wywoływana jest metoda StartGenerating() dla obiektu

klasy UserGenerator. Aby uzyskać wrażenie równoległości działań, stworzone zostały

3 wątki, które odpowiadały za przerysowywanie sceny, wybór ścian (poprzez odpowiednie

pozycje) i poruszanie kostką (poprzez analizę ruchu).

Aby móc wykorzystywać w późniejszej analizie dane części ciała, należy je dodać do

„słownika stawów” - metoda GetJoints(). W jej wnętrzu należy wywołać metodę GetJoint()

dla odpowiednich części ciała z 2 parametrami – numer użytkownika docelowego oraz jedna

z wartości typu wyliczeniowego SkeletonJoint. Docelowo typ ten przechowuje dużo części

ludzkiego ciała, ale biblioteka jeszcze nie implementuje ich obsługi.

Przerysowywanie obrazu polega na usunięciu z nakładki na obrazie z Kinecta

wszystkich dodatkowych elementów, a następnie dodanie ich na nowo w zaktualizowanych

pozycjach – na potrzeby projektu została wykorzystana jedynie elipsa o tych samych

atrybutach szerokości i wysokości (czyli koło) oraz kostka, która została opisana wcześniej.

Współrzędne XYZ danej części ciała w przestrzeni można odczytywać na bieżąco z tablicy

Page 12: Dokumenta Cj A

12

aktualizowanej automatycznie przez bibliotekę openNI. Aby nie doszło do zjawiska

wyścigów wątków, obraz wideo z Kinecta należy zablokować, pobrać pojedynczą bitmapę,

a następnie go odblokować.

Wątek śledzący ruch działa w pętli gorącego czekania z wartością Sleep równą

100 milisekund. Gdy przemieszczenie w osi poziomej lub pionowej przekroczy wartość

progową, wywoływana jest metoda obracająca aktywną ścianę.

Wątek wyboru odpowiedniej ściany również działa w pętli gorącego czekania, ale

ponieważ nie jest tu badane przemieszczenie, to aktualny stan może być sprawdzany znacznie

częściej – 22 milisekundy. W pierwszej kolejności sprawdzane jest czy użytkownik chce

odznaczyć daną ścianę. Ponieważ biblioteka wykorzystująca Kinecta nie jest w swoim

działaniu bezbłędna (szczególnie podczas analizy pozycji użytkowników w luźnych strojach),

należało wprowadzić pewien margines błędu. Marginesy błędów są wykorzystywane podczas

analizy każdej pozycji, gdy użytkownik powinien uzyskać przynajmniej jedną poziomą linię.

System posiada obecnie wewnętrzne ograniczenie na maksymalną liczbę

użytkowników. Nie został przygotowany tryb multiplayer, więc maksymalna liczba

wykrytych użytkowników (obecnie 4) może jednocześnie operować na tej samej kostce

Rubika.

Obsługa Kinecta była utrudniona, ponieważ nie pojawiło się jeszcze SDK Microsoftu

do jego obsługi. Poza tym interfejs należy obsługiwać przy pomocy myszki bo dostępność

urządzenia nie pozwoliła na zaimplementowanie jego obsługi przy pomocy Kinecta.

4. Zasady gry

Zabawa kostką polega na takim ułożeniu kwadratów, aby na każdej ścianie wszystkie

posiadały jeden kolor. Składa się ona z 26 sześcianów i przegubu umieszczonego w środku.

Przegub ten umożliwia każdej z zewnętrznych warstw kostki obrót wokół osi prostopadłej do

danej warstwy i przechodzącej przez środek kostki.

Liczba kombinacji różnych ułożeń kostki 3×3×3 wynosi 43 252 003 274 489 856 000

(ponad 43 tryliony).

Page 13: Dokumenta Cj A

13

5. Elementy dodatkowe

5.1 Zarządzanie profilami graczy

Oprócz samej gry został stworzony system zarządzania profilami graczy. Zarządzanie

profilami. Do zarządzania profilami wykorzystywany jest lokalny plik 'profiles.xml', który

zawiera utworzone profile przez użytkowników gry. Budowa pliku zawierającego profile jest

następująca:

1) Węzeł główny o nazwie 'Users' zawierający utworzone profile użytkowników.

Dodatkowo posiada on 2 atrybuty: 'last' - atrybut przechowujący login ostatnio

zalogowanego użytkownika oraz 'level' - atrybut przechowujący ostatnio

ustawiony poziom gry.

2) Dalej w hierarchi definiowane są poszczególne profile. Każdy z profili składa się

z trzech węzłów - jednego głównego 'User' określającego definicję profilu oraz

dwóch podrzędnych węzłów 'UserName' oraz 'Password' zawierających

informację danych użytkownika. Hasło jako węzeł 'Password' przechowywane

jest w formie zaszyfrowanej algorytmem MD5.

Aby użyć wcześniej zdefiniowanego profilu wystarczy na stronie profilów wybrać

dany login z listy oraz wpisać hasło dla profilu, po czym kliknąć 'Use profile'. Hasło jest

szyfrowane funkcją skrótu MD5 i porównywane z hasłem zakodowanym w pliku

‘profiles.xml’. Jeśli hasła są jednakowe użytkownik staje się aktywny, czyli wszystkie wyniki

zostaną zapisane na jego konto oraz przy ponownym uruchomieniu gry, gdy później nie

nastąpi ponowna zmiana aktywnego użytkownika, zostanie użyty ten profil.

Aby utworzyć nowy profil wystarczy na stronie profilów podać login dla nowego

użytkownika oraz wpisać hasło dla profilu, po czym kliknąć 'Create profile'. Jeśli baza danych

jest dostępna oraz podany login nie istnieje już w bazie użytkowników to nowy użytkownik

zostanie utworzony oraz stanie się aktywny, czyli wszystkie wyniki zostaną zapisane na jego

konto, a także przy ponownym uruchomieniu gry, gdy później nie nastąpi ponowna zmiana

aktywnego użytkownika zostanie użyty ten profil. Dodatkowo do bazy danych zostanie

wprowadzony nowy użytkownik z danymi formularza, czyli login oraz hasło zaszyfrowane

w MD5 oraz, w lokalnym pliku 'profiles.xml' zostanie dodany nowy wpis o utworzonym

Page 14: Dokumenta Cj A

14

profilu (potrzebne węzły zostaną utworzone według wcześniej opisanej hierarchii w pliku

profilów).

5.2 Ranking wyników

Przy wykorzystaniu profili graczy utworzono centralny ranking wyników. Wyniki

globalne są przechowywane w bazie danych, natomiast lokalne w pliku ‘scores.xml’. Po

przejściu do menu ‘Statistics’ widać lokalne wyniki. Po kliknięciu przycisku ‘Update’ wyniki

lokalne są przesyłane do bazy danych, a z bazy pobierane są nowe, których nie ma jeszcze

lokalnie.

5.3 Strona WWW poświęcona grze oraz Fan Page na Facebooku

Ponadto stworzona została strona informacyjna opisująca grę oraz zawierająca

centralną bazę wyników graczy. Dodatkowo został stworzony fan page na facebooku. Adresy:

Strona WWW: http://lisu.homelinux.org/~angel/rubiq

Fan page: http://www.facebook.com/pages/Rubiq-Cube/105023389589931

6. Interfejs użytkownika

Nie wszystkie elementy można obsłużyć przy pomocy Kinecta, więc przygotowane

zostały 2 wersje aplikacji – jedna częściowo obsługuje Kinecta, a druga korzysta tylko

z myszki i klawiatury. W obu przypadkach menu główne obsługiwane jest przy pomocy

myszki.

Jedyna z opcji, która obsługiwana jest inaczej to ‘Start Game’. Pojawia się nowe okno

z instrukcją po lewej. Na środku ekranu znajduje się kostka Rubika. W wersji

z Kinectem po prawej stronie pojawia się również okno z widokiem, z kamery wbudowanej

w urządzenie. Aby uaktywnić obsługę przy pomocy Kinecta, należy ustawić się w pozycji

przypominającej grecką literę Ψ. Poprawne wykrycie użytkownika zostanie zasygnalizowane

pojawieniem się punktów kontrolnych na szkielecie. Będą one podążać za użytkownikiem.

Możliwe jest 9 rodzajów zaznaczonych ścian oraz można niczego nie zaznaczać

i wtedy dokonuje się obrotu całej kostki. Lewą ręką wybiera się odpowiednie ściany,

a prawą wykonuje obroty. Badane są różnice położeń prawej dłoni w krótkich odcinkach

Page 15: Dokumenta Cj A

15

czasu. Jeżeli przesunięcie będzie wystarczająco duże, wykonany zostanie obrót o 45°. Dla

bardziej energicznego ruchu możliwe jest jednorazowe wykonanie obrotu o 90°.

W przypadku obrotu całej kostki możliwe są obroty o 90° i 180°. Kostka lub jej wybrana

ściana jest obracana w kierunku zgodnym z kierunkiem przemieszczenia prawej dłoni.

Patrząc na nachyloną do poziomu kostkę, można w pionie wyodrębnić 6 różnych ścian. Z

przodu widoczne są 2 ściany boczne. Aby wybrać odpowiednią z nich, należy stanąć

w rozkroku lub ze złączonymi nogami. W obu przypadkach lewy łokieć powinien być na

wysokości ramienia. Kąt w łokciu powinien wynosić około 90°, a lewa ręka powinna być

skierowana w pionie do góry. Jedną z 3 ścian wybiera się poprzez skręty ciała – lewa strona z

przodu, na równi z prawą i lewa strona z tyłu. Należy jednak uważać, żeby lewa dłoń nie

znalazła się za ramieniem, ponieważ przy pomocy wykorzystanej biblioteki, tracony jest

obraz szkieletu. Aby wybierać w ścianach poziomych, należy lewą dłoń umieszczać na

wysokości czoła, na wysokości torsu lub na poziomie pasa. Aby dokonać odznaczenia ścian,

należy wyprostować lewą rękę w łokciu i unieść lewą dłoń na wysokość ramienia. Te same

czynności można wykonać przy pomocy klawiatury w wersji, która nie wykorzystuje Kinecta.

W trakcie gry mierzony jest czas – od wykonania pierwszego ruchu kostką. Ułożenie

kostki sygnalizowane jest odpowiednim komunikatem. Aby wyjść z aktualnej rozgrywki,

należy wcisnąć przycisk „ESC”.

W opcji ‘Profile’ ustawiane są dane dotyczące konta – nazwa użytkownika i hasło.

Natomiast w ‘Statistics’ przechowywane są najlepsze wyniki – można użyć przycisku

‘Update’, żeby pobrać aktualne dane rankingowe z serwera. W ‘Settings’ możemy ustawić

level. Odpowiada on liczbie przesunięć mających na celu wymieszanie kostki. Przycisk ‘Exit’

zamyka aplikację.

Bibliografia

[1] Stephens Rod, WPF Programmer’s Reference, Wiley Publishing, 2010.

[2] Nathan A., Windows Presentation Foundation Unleashed, Sams Publishing, 2007.

[3] MacDonald M., Pro WPF in C# 2008 Windows Presentation Foundation with .NET 3.5,

APress, 2008.

Page 16: Dokumenta Cj A

16

[4] Witryna poświęcona technologiom Windows Presentation Foundation oraz Windows

Forms, http://windowsclient.net

[5] Strona poświęcona technologii WPF, http://www.wpftutorial.net

[6] GÓRSKI J., Inżynieria oprogramowania w projekcie informatycznym, Mikom, Warszawa,

1999.

[7] Rysowanie Kinectem za pomocą biblioteki OpenNI,

http://www.studentguru.gr/blogs/vangos/archive/2011/02/09/kinect-and-wpf-

painting-with-kinect-using-openni.aspx

[8] Tutorial 3D dla Windows Presentation Foundation,

http://kindohm.com/technical/WPF3DTutorial.htm

[9] Dokumentacja biblioteki OpenNI, http://openni.org/documentation