Main Page/soft@G/BallXterminator

 

BallXterminator

Scopul programului

Specificatii generale

Conceperea programului

Schema functionarii aplicatiei

Diagrama obiectuala

Diagrama functionala

Realizarea programului

Structrura de clase

Ghidul utilizatorului

Dezvoltari ulterioare

 

Scopul programului


Programul ballx reprezinta un joc in care scopul este ca jucatorul sa amplaseze cel putin cinci bile de aceeasi culoare pe o linie (orizontala, verticala sau diagonala). Realizarea acestor linii se face prin mutarea bilelor in cadrul unei table de joc alcatuita din casute, fiecare casuta putand contine o bila la un moment dat. Mutarea dintr-o casuta in alta se poate face doar daca exista un drum intre cele doua casute. Trebuie mentionat ca trecerea intre doua casute adiacente se poate face doar pe directia orizontala sau verticala si o bila nu poate trece printr-o casuta in care deja exista o bila. Dupa fiecare mutare efectuata de jucator programul va genera inca trei bile de culori aleatoare pe pozitii aleatoare pe tabla de joc.

Dimensiunea tablei de joc este de 9 casute/9 casute. Bilele pot avea 7 culori diferite.

Specificatii generale


Implementarea programului a fost realizata in mediu Visual C++ pentru a folosi facilitatile lucrului cu clase. Am utilizat, pentru interfata grafica, libraria MFC.

Source Code

Conceperea programului


Ideea de baza care a stat la baza conceperii si realizarii programului a fost o cat mai  usoara si eficace interactiune cu utilizatorul. Aceasta se poate vedea si din realizarea grafica dar ma ales la o analiza amanuntita a structurii interne. Intelegearea stucturii si functionarii este usor de inteles si pentru o persoana ce nu este experta in programarea in mediul Visual C++.

In aceeasi idee am manipulat nu doar structura interna de clase ci si echivalenta externa, "vizuala", a acestor clase. Mai concret am ales o alternativa care mi s-a parut la acel moment cea mai buna solutie in vederea unei programari obiectuale autentice. Adica majoritatii claselor cu care utilizatorul interactuioneaza in mod direct, acolo unde a fost posibil, le-am creat cate un ActiveX care au evenimente si metode nu doar practice ci si foarte intuitive. De exemplu sa consideram controlul ActiveX "XImage", si metoda SetPicture ce primeste ca parametru un string. Aceasta metoda va schimba imaginea continuta in cadrul acestui control ce nu reprezinta altceva decat o casuta in care se poate afla o bila.. Si ramanand tot la cest control, in cadrul lui am impementat si evenimentul de "ClickOn" care va aparea atunci cand se executa un click pe acest control. Din aceste exemple se observa imediat caracterul practic si intuitiv de care vorbeam. Fiecarui astfel de control ActiveX odata adaugat proiectului ii va corespunde o clasa cu metodele, evenimente si campurile corespunzatoare. De exemplu controlului XImage ii corespunde clasa C_XImage.

Controalele ActiveX au fost create in mediul Visual Basic. Am ales aceasta alternativa datorita faptului facilitatilor oferite de acest mediu in crearea unor astfel de controale. Dupa parerea mea acest mediu e foarte bun pentru crearea ActiveX-urilor si poate cel mai potrivit. Facilitatile oferite programatorului, insotite de vastitatea si totodata intuitivitatea procesului de creare m-au determinat sa aleg acest mediu. Principalul "vinovat" care m-a determinat sa aleg utilizarea controalelor a fost lipsa unui control al Visual C-ului care sa satisfaca cerintele mele in ce priveste o manipulare a unor imagini care sa realizeze un echilibru echitabil intre cele doua principii: complexitate si viteza de lucru.

In continuare am descris schematic structura de clase precum si modalitatea de interactiune cu utilizatorul: vezi  Functionarea programului.

Specific faptul ca in cazul metodelor nu am figurat si parametrii, pentru studierea acestora vezi sectiunea Structura de clase.

        Schema functionarii aplicatiei

Diagrama obiectuala

