Home - Rasfoiesc.com
Educatie Sanatate Inginerie Business Familie Hobby Legal
Doar rabdarea si perseverenta in invatare aduce rezultate bune.stiinta, numere naturale, teoreme, multimi, calcule, ecuatii, sisteme




Biologie Chimie Didactica Fizica Geografie Informatica
Istorie Literatura Matematica Psihologie

Informatica


Index » educatie » Informatica
» PROIECT SISTEME PENTRU PRELUCRARI GRAFICE - CHICKEN INVADERS


PROIECT SISTEME PENTRU PRELUCRARI GRAFICE - CHICKEN INVADERS


UNIVERSITATEA DIN CRAIOVA

FACULTATEA DE AUTOMATICA, CALCULATOARE SI ELECTRONICA

PROIECT

SISTEME PENTRU PRELUCRARI GRAFICE



CHICKEN INVADERS

Tema proiectului:

Algoritmi de survival-razboi. Chicken Invaders.

Se va dori implementarea unei aplicatii asemanatoare jocului "Chicken Invaders", programarea jocului facandu-se cu DirectX. Atentie, nu se va folosi "game ingine", totul realizandu-se in cod C++ si DirectX

Introducere

Pentru realizarea acestui proiect am fost nevoiti sa ne reimprospatam cunostintele noastre de Algebrea liniara de care ne-am lovit intens la manipularea vectorilor. Cunostintele C++ combinate cu un nou stil de programare datorat intrarii pe scena a DirectX-ului ne-a condus la realizarea pas cu pas a acestui proiect. In realizarea proiectului nu am folosit nici o librarie de "game ingine".

La realizarea acestui proiect ne-am folosit de: Microsoft Visual Studio 2005 acesta fiind mediul de programare, Maya pentru creare de mesh-uri, DirectX 9 SDK instalat si foarte foarte multa cautare pe Google pentru tutoriale.

Documentatia privind aspectele legate de proiect

Crearea aplicatiei windows de baza a proiectului

Am inceput acest proiect construind o aplicatie windows simpla, alegand Win32 de la tipul de proiect la Visual Studio 2005.

#include <windows.h>

const char MAIN_WINDOW_TITLE[] = 'Chicken Invaders',
MAIN_WINDOW_CLASS_NAME[] = 'myWindowClass';

const int MAIN_WINDOW_WIDTH = ,
MAIN_WINDOW_HEIGHT = ;


LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

return ;



int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)


// Create window
hwnd = CreateWindowEx(
NULL,
MAIN_WINDOW_CLASS_NAME,
MAIN_WINDOW_TITLE,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
MAIN_WINDOW_WIDTH, MAIN_WINDOW_HEIGHT,
NULL, NULL, hInstance, NULL);

if(hwnd == NULL)

// Show window
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);

// Message loop
while(GetMessage(&msg, NULL, , ) > )

return msg.wParam;

Codul de mai sus este codul de baza, de inceput al proiectului nostru care creeaza o aplicatie windows de baza.

Exista doar doua standard functii: WinMain () si WndProc (). Functia WinMain () include definitia ferestrei, precum si principalele mesaje din bucla. Functia WndProc () prelucreaza mesajele, atata timp cat aplicatia ruleaza.

In acest exemplu, am taiat mesajele lasand doar 2 mesaje in curs de procesare de catre functia WndProc () . Aceste mesaje sunt: WM_CLOSE si WM_DESTROY.

Mesajul WM_CLOSE este trimis, atunci cand utilizatorul inchide fereastra. In cazul in care este primit, fereastra este distrusa chemand metoda DestroyWindow (hwnd). Metoda DestroyWindow ()de asemenea genereaza un mesaj WM_DESTROY.

Mesajul WM_DESTROY duce la oprirea aplicatiei. Acest lucru se realizeaza prin apel la metoda PostQuitMessage (0).

In interiorul WinMain () vom folosi WNDCLASSEX pentru a specifica tipul de fereastra care ne-o dorim pentru a o crea. Hwnd este un handle la fereastra si msg este mesajul pe care il vom trimite.

Verificam daca fereastra a fost inregistrata cu succes, daca nu aratam un mesaj de eroare in MessageBox. Dupa ce fereastra a fost inregistrata o cream transmitand titlul, latimea si inaltimea printre alti parametri.

