Atenție vă rog! Acest site nu este actualizat. Noua versiune: shatalov.su
Continuăm să luăm în considerare Arkanoidul. Înainte de a citi a doua parte, asigurați-vă că ați citit prima parte.
A doua versiune a fost scrisă undeva în douăzeci de ore - un weekend întreg. Modul de joc în sine a fost complet copiat de la versiunea 0.1, despre care am discutat în ultima lecție.
Programul folosește acompaniament muzical. Pentru ieșirea audio, am folosit XAudio2. Din nefericire, acesta este un subiect prea mare pentru a atinge chiar și în scurt timp acest lucru în problema de astăzi. Despre sunet, vom vorbi mult mai târziu.
Nu vă voi da codul. Trebuie să o scrieți singur. Imaginile pentru interfață se află în dosarul cu jocul.
Interfața jocurilor
Interfața versiunea 0.2 se bazează pe ceea ce se găsește în programul Cells v0.3. Dar, în același timp, există mici îmbunătățiri. Să aruncăm o privire la metoda de desenare a elementului de interfață:
Dacă imaginea este albă, atunci nu este copiată deloc. Acest lucru vă permite să creați elemente de interfață de orice formă.
Există 41 de elemente de interfață în program. Cea mai mare parte a scrisului programului pe care îl veți petrece doar pentru a umple interfața:
Cele mai multe articole sunt fie EDITOR, fie MENU. Unele elemente sunt separate - END_GAME. Când începeți să construiți interfața, veți înțelege ce element să plasați.
Elementele sunt stocate într-o serie de indicii (am luat cu o marjă de 50):
Masa însăși este populată în funcția InitGraphics. Funcția nu diferă de numărul de elemente în altceva decât numărul elementelor din celule.
După încărcarea elementelor de interfață, graficele pentru bile și blocuri sunt descărcate (platforma utilizează o culoare neagră solidă). Iată cum puteți încărca o imagine a unuia dintre blocuri:
std :: ifstream este4 ("images / game / metal.bmp", std :: ios :: binary); is4.seekg (54,0); pentru (int i = 19; i> = 0; - i) este4.read (reinterpret_cast (mdTiles [2] [i * 50]), 50 * 4); is4.close ();
Imaginea este citită cu linia (dimensiunea blocului este de 20 * 50).
Interfața este tratată ca și în celule - prin funcțiile CheckInt și IntProc. În acest caz, IntProc este o funcție foarte lungă.
Aici, utilizatorul apasă un buton care mărește numărul de rânduri (mai mult - mai mult). Putem face imediat butonul care reduce numărul de linii active. A doua linie până când atingem nu va - aici mărimea nivelului se schimbă. După aceasta, elementul SAVE_LEVEL poate fi activ - nivelul poate fi salvat numai atunci când s-au făcut modificări. În final, se numește funcția CheckInterface. Să ne uităm la piesa ei:
Observați cum este considerată marginea din dreapta a ultimului bloc: c-> ox + c-> coloane * (c-> blockWidth + c-> xgap) -c-> xgap. Există multe calcule similare în această funcție. Astfel de calcule sunt necesare astfel încât atunci când creșteți indentarea, numărul de blocuri, distanța dintre blocuri, nimic nu iese din ecran. Programare plăcută!
Cel mai important lucru este două linii înainte de a apela CheckInterface. Înainte de modificarea nivelului curent, se reîncarcă. De fiecare dată când utilizatorul dă clic pe "Salvați nivelul", acest nivel este scris într-un fișier. Când reporniți, toate modificările efectuate după ultima salvare sunt pierdute. ReloadLevel încarcă nivelul din fișierul corespunzător.
Afișează blocuri pe ecran
Joc logic
În timpul jocului, aparatul de stare poate fi în una din cele trei stări: NEW_GAME_STATE, START_LEVEL_STATE, RUN_STATE. Există șase state în program:
Când utilizatorul dă clic pe "Joc nou", aparatul de stare merge la NEW_GAME_STATE:
Aici setați nivelul actual, punctele, textul afișat în partea de sus, steagul de înfrângere. Jocul merge în starea START_LEVEL_STATE. Codul pentru starea START_LEVEL_STATE este mult mai complicat decât în versiunea anterioară:
Aici puteți distinge trei părți. În primul rând, platforma și mingea sunt instalate. A doua și a treia parte sunt mult mai interesante.
În a doua parte a codului, valoarea curentului este egală cu 10. Această valoare este primită doar într-un caz - la sfârșitul jocului, când nivelele au fost trecute de la zero la 9 (aceste niveluri pot fi goale). Dacă lvl nu este 10 (au fost nivele goale în joc), atunci un număr dintr-o singură cifră este introdus în șirul de text afișat în partea de sus a ecranului. Dacă lvl este de 10 (toate cele zece niveluri au fost jucate), atunci un număr de două cifre - zece este introdus în linie.
După aceasta, meniul final este vizibil.
Să mergem la codul care urmează verificării până la nivelul final. Vă reamintesc că suntem în starea de pornire a unui nou nivel (START_LEVEL_STATE). Aici trebuie să verificați caseta de deces. Dacă jucătorul este în această stare cu un drapel activ, atunci trebuie să continuați nivelul curent (jucătorul a ratat mingea - minus o singură viață). Dacă steagul morții nu este activ (aceasta înseamnă că jucătorul a trecut nivelul anterior), apoi reîncărcați nivelul.
Ultima parte verifică steagul notHollow (gol - gol). Aici se verifică dacă există cel puțin un bloc în nivel. Dacă nu există blocuri la nivel de bloc, atunci mergeți (currentLevel) la nivelul următor (lvl nu se schimbă).
Iar la sfârșit, du-te la statul RUN_STATE. Nu a existat decât un singur steag - la nivel. În timpul jocului, acesta trebuie să fie zero. Acest steag este setat când jocul este încărcat de pe disc. Cum funcționează, chiar mai jos.
Ultima stare este RUN_STATE. Codul de aici este foarte similar cu cel utilizat în versiunea 0.1. Voi nota doar diferențele:
În timpul jocului, puteți merge la meniu. Când utilizatorul a marcat cel puțin câteva puncte, butonul "Continuare" devine activ. "Joc nou" merge în starea GAME_INIT_STATE și "Continuați" - în RUN_STATE. Când un utilizator intră în meniu, poate da clic pe butonul "Descărcare". În acest moment, flagul levelLoaded este setat. Când utilizatorul dă clic pe Continuați, această casetă de selectare indică faptul că nivelul curentului trebuie inițializat din nou. În același timp, platforma și mingea se vor muta în poziția inițială.
Următoarea piesă interesantă de cod este situată în verificarea mingii pentru platformă:
Un pavilion de moarte este stabilit aici. Apoi, numărul de vieți scade. Acum trebuie să verificați dacă viața a ieșit? Dacă sa terminat, vom arăta fereastra finală. Dacă nu, accesați START_LEVEL_STATE. Îmi amintesc că atunci când se instalează deadFlag, nivelul nu se repornește (acest lucru este foarte important - utilizatorul nu trebuie să înceapă din nou).
Acum trebuie să verificați sfârșitul nivelului. Dacă pe teren au fost doar blocuri goale și grele (care nu pot fi rupte), nivelul sa terminat.
La sfârșitul nivelului, trebuie să faceți mai multe lucruri:
În primul rând, nivelul curent este incrementat. Apoi, starea mașinii de stat finit se schimbă la începutul nivelului. Creste lvl. Aici, pentru a doua oară, se verifică unicitatea / dubla valoare a lvl - dacă utilizatorul a ajuns la nivelul zecea.
După acest bloc, se numește ProcessBall. Funcția a rămas practic neschimbată. Singurul lucru, în această versiune sunt blocuri solide, deci ai nevoie de un test pentru o coliziune cu ei.
În meniu, aș dori să fac câteva comentarii:
În cele din urmă, am ajuns la partea din program pe care aș dori să o subliniez separat.
Sunt zece nivele în joc. Toate nivelurile se află în dosarul niveluri. Fișierul nivelurilor din acest dosar este nivelul salvat. La început am vrut să pot da nume fișierelor, dar apoi apar o serie de întrebări, explicația cărora ar necesita eliberarea a două. Așa că am folosit numele.
Să ne uităm la clasa de nivele:
Aici se schimbă numele (ultimul caracter din nume este un număr). Și pentru fiecare nume, constructorul este chemat. La descărcarea unui fișier, ar trebui luate în considerare două cazuri: fișierul poate conține un nivel și fișierul poate fi gol. În primul caz, scoatem toate variabilele din fișier. Puteți defini singur ordinea variabilelor. Principalul lucru este că ultima este matricea hărții. În cel de-al doilea caz, vom crea un nivel în zbor (eu creez un bloc de 5 * 5 blocuri cu blocuri goale). Iată codul pentru constructor:
În constructor, puteți vedea cum este determinată existența fișierului.
În destructor, trebuie să eliberați memoria de pe hartă.
Metoda LoadLevel este utilizată pentru încărcarea nivelului. În utilizare este ușor diferit de ReloadLevel. LoadLevel este folosit pentru a încărca un joc pe care utilizatorul la salvat anterior. Numele de fișier (întotdeauna nivele) este trecut la metodă.
Metoda ResizeLevel este utilizată pentru a schimba dimensiunea nivelului (numit atunci când harta este schimbată). În acest caz, este creată o matrice temporară, în care este stocată hărțile. harta este ștearsă. Memoria de hartă a mărimii noi este apoi alocată, iar conținutul temporar este copiat pe hartă.
Există un punct important aici. hartă este o matrice unidimensională. Întrebarea este: cum să ștergeți coloana din dreapta? Vă recomandăm să scrieți această metodă singură. Este extrem de important să înțelegem cum funcționează acest lucru. Doar în caz, voi da codul complet. Argumentele sunt transmise unui nou număr de rânduri și coloane:
Adăugarea și eliminarea corectă a coloanelor sunt afișate în verificările cu coloane.
Programul are încă două funcții (nu o metodă): SaveLevel și LoadLevel. Aceste funcții numesc metodele corespunzătoare nivelului curent. În afară de aceasta, fișierul save.sav stochează (sau încarcă de la el) informații despre actualul joc: numărul de vieți, nivelul curent (și lvl și currentLevel), numărul de puncte.
Programul este totul.
Coliziunea a două dreptunghiuri
Este timpul să adăugăm un nou test programelor noastre - o coliziune a două dreptunghiuri. Acest lucru va face programele noastre un pic mai realiste. Coliziunea a două dreptunghiuri este un caz mult mai complicat decât coliziunea unui punct și a unui dreptunghi. Există o mulțime de modalități de a efectua un astfel de control. Vă voi arăta cel mai ușor.
Mai întâi, să vedem cum arată o coliziune a două dreptunghiuri pe o axă - intersecția a două segmente:
Coordonatele acestor segmente arată astfel: 1 (3,6), 2 (5,8). Numărul anterior al corespondenței a arătat că, uneori, pentru a simplifica ecuațiile nu trebuie să utilizați coordonatele, ci valorile minime și maxime. Minimele și maximele acestor segmente vor arăta astfel:
Testul pentru coliziunea a două segmente este foarte simplu: maximul primului segment trebuie să fie mai mare decât cel al celui de-al doilea și maximul celui de-al doilea este mai mare decât cel al primei:
Rețineți că acest test funcționează și aici în acest caz (datorită faptului că folosim min și max):
Acum puteți transfera acest test într-un spațiu bidimensional. Este suficient să adăugați aceeași verificare pentru a doua axă:
Ramane doar sa scriem cea mai simpla functie pentru determinarea numarului minim si maxim de doua numere.
Îmbunătățiți interfața
Astăzi am adăugat o bună ocazie pentru interfața noastră, fără a face aproape nici un efort. Să ne gândim cum să îmbunătățim interfața, fără a o schimba fundamental.
Acum elementul este deprimat dacă testul a fost trecut:
Ie în cazul în care cursorul a fost împinsă peste dreptunghiul care desemnează elementul. Putem adăuga foarte ușor la elementele noastre de interfață de orice formă. Este suficient pentru a face testul, după cele de mai sus dat o mai mult - cu privire la orice pixel a fost de peste: în cazul în care un mod transparent (alb), elementul nu este apăsat. Aceasta ar putea arăta astfel:
Apoi întregul test va arăta astfel:
Acum puteți crea elemente de orice formă. Este suficient să se desemneze numai zone inactive ca alb.
concluzie
Programul a fost scris mai mult de două luni în urmă. Singurul lucru cu care sunt nemulțumit - clasa pentru nivele poate fi simplificată - am multe cod repetitiv. Sper că o puteți face.
exerciții
Arkanoid
aparat foto
celulele
sprite