Dupa cum se vede din figura anterioara Utilizatorul va comanda mutarile din cadrul jocului prin intermediul mouse-ului. El va interactiona in mod direct cu fereatra de dialog CBallXDlg si prin intermediul acesteia cu Controlul ActiveX GTable. La randul ei acest control este format din 81 de controale ActiveX XImage, care reprezinta fiecare casuta in care se poate afla o bila. De fapt utilizatorul executa un click pe o astfel de casuta, ActiveX-ul va genera un eveniment de tip "click" pentru controlul GTable, care identifica tipul si sursa evenimentului, il interpreteaza si genereaza un alt eveniment de tip "click" pentru fereastra de dialog, care il va intrepreta si trata, utilizatorul vazand rezultatul actiuni sale. Toate evenimentele petrecute in cadrul controalelor sunt intr-o stransa legatura cu ceea ce se intampla in clasele de la nivelul intern: Element si Table. In cadrul acestor clase operatiile sunt mult mai numeroase, consultarea din exterior realizandu-se prin functii specifice.

Diagrama functionala

In diagrama functionala anterioara este descris algoritmul ce se desfasoara atunci cand jucatorul executa un click pe tabla de joc in pozitia in care va fi mutata o bila selectata anterior iar bila va fimutata in pozitia respectiva, stergandu-se de la vechea pozitie de pe tabla de joc. Iata cum s-ar explica in cateva cuvinte functionarea programului in aceasta situatie.Utilizatorul va efectu prin intermediul mouse-ului un click pe fereasrta CBallXDlg, de fapt pe tabla de joc reprezentata de controlul ActiveX GTable, mai precis pe o casuta din cele 81 din care e formata tabla, casuta ce reprezinta la randul ei un control : XImage. Click-ul efectuat va genera evenimentul OnClick care va fi capturat de GTable si care va genera mai departe la CBallXDlg evenimentul OnClickOnGTable, returnand si coordonatele casutei cu pricina. Acum aplicatia va verifica valoarea care se afla in campul value al clasei Element clasa ce corespunde controlului XImage. Dupa cum am specificat si anterior controlului GTable format din controle XImage corespunde clasa Table ce are in alcatuire o matrice de Elemente. Asadar se verifica prin intermediul campului value daca acest camp are valoarea 0 sau nu, adica daca e o casuta libera sau nu. Valoarea campului Value e returnata aplicatiei. Sa presupunem ca se returneaza 0 adica avem o casuta libera. Prin urmare aplicatia va lansa o interogare asupra matricii Table, si anume functia TouchPoint care va verifica daca exista un drum din pozitia de start aleasa la un pas anterior si pozitia de final aleasa acum. Rezultatul se va returna in variabila  canMoveThere. Sa presupunem acum ca se poate ajuge in casuta respectiva. In continuare se va seta imaginea din vechea casuta, stergandu-se bila, bila care se va desena acum la noua locatie prin metoda SetImage. O data schimbata imaginea in controale, se face actualizarea valorilor si la nivel intern in matricea Table schimband valoarea campului value, prin metoda SetValue. In urma acestor operatii, schimbarile efectuate se vor regasi si pe monitor fiind percepute vizual de catre utilizator.

 Realizarea programului


Vom analiza acest aspect al realizarii aplicatiei urmarind operatiile efectuate in timpul folosirii programului de catre un utilizator.

Astfel o data inceput jocul jucatorului i se cere sa introduca un nume care il va identifica, dupa care pe tabla de joc vor aparea intre trei si cinci bile de diferite culori. De asemenea se observa in partea de jos a ferestrei trei casute ce contin 3 bile ce reprezinta bilele ce vor fi amplasate pe tabla la urmatoarea mutare.

Generarea bilelor se face in functia Generate3Balls(). Functia genereaza trei bile ce reprezinta bilele viitoare. Ma apoi la urmatorul pas aceste trei bile vor fi amplasate pe tabla de joc. Aceasta functie la randul ei foloseste functia RandGenerate7() care va genera un numar aleator intre 1 si 7. Functia RandGenerate7()   a fost astfel conceputa incat fiecare din numerele de la 1 la 7 apar cu aproximativ aceeasi probabilitate. Acelasi principiu de generare l-am utilizat si in functia RandGenerate8() care genereaza numere intre 0 si 8 fiind utilizata la amplasarea aleatoare a bilelor pe tabla de joc. Odata amplasate bilele pe tabla de joc, jucatorul trebuie sa le amplaseze astfel incat sa aseze minim 5 bile pe o linie.