Urmatorul pas este afisarea si actualizarea ferestrei.

In cele din urma este bucla de mesaje care in mod constant verifica daca exista mesaje in coada prin apel la metoda GetMessage ().Daca da, acestea sunt traduse si expediate astfel incat sa poata fi prelucrate de catre functia WndProc ().

Crearea dispozitivului DirectX device ( DirectX device )

Pentru a folosi avantajele puse la dispozitie de cardul grafic, vom crea un DirectX device pentru a interactiona cu ea. In cazul in care sunt mai multe carduri grafice, atunci il vom folosi doar pe cel principal.

In cazul in care am exista un card grafic care nu se potriveste DirectX-ului instalat atunci se introduce variabila D3DCREATE_SOFTWARE_VERTEXPROCESSING care va face o prelucrare software . Astfel se verifica mai intai compatibilitattea cu cardul grafic iar daca nu e compatibil se trece pe o prelucrarea software.

Inainte de toate, vom include urmatoarele fisiere header:

#include<d3d9.h>
#include<d3dx9.h>

apoi adaugam urmatoarele variabile globale la program:


// Globals

LPDIRECT3D9 directX;
LPDIRECT3DDEVICE9 directXDevice;

Prima variabila este un pointer la Direct3D9. Ce-a dea doua variabila este un pointer spre un dispozitiv DirectX.

In metoda WinMain() am adaugat apoi urmatorele:

// Init DirectX objects
initDevice(hwnd);
initCamera();
initScene();

// Message loop
while(msg.message != WM_QUIT)
drawScene();


// Cleanup DirectX objects
cleanup();
return msg.wParam;

Inainte de a intra in bucla de mesaje, apelam metoda initDevice careia i se transmite ca parametru un handler al ferestrei curente.

Am folosit aici metoda PeekMessage () deoarece ea nu asteapta o confirmare a faptului ca un mesaj a fost plasat in coada de asteptare ci se intoarce imediat. GetMessage () nu se intoarce pana cand mesajul este plasat in coada de asteptare si aceasta produce intarzieri

Codul sursa a metodei initDevice():

void initDevice(HWND myWindow)

ZeroMemory( &dxPresentParams, sizeof(dxPresentParams) );
dxPresentParams.Windowed = TRUE;
dxPresentParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
dxPresentParams.BackBufferFormat = D3DFMT_UNKNOWN;

if (FAILED(directX->CreateDevice(
D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,
myWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING,
&dxPresentParams, &directXDevice)))


directXDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
directXDevice->SetRenderState(D3DRS_LIGHTING, false);



Mai intai am definit dxPresentParams, care este un obiect care reprezinta toate caracteristicile DirectX sustinut de un dispozitiv. Apoi, vom crea obiectul mediului DirectX, vom verifica daca mediu DirectX este disponibil (instalat in sistem), daca nu vom da un mesaj de eroare care indica acest lucru. Dupa care initializam proprietatile dxPresentParams, incercand sa cream un dispozitiv de sustinere a DirectX prin 'prelucrare hardware a varfurilor'. Daca nu reusim sa cream un astfel de dispozitiv, vom incerca sa cream un ' dispozitiv software' care sa sustina ' prelucrarea software a varfurilor' intr-un mod tip simulare. In cele din urma setam proprietatile dispozitivului.

Urmatoarea metoda initiaza punctual de vedere:

void initCamera()

Ochiul punctului de vedere situat la (0,0, -30) 'se uita la' tinta ce se afla la (0, 0, 0), care este centrul lumii noastre 3D (numerele reprezinta coordonatele x, y, z) .

Apoi am definit matricea de proiectie care este responsabila pentru o vizualizare in perspectiva, care creeaza o iluzie de adancime pe ecran. In cele din urma vom transforma matricea de proiectie prin apelarea metodei SetTransform() a dispozitivului nostru DirectX.

Apoi metoda cleanup() pentru a elibera resursele DirectX din memorie.

void cleanup()

if(directXDevice)

if(directX)

// change

if( g_pTexture )

g_pTexture->Release();

Desenarea pe ecran a diferite obiecte

