DirectX: Trójwymiarowy labirynt od podstaw - Część II

17.03.2010 - Adam Błaszkiewicz
TrudnośćTrudność

Obsługa klawiatury

Stan klawiszy (wciśnięty lub nie) będziemy przechowywać w globalnej tablicy:

1
char klawisze[256];

Aby aktualizować tablicę, możemy na przykład obsługiwać 2 dodatkowe komunikaty w funkcji zwrotnej naszego okna:

1
2
3
4
5
6
7
                case WM_KEYDOWN:
                        klawisze[wParam]=1;
                        return 0;
 
                case WM_KEYUP:
                        klawisze[wParam]=0;
                        return 0;

W pętli komunikatów, tuż przed wywołaniem funkcji Render(), przetwarzamy wciśnięte klawisze i ewentualnie przesuwamy odpowiednio gracza (wygodnie będzie umieścić ten kod w osobnej funkcji):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
if(klawisze['W'])
{
        Przesun(kierunek);
        klawisze['W']=0;
}
if(klawisze['S'])
{
        Przesun(-kierunek);
        klawisze['S']=0;
}
if(klawisze['A'])
{
        D3DXVECTOR3 v;
        D3DXVec3Cross(&v, &kierunek, &gora);
        Przesun(v);
        klawisze['A']=0;
}
if(klawisze['D'])
{
        D3DXVECTOR3 v;
        D3DXVec3Cross(&v, &gora, &kierunek);
        Przesun(v);
        klawisze['D']=0;
}
if(klawisze[VK_SPACE])
{
        Przesun(gora);
        klawisze[VK_SPACE]=0;
}
if(klawisze[VK_CONTROL])
{
        Przesun(-gora);
        klawisze[VK_CONTROL]=0;
}
if(klawisze[VK_LEFT])
{
        D3DXMATRIX mat;
        D3DXMatrixRotationAxis(&mat, &gora, -D3DX_PI/2);
        D3DXVec3TransformCoord(&kierunek, &kierunek, &mat);
 
        klawisze[VK_LEFT]=0;
}
if(klawisze[VK_RIGHT])
{
        D3DXMATRIX mat;
        D3DXMatrixRotationAxis(&mat, &gora, D3DX_PI/2);
        D3DXVec3TransformCoord(&kierunek, &kierunek, &mat);
 
        klawisze[VK_RIGHT]=0;
}
if(klawisze[VK_UP])
{
        D3DXVECTOR3 v = kierunek;
        kierunek = -gora;
        gora = v;
 
        klawisze[VK_UP]=0;
}
if(klawisze[VK_DOWN])
{
        D3DXVECTOR3 v = kierunek;
        kierunek = gora;
        gora = -v;
 
        klawisze[VK_DOWN]=0;
}
if(klawisze[VK_DELETE])
{
        D3DXMATRIX mat;
        D3DXMatrixRotationAxis(&mat, &kierunek, D3DX_PI/2);
        D3DXVec3TransformCoord(&gora, &gora, &mat);
 
        klawisze[VK_DELETE]=0;
}
if(klawisze[VK_NEXT])
{
        D3DXMATRIX mat;
        D3DXMatrixRotationAxis(&mat, &kierunek, -D3DX_PI/2);
        D3DXVec3TransformCoord(&gora, &gora, &mat);
 
        klawisze[VK_NEXT]=0;
}

Jeśli któryś z obsługiwanych przez nas klawiszy został wciśnięty, ustawiamy jego status z powrotem na niewciśnięty, aby gracz musiał ponownie wcisnąć ten klawisz, jeśli chce wykonać tę samą akcję.

Klawisze W, S, A, D przesuwają gracza odpowiednio do przodu, do tyłu, w lewo oraz w prawo. Spacja przesuwa gracza w górę, a Control w dół. Do obrotów służą strzałki oraz Delete i Page Down (VK_NEXT). W każdym z przypadków modyfikujemy odpowiednio zmienne pozycja, kierunek i gora, opisujące pozycję oraz obrót gracza. Używamy też pomocniczej funkcji przesun(), która przesuwa gracza w zadanym kierunku. Wygląda ona tak:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void Przesun(D3DXVECTOR3& vec)
{
    mapa_node& node = 
        MAPA((UINT)pozycja.x,
             (UINT)pozycja.y,
             (UINT)pozycja.z);
 
    if(vec.x> 0.9 && node.przejscie[0][1]) pozycja += vec;
    if(vec.x<-0.9 && node.przejscie[0][0]) pozycja += vec;
    if(vec.y> 0.9 && node.przejscie[1][1]) pozycja += vec;
    if(vec.y<-0.9 && node.przejscie[1][0]) pozycja += vec;
    if(vec.z> 0.9 && node.przejscie[2][1]) pozycja += vec;
    if(vec.z<-0.9 && node.przejscie[2][0]) pozycja += vec;
}

Aby uniknąć błędów zaokrągleń, nie porównujemy współrzędnych znormalizowanego wektora kierunku (czyli wektora o długości równej 1, który mówi nam, w którą stronę skierowany jest gracz) bezpośrednio do 1 lub -1. Przesunięcie gracza polega po prostu na dodaniu do jego pozycji wspomnianego wektora kierunku. Jednak musimy dodatkowo sprawdzić, czy na drodze nie znajduje się ściana (lub podłoga).

Płynne ruchy kamery

Nie chcemy, żeby kamera skakała ze środka jednego skrzyżowania do środka drugiego. Zamiast tego, chcielibyśmy uzyskać płynny ruch. Najprościej jest uzyskać taki efekt za pomocą liniowej zależności szybkości od odległości do celu. Naszym celem będzie pozycja gracza opisana za pomocą zmiennych pozycja, kierunek i gora. Natomiast faktyczną pozycję i obrót kamery będziemy przechowywać w zmiennych pozycja_real, kierunek_real i gora_real. Co jakiś czas, na przykład na początku funkcji renderującej, aktualizujemy zmienne "_real":

1
2
3
        pozycja_real = 0.9*pozycja_real + 0.1*pozycja;
        kierunek_real = 0.9*kierunek_real + 0.1*kierunek;
        gora_real = 0.9*gora_real + 0.1*gora;

Tak więc, liczymy średnią ważoną. Moglibyśmy także napisać:

        pozycja_real += (pozycja - pozycja_real)*0.1;

Warto zauważyć, że wektory _real nie będą znormalizowane podczas przemieszczania się w stronę wektorów docelowych (a z matematycznego punktu widzenia nigdy nie będą równe wektorom docelowym). Należy uważać podczas używania nieznormalizowanych wektorów w połączeniu z niektórymi funkcjami Direct3D.

Innymi słowy, przesuwamy punkt pozycja_real w stronę punktu pozycja o 1/10 odległości pomiędzy nimi. Analogicznie postępujemy z wektorami kierunek_real i gora_real.

5
Twoja ocena: Brak Ocena: 5 (1 ocena)

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com