Mutarea bilelor. Mutarea se realizeaza print 2 click-uri succesive pe tabla de joc, respectiv in pozitia initiala si cea finala. La efectuarea unui click pe tabla de joc se apleaza metoda OnClickOnGTable(...).  In cadrul acesteia se verifica daca este primul click sau cel final. In cazul in care este clickul efectuat pe o bila atunci acesta se considera click-ul initial si bila respectiva isi va schimba aspectul aratand utilizatorulu ca bila a fost selectata. Daca click-ul nu a fost executat pe o bila ci pe o casuta goala si exista o bila anterior selectata atunci se incerca deplasarea bilei respective din pozitia initiala in pozitia finala. Regula jocului spune ca deplasarea unei bile dintr-ul loc in altul se poate realiza doar printr-o depalsarea pe orizontala sau verticala, si nu poate trece o bila peste o alta bila, adiuca depalsarea se face casuta cu casuta doar in casutele goale. Deplasarea dintr-un punct in altul al unei bile se poate face fie aratandu-i utilizatorului traseul parcurs, fie mutand direct bila in pozitia finala. Algoritmul care determina faptul ca dintr-un puct se poate ajunge in altul este imlementat in functia TouchPoint(int x, int y, int xf, int yf). Acesta functie verifica posibilitatea atingerii punctului final in mod recursiv. Se foloseste o matrice auziliara mazeTableAux[9][9] care este similara unui labirint in sensul ca fiecarei casute ii corespunde un element care are valoarea 1 daca casuta e ocupata de o bila sau 0 in sens contrar.

Functia amintita va realiza o hasura a matricii pornind din puctul initial, in toate directiile pana la umplerea intregii portiuni posibile. Daca hasura ajunge si in puctul final acesta inseamna ca mutarea este posibila. In cazul in care este selectata optiunea Do Not Animate din meniul Configure, se realizeaza mutarea bilei din pozitia initiala in pozitia finala. In cazul in care insa e selectata optiunea Animate din meniul Configure, atunci se va apela functia AnimateMove() ce va anima miscarea intre cele doua pozitii, aratand si traseul parcurs. Trebuie mentionat faptul ca in anumite cazuri chiar daca este selectata optiunea Animate nu se realizeaza animatia. Acesta se datoreaza faptului ca la calcularea traseului ce urmeaza sa fie parcurs, algoritmul folosit poate dura un timp foarte mare si pentru a nu face utilizatorul sa astepte s-a ales aceasta solutie de a sari peste acest pas. Chiar daca acesta reprezinta un punct slab al programului, situatiile in care apare sunt rare iar efectele sunt aproape insesizabile. Algoritmul folosit pentru afisarea traseului este cel clasic de parcurgere al unui labirint, caruia i-am adus unele optimizari deoarece altfel pentru un labirint de dimensiunile de 9/9, procesul de calcul dura in medie cateva secunde, ceea ce devenea enervant pentru jucator. Astfel ca acum la fiecare pas al procesului se apeleaza o rutina ce decide care este cea mai indicata ruta care sa fie urmata. Totusi jucatorul va avea parte de anumite surprize in ce priveste traseul ales de bila, anume ca acesta nu va fi cel optim. Acest aspect l-am neglijat intentionat deoarece asigura un anume farmec jocului, ale carui principale obiective sunt rapiditatea si amuzamentul. Functia ce cauta ruta se numeste TraceRt(int x, int y, int xf, int yf, int step). 

Operatiile executate de acesta functie sunt asupra matricii mazeTable[9][9], matrice cu aceeasi structura initiala ca si mazeTableAux[9][9]. Cele doua matrici sunt construite in cadrul functiilor TableToMaze() respectiv TableToMazeAux(). O data construita matricea mazeTable si stabilit traseul bilei se executa functia GetFinalPath() in care traseul din matricea mazeTable este transformat in matricea finalPath[2][100], unde traseul este sub forma de perechi de coordonate XY ce vor fi parcurse. Acest lucru este posibil deoarece la construirea trasului in matricea mazeTable fiecare pas este identificat printr-un indice. Odata  acest traseu construit este apelata functia AnimateMove() ce realizeaza deplasarea propriu-zisa.

Bilele ce apar in cadrul casutelor de pe tabla de joc, sunt fisiere de imagini de format bitmap. Aceste fisiere trebuie sa se afle in directorul images in directorul curent al fisierului executabil ballx.exe. Calea spre aceste fisiere se incarca in vectorul ballsColors[15][80] la inceperea unui nou joc. La selectarea unei bile sau atunci cand are loc deplasarea bilei, imaginea se va schimba cu o imagine ce simuleaza miscarea. Aceste imagini trebuie sa se afle in acelasi loc cu cele ce reprezinta bilele statice. Ca exemplu, imaginea bilei rosii se afla in fisierul red.bmp, iar imaginea pentru bila rosie in miscare in fisierul redmove.bmp. Astfel in executia functiei AnimateMove() pe langa deplasare bilei se schimba si imaginea bilei, cu imaginea bilei in miscare.