Incepem cu o definitie a unui Boolean isWireframe , variabila globala. Apoi vom defini un mesh pt a retine varfurile obiectului pe care vrem sa il desenam intial. Initial va o fi un cub peste care se va pune apoi un alt mesh.

bool isWireframe = false;
LPD3DXMESH meshBox;

Urmatorul lucru verifica modul in care se va rula: in wireframe sau nu si modifica starea dispozitivului.

if(isWireframe)
directXDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
else
directXDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

In cadrul metodei InitScene adaugam urmatorul cod:

D3DXCreateBox(
directXDevice,
2.0f, // width
2.0f, // height
2.0f, // depth
&meshBox,

DirectX vine incorporat cu mai multe primitive cum ar fi :

D3DXCreateCylinder()
D3DXCreateLine()
D3DXCreateFont()
D3DXCreatePolygon()
D3DXCreateSphere() dar din toate astea s-a ales pt proiectul prezent lucrul cu cuburi si sfere peste care se aplica sau nu un alt mesh.

Metoda drawScene () este un loc unde vom desena toate figurile noastre geometrie. Vom scrie tot codul intre metodele BeginScene () si EndScene ().

Iata cum ar arata:

D3DXMATRIX matrix;
D3DXMatrixTranslation(&matrix, 0.0f, 0.0f, 0.0f);
directXDevice->SetTransform(D3DTS_WORLD, &matrix);

// draw the object using the previously created world matrix.
meshBox->DrawSubset( ); // box has only 1 subset (AttribId = 0)


In primul rand vom defini matrice. Dorim cubul nostru sa apara in centrul lumii 3D create de noi. De aceea am stabilit coordonatele la 0. Apoi vom modifica matricea cu metoda SetTransform (), care ia constanta D3DTS_WORLD ca parametru si returneaza matricea transformata in variabila matrice definita anterior. Putem apoi desena obiectul nostru prin apel la metoda DrawSubset (0) a meshBoxului.

Este intotdeauna important sa curatam memoria de obiecte cand e indicat momentul. In acest exemplu, vom efectua curatenie cand vom iesi din aplicatie. Asta inseamna ca ne putem folosi de metoda cleanup () si sa adaugam urmatorul cod acolo pentru a elibera meshBox din memorie:

if (meshBox) )


Crearea animatiei cu DirectX. Miscarea in jos si in sus a cubului (liliacului)

Vom defini constantele de a stabili unele limite cubului nostru:

const float MAX_BOX_Y = 3.0f , Const float MAX_BOX_Y = 3.0f,

MIN_BOX_Y = - 4.0f ; MIN_BOX_Y = - 4.0f;

O alta variabila globala:

float timeDelta = 0.0f;

timeDelta poate fi mai bine inteleasa ca 'masura de miscare'. Cu alte cuvinte cat de mult se va misca cubul nostru in fiecare cadru. Este initializata aici la 0.

void drawScene()
else

vectorB = D3DXVECTOR3( , y, );

direction = vectorA - vectorB;
D3DXVec3Normalize(&direction, &direction);
newPosition = vectorA + (direction * timeDelta);

D3DXMatrixTranslation(&matrix, , y, );
directXDevice->SetTransform(D3DTS_WORLD, &matrix);


// draw the object using the previously created world matrix.
meshBox->DrawSubset( ); // box has only 1 subset (AttribId = 0)


// end scene
directXDevice->EndScene();
directXDevice->Present(NULL, NULL, NULL, NULL);

Dupa cum se poate vedea am adaugat definitia statica a variabilei y pentru a retine coordonata y a cubului intre apelurile metodelor si definirea statica a unui vector de directie. Vector de directie se va schimba pe masura ce cubul se va misca in sus si in jos pe ecran.

Avem nevoie de vectorA si vectorB sa retina pozitia de plecare si de destinatie a cubului respectiv, precum si un vector newPosition pentru a stoca rezultatele manipulari vectorului.

Cubul se misca in sus, daca coordonta y este mai mare decat minimul permis, de exemplu, -4.2. De asemenea, se misca in sus in cazul in care coordonata y este mai mica sau egala cu maximul permis (de exemplu 2.8) si, in acelasi timp, in cazul in care valoarea de directie a lui.y este mai mica sau egala cu 0.

Dupa cum puteti vedea in toate celelalte cazuri, cubul nostru se va misca in jos.

