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

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

Reprezentacja mapy

Labirynt będziemy przechowywać jako tablicę jego sześciennych skrzyżowań. Każde skrzyżowanie może być połączone lub rozdzielone ścianą z każdym z sześciu sąsiadującymi z nim innymi skrzyżowaniami.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int mapa_size[ 3 ] = { 0, 0, 0 };
 
struct mapa_node
{
        char przejscie[ 3 ][ 2 ];
};
 
vector<mapa_node> mapa;
 
#define V(x,y,z) ((x) + \
                  (y)*(mapa_size[ 0 ]+1) + \
                  (z)*(mapa_size[ 0 ]+1)*(mapa_size[ 1 ]+1) )
 
#define MAPA(x,y,z) mapa[(x) + \
                         (y)*mapa_size[0] + \
                         (z)*mapa_size[0]*mapa_size[1]]

Tablica mapa_size przechowuje rozmiar labiryntu (jednostką jest skrzyżowanie) odpowiednio w wymiarach x, y, z.

Struktura mapa_node opisuje skrzyżowanie za pomocą tablicy przejscie[wymiar][kierunek]. Dla każdego kierunku w każdym wymiarze (łącznie 6 kierunków) zapisujemy wartość różną od zera, jeśli w danym kierunku da się przejść (nie ma ściany). W przeciwnym wypadku zapisujemy zero.

Następnie deklarujemy vector mapa, który przechowuje wszystkie struktury mapa_node. Odwołujemy się do niego poprzez makro MAPA, które mapuje trójwymiarową pozycję skrzyżowania na indeks jednowymiarowej tablicy. Oczywiście możemy wykonać to mapowanie w inny sposób.

Makro V wykonuje podobne mapowanie, ale dla wymiarów powiększonych o 1. Będzie nam potrzebne przy odwoływaniu się do wierzchołków ścian, ponieważ w każdym wymiarze będzie ich o 1 więcej niż skrzyżowań:


Schematycznie przedstawiona mapa w dwóch wymiarach

Rysunek jest oczywiście uproszczony do dwóch wymiarów. Czerwone kwadraty oznaczają skrzyżowania, a czarne kółka to wierzchołki ścian.

Powyższa reprezentacja wystarcza do przetwarzania logiki gry. Jednak aby renderować ściany, potrzebujemy dodatkowych zmiennych i buforów. Odnajdźmy w naszym programie fragment, w którym deklarujemy bufory wierzchołków i tekstury:

1
2
IDirect3DVertexBuffer9  *pVB = 0;
IDirect3DTexture9       *pTexture = 0;

Zamiast tych dwóch buforów, zadeklarujmy następujące:

1
2
3
4
5
6
7
8
IDirect3DVertexBuffer9  *pVBsciany = 0;
IDirect3DVertexBuffer9  *pVBpodlogi = 0;
 
IDirect3DIndexBuffer9   *pIBsciany = 0;
IDirect3DIndexBuffer9   *pIBpodlogi = 0;
 
IDirect3DTexture9       *pTextureS = 0;
IDirect3DTexture9       *pTextureP = 0;

Deklarujemy tu dwa bufory wierzchołków dla ścian i podłóg labiryntu (chociaż z punktu widzenia logiki gry ściany i podłogi niczym się nie różnią). Robimy tak, ponieważ w przeciwnym wypadku niektóre wierzchołki musiałyby mieć więcej niż jedną parę współrzędnych tekstury.

Oprócz buforów wierzchołków, użyjemy też buforów indeksów, aby nie duplikować niepotrzebnie wierzchołków. Bufor indeksów jest zwykłą tablicą liczb całkowitych, które są indeksami bufora wierzchołków. Kolejne trójki indeksów (przy interpretacji bufora jako listy trójkątów) będą mówiły, które wierzchołki z bufora wierzchołków mają tworzyć dany trójkąt.

Deklarujemy też dwie tekstury - teksturę ściany i teksturę podłogi.

Kolejnymi zmiennymi, które zadeklarujemy globalnie, będą:

1
2
int num_sciany = 0;
int num_podlogi = 0;

Odpowiednio liczba ścian i liczba podłóg. Poza tym, będziemy potrzebować 3 wektorów (w matematycznym sensie), aby zapamiętać aktualną pozycję gracza, kierunek, w którym patrzy oraz w którą stronę jest skierowany "czubek głowy" gracza (wektor w górę).

1
2
3
D3DXVECTOR3 pozycja;
D3DXVECTOR3 kierunek;
D3DXVECTOR3 gora;

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

Copyright © 2008-2010 Wrocławski Portal Informatyczny

design: rafalpolito.com