Un joc este considerat terminat atunci cand nu mai exista nici o casuta libera pe tabla de joc. Acest lucru se verifica in functia CheckForSpaceOnTable() care returneaza TRUE in cazul in care mai exista spatiu pe tabla sau FALSE in sens contrar.

Structrura de clase


1. Clasa Element

Un element reprezinta o casuta de pe tabla de joc cu tot ce implica aceasta.

Structura clasei element este urmatoarea:

class Element 

{

public:

int GetValue();

boolean GetCheck();

boolean GetLineVisibility();

void SetLineVisibility(boolean Value);

void SetCheck(boolean Value);

void SetValue( int Value);

Element();

virtual ~Element();

private:

boolean checked;

boolean lineVisible;

int value;

};

Metodele clasei au urmatoarele functii:

- boolean GetCheck() : returneaza valoarea campului checked;

- boolean GetLineVisibility() : returneaza valoarea campului lineVisible;

- void SetLineVisibility(boolean Value) : seteaza valoarea campului lineVisible;

- void SetCheck(boolean Value) seteaza valoarea campului checked;

 - void SetValue( int Value) : seteaza valoarea campului value;

Campurile clasei au urmatoarea semnificatie:

- checked : se modifica in functie de faptul a respectiva casuta este selectata sau nu;

- lineVisible: linia ce demarceaza casuta este vizibila sau nu;

- value : valoarea corespunzatoare culorii bilei. Fiecarea culori ii corespunde o valoare intreaga;

2. Clasa Table

Corespunde tablei de joc, fiind de fapt o matrice de 9/9 Elemente.

Structura clasei Table este urmatoarea:

class Table

{

public:

Table();

virtual ~Table();

Element element[9][9];

};

Fiecareia din aceste doua clase ii corespunde un contol ActiveX care va fi inclus in aplicatie fiecaruia dintre acestea fiindu-i asociata o clasa. S-a ales aceasta modalitate pentru o manipulare mai intuitiva si mai eficienta a entitatilor.

3. Clasa C_XImage

Corespunde clasei Element, fiind analogul grafic al acestei clase.

class C_XImage : public CWnd

{...

// Operations

public:

CString GetImage();

void Check(BOOL Value);

void SetLineVisibility(BOOL Visible);

void SetPicture(LPCTSTR NewPicture);

void JustSetPicture(LPCTSTR NewPicture);

void DisplayImage();

void Refresh();

void Image1_Click();

};

Metodele acestei clase au pe scurt urmatoarea functionalitate:

Check              : bifeaza casuta;

SetLineVisibility: seteaza vizibilitatea liniei ce incadreaza casuta;

SetPicture        : seteaza si afiseaza imaginea continuta in cadrul casutei;

JustSetPicture : doar seteaza imaginea in cadrul casutei fara a o afisa.

DisplayImage  : afiseaza imagina incarcata cu JustSetPicture;

Refresh                        : reactualizeaza continutul imaginii casutei;

Image1_Click  : genereaza un eveniment in cazul in care s-a executat un click stanga de mouse in cadrul casutei.

4. Clasa C_GTable

Reprezinta echivalentul grafic al clasei Table. Inacelasi fel in care clasa Table este formata dintr-o matrice de Elemente, clasa C_GTable este formata dintr-o matrice de controale corespunzatoare clasei C_XImage.

In linii mari structura acestei clase este urmatoarea:

class C_GTable : public CWnd

{...

// Operations

public:

void SetImageX(short i, short j, LPCTSTR NewImage);

void SetLineVisibility(BOOL Visible);

};

Metodele clasei au urmatoarea semnificatie:

SetImageX                  : seteaza imaginea unei casute specificate.

SetLineVisibility         : seteaza afisarea liniilor ce separa casutele;

Ghidul utilizatorului


In acest capitol  voi prezenta cei cativa pasi ce trebuie urmariti si executati inainte de lansarea in executie a programului.

Configuratie necesara