Dupa scaderea vectorB din vectorA pentru a calcula vectorul directie trebuie normalizat. Apoi vom calcula noul vector de pozitie si vom efectua transformarea matricei. Matricea modificata este stocata in variabila matrice. Dupa ce a fost modificata matricea informam directXDevice de transformare prin apelarea metodei SetTransform () si trecerea constantei D3DTS_WORLD si a matricii ca parametrii. Dupa care vom desena cubul prin apel de DrawSubset (0) a obiectului meshBox

// Message loop with timeDelta / / Mesaj bucla cu timeDelta
static float lastTime = ( float )timeGetTime(); static float lastTime = (float) timeGetTime ();
while (msg.message != WM_QUIT) )
else )

Controlarea totala a cubului de la tastatura.

De asemenea, vom construi un foarte simplu HUD (heads-up display) pentru jocul nostru cu ferestre de dialog si vom utiliza un viewport DirectX pentru a crea lumea noastra 3D, in functie de dimensiunile specificate.

Cu Resource Editor in Visual Studio am creat fisierul ControlPanel.rc, care cuprinde definitiile: 2 ferestre de dialog (una pentru a fi folosita ca un panou de control pentru a prezenta informatii suplimentare pentru utilizator si una ca sa fie folosita ca un Viewport sa creeze lumea 3D DirectX). Panoul de control al fereastrei de dialog are un numar de controale statice (etichete) pentru a retine valorile pozitiilor X, Y, Z ale cubului.

Continutul ControlPanel.rc

// Microsoft Visual C++ generated include file.

// Used by ControlPanel.rc

#define ID_VIEWPORT    102

#define ID_CONTROLPANEL    103

#define ID_GAMEMENU    104

#define ID_BOX_X    1001

#define ID_BOX_Y    1002

#define ID_BOX_Z    1003

#define ID_BOX_X_LABEL    1004

#define ID_BOX_Z_LABEL    1005

#define ID_BOX_Y_LABEL    1006

#define ID_FIREBALLS    1007

#define ID_FIREBALLS_LABEL    1008

#define ID_ASTEROIDS    1009

#define ID_ASTEROIDS_LABEL    1010

#define ID_ASTEROIDS_VECTOR    1011



#define ID_ASTEROIDS_VECTOR_LABEL 1012

#define ID_FIREBALLS_VECTOR_LABEL 1013

#define ID_FIREBALLS_VECTOR    1014

#define ID_SCORE    1015

#define ID_SCORE_LABEL    1016

#define ID_GAME_OVER    1017

#define ID_FIREBALLS_LABEL2    1018

#define ID_GAMEMENU_NEWGAME    40004

#define ID_GAMEMENU_EXIT    40005

// Next default values for new objects

#ifdef APSTUDIO_INVOKED

#ifndef APSTUDIO_READONLY_SYMBOLS

#define _APS_NEXT_RESOURCE_VALUE    105

#define _APS_NEXT_COMMAND_VALUE 40006

#define _APS_NEXT_CONTROL_VALUE 1020

#define _APS_NEXT_SYMED_VALUE    101

#endif

#endif

Continutul ControlPanel.rc


// Dialog


ID_CONTROLPANEL DIALOGEX , , ,
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, 'MS Shell Dlg', , , 0x1
BEGIN
LTEXT 'X',ID_BOX_X, , , ,
LTEXT 'Z',ID_BOX_Z, , , ,
LTEXT 'Y',ID_BOX_Y, , , ,
LTEXT 'X:',ID_BOX_X_LABEL, , , ,
LTEXT 'Z:',ID_BOX_Z_LABEL, , , ,
LTEXT 'Y:',ID_BOX_Y_LABEL, , , ,
END

ID_VIEWPORT DIALOGEX , , ,
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD
FONT 8, 'MS Shell Dlg', , , 0x1
BEGIN
END

Urmatoarele constante au fost adaugate pentru a defini limitele de miscare a cubului

const float MAX_BOX_X = 9.0f ,

MIN_BOX_X = - 9.0f ,

MAX_BOX_Y = 4.5f , MAX_BOX_Y = 4.5f,

MIN_BOX_Y = - 5.5f ;

Vom defini un viewport ca o variabila globala:

D3DVIEWPORT9 viewPort;

Urmatoarele variabile sunt definite la nivel global asa ca vom avea un acces usor la ferestrele de dialog.

HWND hwndControlPanel = NULL;
HWND hwndViewPort = NULL;

Am adaugat variabila isBoxMove pentru a determina daca trebuie sa miscam cubul cand se deseneaza o scena.

bool isWireframe = true
isBoxMove = true

Variabila boxMove este definita ca un WPARAM asa ca noi sa-l putem trimite ca un parametru mesaj la o anumita fereastra de dialog.

WPARAM boxMove;
D3DXVECTOR3 posBox = D3DXVECTOR3( 0.0f 3.37f 0.0f

Avem nevoie, de asemenea, de vectorul posBox pentru a salva pozitia actuala a cubului nostru in lumea 3D.

Urmatoarea functie de conversie de la dublu la sir de caractere:

string CStr(double dVal)

Motivul pentru care am facut variabila posBox este de a ne permite accesul la pozitia cubului din orice metoda.

Apoi vom defini vectorul de directie si vectori A si B de pozitie, care semnifica pozitia de plecare si de destinatie a cubului respectiv. Ultima definitie este o matrice care va contine cubul transformat in spatiu.

void drawBoxMove()
else if(boxMove == VK_DOWN && y > MIN_BOX_Y)
else if(boxMove == VK_RIGHT && x < MAX_BOX_X)
else if(boxMove == VK_LEFT && x > MIN_BOX_X)

vectorB = D3DXVECTOR3(x, y, z);


direction = vectorA - vectorB;
D3DXVec3Normalize(&direction, &direction);
posBox = vectorA + (direction * timeDelta);

D3DXMatrixTranslation(&matrix, posBox.x, posBox.y, posBox.z);
directXDevice->SetTransform(D3DTS_WORLD, &matrix);

//deseneaza obiectul folosind matricea precedenta
meshBox->DrawSubset( );

// trimite mesajul catre label
string strX = CStr(posBox.x);
string strY = CStr(posBox.y);
string strZ = CStr(posBox.z);

SendMessage(hwndControlPanel, WM_COMMAND, ID_BOX_X, (LPARAM)strX.c_str());
SendMessage(hwndControlPanel, WM_COMMAND, ID_BOX_Y, (LPARAM)strY.c_str());
SendMessage(hwndControlPanel, WM_COMMAND, ID_BOX_Z, (LPARAM)strZ.c_str());

Singurul lucru care il facem in functia DrawScene este de a verifica, in cazul daca valoarea variabilei isBoxMove este adevarata ceea ce inseamna ca trebuie sa se deseneze miscarea cubului.

Adaugam urmatoarea metoda pentru a initializa fereastra de dialog de gazduire a DirectX viewport-ului nostru.

BOOL CALLBACK DlgProcViewPort(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

}
break;

default:
return FALSE;

return TRUE;

Ceea ce primeste in plus metoda DlgProcControlPanel() sunt mesajele WM_COMMAD de updatare a etichetelor x, y, z de pozitie a cubului.

BOOL CALLBACK DlgProcControlPanel(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

break;

default:
return FALSE;

return TRUE;

iar in WinProc(), pentru a face posibila miscarea cubului am pus:

case WM_KEYDOWN:
switch(wParam)
break

Daca vom apasa tasta stanga, la dreapta, in sus sau in jos initializam boxMove cu valoarea lui wParam si setam valoarea lui isBoxMove sa fie adevarat. Daca orice alta cheie este apasata atunci variabila isBoxMove va fi setata pe fals, fixand cubul in pozitia curenta in spatiu.

Tragerea cu mingi de foc in spatiu la apasarea tastei SPACE

De fiecare data cand tasta [spatiu] este apasata trebuie sa creem un obiect sfera cu un mesh de minge de foc si sa modificam pozitia in raport cu pozitia de zbor a cubului..

Am decis sa cream o noua clasa Fireball care va tine mesh-ul mingilor de foc si pozitia lor in spatiu.

Fireball.cpp

#include <d3d9.h>

#include <d3dx9.h>

class Fireball

#endif

Fireball.h

#ifndef __Fireball_h__
#define __Fireball_h__


#include <d3d9.h>
#include <d3dx9.h>

class Fireball


#endif

Clasa constructor a Fireball accepta pozitia si pointerul mesh a oricarui obiect , ceea ce face posibil utilizarea aceastei clase pentru multe scopuri. Mai intai de toate, trebuie sa includem headerul fireball.h in clasa unde WinMain este definit astfel incat sa putem sa profitam de aceasta clasa in aplicatia noastra.



Apoi definim vectorul de fireballs in care putem stoca mai multe obiecte de tip mingi de foc pe care l-am creat mai devreme.

vector<Fireball> fireballs;
Metoda drawBoxFireMove () este responsabila pentru desenarea fiecarei mutari a mingii de foc in lumea noastra. Este nevoie de pozitie si de mesh ca parametri.

void drawBoxFireMove(D3DXVECTOR3 & position, LPD3DXMESH mesh)

Din moment ce orice minge de foc poate fi creata utilizand aceasta metoda, trebuie sa avem grija ca doar vizibile (acestea, care nu au ajuns inca la valoarea maxima a lui z definita de constanta MAX_FIREBALL_Z) acestea sunt create, iar restul sunt ignorate. Apoi cream un obiect tip sfera care sa tina mash-ul mingii de foc. Pentru a muta un obiect dintr-o pozitie A la B, efectuam calcule cu vectori .

Dupa ce matricea a fost transformata , informam directXDevice ca am efectuat de modficarea apeland metoda SetTransform () si transmitand constanta D3DTS_WORLD si matricea transformata ca parametri. In cele din urma desenam obiectul cu DrawSubset (0). Aceasta este 0, deoarece numai in sfera are 1 subset de desenat.

In interiorul metodei drawScene () trebuie sa apelam metoda drawBoxFireMove ()pentru fiecare minge de foc stocata in vectorul fireballs astfel:

// draw fireballs
for(vector<Fireball>::reverse_iterator iterFireballs = fireballs.rbegin();
iterFireballs != fireballs.rend(); ++iterFireballs)

In interiorul metodei DlgProcControlPanel () vom defini o variabila statica pentru a retine numarul de fireballs trase de cubul zburator pana acum.

static int numberOfFireballsFired = ;

si adaugam procesarea urmatorului caz:

case ID_FIREBALLS:
numberOfFireballsFired += ;
SetDlgItemText(hwnd, ID_FIREBALLS,
(LPCSTR)CStr(numberOfFireballsFired).c_str());
break

Apoi in metoda WndProc () adaugam procesarea evenimentului apasarii tastei SPACE

case VK_SPACE: // box fireball

break

Daca tasta [spatiu] este apasata atunci vom crea o noua minge de foc si o adaugam la vectorul fireballs apeland metoda push_back () a vectorului. Apoi vom trimite un mesaj la fereastra hwndControlPanel pentru o prelucrare ulterioara.

Crearea asteroizilor

Vom implementa asteroizi in acelasi fel cum am implementat mingile de foc si vom folosi clasa Fireballs deja creata.

vector<Fireball> asteroids;

Metoda generateAsteroid () creeaza un nou asteroid si-l adauga la vectorul de asteroizi. Se selecteaza aleatoriu valorile pozitiilor X si Y ale asteroid. Valoarea Z este mereu aceeasi si este definita de constanta MAX_ASTEROID_Z.

void generateAsteroid()

srand((unsigned)time( ));
int randomY = (rand()%5); // random between 0 and n-1
if(randomY % 2 == )

D3DXVECTOR3 position = D3DXVECTOR3(randomX, randomY, MAX_ASTEROID_Z);
LPD3DXMESH mesh = ;

D3DXCreateSphere(
directXDevice,
1.2f, // radius


&mesh,


Fireball fireball(position, mesh);
asteroids.push_back(fireball);

Metoda drawAsteroidMove() este asemanatoare metodei drawBoxFireMove() singura diferenta fiind ca se misca in directia opusa fata de mingile de foc. De aceea adunam de fiecare data la pozitia lui Z pe timeDelta si nu scadem ca in cazul migii de foc.

void drawAsteroidMove(D3DXVECTOR3 & position, LPD3DXMESH mesh)

Am creat de asemenea metoda eraseInvisibleObjects() pentru a sterge obiectele pentru a nu incetini rularea programului. Astfel, cele care depasesc limitele devin invizibile, aceasta functie stergand pe aceste obiecte invizibile.

void eraseInvisibleObjects()
fireballs.erase(fireballs.begin());



// update fireballs vector label
SendMessage(hwndControlPanel, WM_COMMAND, ID_FIREBALLS_VECTOR,
(LPARAM)CStr(fireballs.size()).c_str());

// erase vector's first generated invisible asteroid
if(asteroids.size() > )
asteroids.erase(asteroids.begin());



// update asteroids vector label
SendMessage(hwndControlPanel, WM_COMMAND, ID_ASTEROIDS_VECTOR,
(LPARAM)CStr(asteroids.size()).c_str());

De asemenea, vom avea nevoie de stergerea tuturor obiectelor de example la sfarsitul jocului sau la inceput . aici apare functia eraseAllObjects().

void eraseAllObjects()

fireballs.clear();

// erase all asteroids
for(vector<Fireball>::iterator iterAsteroids = asteroids.begin();
iterAsteroids != asteroids.end(); ++iterAsteroids)

asteroids.clear();

// update fireballs vector label
SendMessage(hwndControlPanel, WM_COMMAND, ID_FIREBALLS_VECTOR,
(LPARAM)CStr(fireballs.size()).c_str());

// update asteroids vector label
SendMessage(hwndControlPanel, WM_COMMAND, ID_ASTEROIDS_VECTOR,
(LPARAM)CStr(asteroids.size()).c_str());

In cadrul metodei drawScene() adaugam randarea asteroizilor la fel ca cea a migilor de foc.

// draw asteroids
for(vector<Fireball>::reverse_iterator iterAsteroids = asteroids.rbegin();
iterAsteroids != asteroids.rend(); ++iterAsteroids)

Detectare coliziunii

Am ales ca tehnica de detectarea a coliziunii urmatoarea: inconjurarea obiectelor cu mici cutiute si apoi verificam daca aceste cutiute se intersecteaza cu un anumite grad de precizie.

Metoda isCollisionDetected () ia pozitiile vectorilor a doua obiecte ca parametrii si determina daca nu exista nici o coliziune intre ele prin calcularea distantei dintre pozitia vectorilor. Distanta se calculeaza in functie de bine cunoscuta formula de Algebra liniara.

bool isCollisionDetected(const D3DXVECTOR3 & pos1, const D3DXVECTOR3 & pos2)

In interiorul metodei drawScene ()vom adauga prelucrarea de coliziune dupa ce toate obiectele au fost desenate:

// collision detection

for(vector<Fireball>::iterator iterAsteroids = asteroids.begin();
iterAsteroids != asteroids.end(); ++iterAsteroids)


// check if box collides with this asteroid
if(isCollisionDetected(iterAsteroids->position, posBox))




Ce se intampla aici este looping prin toate elementele din interiorul vectorului de asteroizi si apoi looping prin toate elementele vectorului fireballs (bile trase de cub) si apelarea la metoda isCollisionDetected ()in timp ce se transmit ca parametrii pozitia vectorilor de asteroizi si de mingi de foc.

Daca este detectata coliziunea vom transforma ambele obiecte in invizibil asa ca vor fi sterse de catre metoda eraseInvisibleObjects () dupa ce au terminat de desenat scena si actualizat scorul prin trimiterea unui mesaj la fereastra hwndControlPanel.

Apoi verificam daca cutiutele noastre zburatoare s-au ciocnit cu un asteroid, daca da - jocul s-a terminat.

Dupa ce scena a fost randata, verificam daca s-a terminat jocul pentru a trimite mesajul corespunzator unei ferestre wndControlPanel si pentru a sterge toate obiectele.

if(isGameOver)
eraseInvisibleObjects();

De asemena mai adaugam 2 case-uri in metoda DlgProcControlPane. Una pt updatare scor iar una pentru procesarea GAME OVER-ului.

case ID_SCORE:
score += 1;
SetDlgItemText(hwnd, ID_SCORE, (LPCSTR)CStr(score).c_str());
break

case ID_GAME_OVER:

break

Bibliografie







Politica de confidentialitate





Copyright © 2024 - Toate drepturile rezervate