Programul a fost testat cu succes pe sisteme de operare Windows 95 si Windows 98. De asemenea exista sanse mari sa ruleze fara probleme si pe un sistem Windows 2000. In timpul testarilor, in unele cazuri dupa o functionare mai indelungata au aparut unele probleme pe astfel de sisteme. In cadrul testarilor nu am reusit sa realizez o rulare pe Windows NT.

Configuratie recomandata

Sistem operare : Windows 98.

CPU : >100MHz

Placa grafica : >2Mb

Instalare

Sa presupunem ca atzi copiat jocul in directorul C:\Games\ballx. In acelasi director va trebui sa aveti copiat si directorul images, cel care contine imaginile in format bitmap pe care programul le foloseste in executie.

Un alt lucru important care trebuie retinut este faptul ca programul foloseste controale ActiveX. Acest fapt implica necesitatea inregistrarii acestor controale inaintea executiei programului. Aceste controale sunt : GameTable.ocx, ImageControl.ocx si TitleImage.ocx. Acestea trebuie copiate si ele undeva pe hard-diskul pe care se afla si executabilul. Indicat ar fi sa fie copiate in acelasi director. Deci sa presupunem ca ati copiat aceste fisiere in directorul C:\Games\ballx. Inregistrarea unui control se face folosind comanda regsvr32. Pentru sistemele Win9x exista deja doua fisiere batch care fac acest lucru. Ele sunt : BallXRegist98.bat si UnBallXRegist98.bat. Pentru a avea efect aceste fisiere trebuie mai intai copiate in acelasi fisier cu controalele. Apoi se lanseaza in executie BallXRegist98.bat. Acesta va inregistra controalele pentru joc. Fisierul UnBallXRegist98.bat se va lansa in executie atunci cand se doreste stergerea jocului pentru a goli registri de informatie inutila.

Sa presupunem ca ati lansat in executie BallXRegist98.bat. La executia acestui fisier vor aparea trei mesaje care va vor anunta daca inregistrarea a avut loc cu succes sau nu. In cazul in care nu apare nici un mesaj sau mesajul e unu de eroare inseamna ca va trebui sa le inregistrati controalele manual. Aceasta operatie manuala e necesara si in cazul in care aveti un sistem WinNT sau orice alt sistem in care fisierul regsvr32 nu se afla in calea C:\Windows\System.

Tot in acelasi director cu executabilul ballx.exe, in cazul nostru: C:\Games\BallX, trebuie sa aveti copiate si fisierele : Mfc42d.dll, Mfco42d.dll, Msvcrt.dll si Msvcrtd.dll.

Acestea fiind zise si facute ar trebui ca programul sa ruleze fara probleme.

Utilizare

Inceperea unui nou joc se face alegand din meniu :Xterminate, Start Xterminating . La alegerea acestei obtiuni apare o fereastra in care jucatorul isi introduce numele.

De asemenea, jucatorului ii sunt permise si unele obtiuni de configurare a jocului. Pentru aceasta are la dispozitie meniul Configure. iata in continuare pe scurs obtiunile din acest meniu si semnificatia lor:

·         Show Lines - afiseaza caroiajul;

·         Hide Lines - ascunde caroiajul;

·         Animate - animeaza miscarile bilelor pe tabla de joc;

·         Do Not Animate - Elimina animatia.

Pe langa aceste meniuri mai exista si meniul  Breath cu obtiunile:

·         TOP10 - afiseaza un clasament cu utilizatorii in functie de punctele facute.

·         Get Out - Incheie sesiunea de joc. Aceasta  are exact aceeasi functie ca si butonul RETIRE de pe fereasta de joc.

Dezvoltari ulterioare


Luand in considerare parerile celor ce au testat programul mi-au fost sugerate unele modificari ce ar fi bine-venite. Una dintre acestea ar fi optimizarea traseului bilei atunci cand se doreste animare miscarii bilelor. Totusi si in acest caz parerile sunt impartite. In timp ce unii considera deranjane traseele alese pentru deplasarea bilelor, unii au fost de parere ca aceasta ar asigura haz jocului. Prin urmare, pana la o dezvoltare ulterioara care sa contina optimizarea traseului, cei nemultumiti de aceasta problema pot utiliza obtiunea Do Not Animate din meniul Configure .

O alta problema ce s-ar mai putea supune unor imbunatatiri ar fi cresterea vitezei de calcul a traseului.

Cea mai importanta provocare va fi insa realizarea compatiblitatii cu SO WinNT, pe care deocamdata acest joc nu ruleaza.