DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս

«Ես գիտեմ, որ ոչինչ չգիտեմ» Սոկրատես

Ում համար: ՏՏ ոլորտի մարդկանց համար, ովքեր թքում են բոլոր ծրագրավորողների վրա և ցանկանում են խաղալ իրենց խաղերը:

Ինչի մասին: ինչպես սկսել խաղեր գրել C/C++-ով, եթե դա ձեզ անհրաժեշտ է:

Ինչու՞ պետք է կարդալ սա. Հավելվածների մշակումն իմ աշխատանքային մասնագիտությունը չէ, բայց ես ամեն շաբաթ փորձում եմ կոդավորել։ Որովհետև ես սիրում եմ խաղերը:

Բարեւ: Իմ անունն է Անդրեյ Գրանկին, ես DevOps եմ Luxoft-ում: Հավելվածների մշակումն իմ աշխատանքային մասնագիտությունը չէ, բայց ես ամեն շաբաթ փորձում եմ կոդավորել։ Որովհետև ես սիրում եմ խաղերը:

Համակարգչային խաղերի արդյունաբերությունը հսկայական է, այսօր նույնիսկ ավելի շատ խոսակցություններ կան, քան կինոարդյունաբերությունը: Խաղերը գրվել են համակարգիչների զարգացման սկզբից՝ ժամանակակից չափանիշներով, բարդ և հիմնարար զարգացման մեթոդների կիրառմամբ։ Ժամանակի ընթացքում խաղային շարժիչները սկսեցին հայտնվել արդեն ծրագրավորված գրաֆիկայով, ֆիզիկայով և ձայնով։ Նրանք թույլ են տալիս կենտրոնանալ հենց խաղի զարգացման վրա և չանհանգստանալ դրա հիմքի վրա: Բայց դրանց հետ մեկտեղ, շարժիչների հետ միասին, մշակողները «կուրանում են» և դեգրադացվում։ Խաղերի հենց արտադրությունը դրվում է կոնվեյերի վրա։ Եվ արտադրության քանակը սկսում է գերակշռել դրա որակին։

Միևնույն ժամանակ, երբ խաղում ենք ուրիշների խաղերը, մենք անընդհատ սահմանափակվում ենք գտնվելու վայրով, սյուժեով, կերպարներով, խաղային մեխանիզմներով, որոնք ուրիշ մարդիկ են հորինել: Այսպիսով, ես հասկացա, որ ...

… ժամանակն է ստեղծելու ձեր սեփական աշխարհները, որոնք ենթակա են միայն ինձ: Աշխարհներ, որտեղ ես եմ Հայրը, Որդին և Սուրբ Հոգին:

Եվ ես անկեղծորեն հավատում եմ, որ գրելով ձեր սեփական խաղային շարժիչը և դրա վրա խաղը, դուք կկարողանաք բացել ձեր աչքերը, սրբել պատուհանները և մղել ձեր տնակը՝ դառնալով ավելի փորձառու և անբաժան ծրագրավորող։

Այս հոդվածում ես կփորձեմ պատմել ձեզ, թե ինչպես սկսեցի գրել փոքր խաղեր C/C ++-ով, ինչպիսի՞ն է զարգացման գործընթացը և որտեղ եմ ժամանակ գտնում զբաղված միջավայրում հոբբիի համար: Այն սուբյեկտիվ է և նկարագրում է անհատական ​​մեկնարկի գործընթացը: Նյութ անտեղյակության ու հավատքի մասին, այս պահին աշխարհի իմ անձնական պատկերի մասին։ Այսինքն՝ «ադմինիստրացիան պատասխանատու չէ ձեր անձնական ուղեղների համար»։

Պրակտիկա

«Գիտելիքն առանց պրակտիկայի անօգուտ է, պրակտիկան առանց գիտելիքի վտանգավոր է»: Կոնֆուցիուս

Իմ նոթատետրը իմ կյանքն է։


Այսպիսով, գործնականում կարող եմ ասել, որ ինձ համար ամեն ինչ սկսվում է նոթատետրից։ Այնտեղ գրում եմ ոչ միայն իմ ամենօրյա առաջադրանքները, այլև նկարում, ծրագրավորում, գծապատկերներ նախագծում և լուծում խնդիրներ, այդ թվում՝ մաթեմատիկական: Միշտ օգտագործեք նոթատետր և գրեք միայն մատիտով: Այն մաքուր է, հարմարավետ և հուսալի, IMHO:

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Իմ (արդեն լցված) նոթատետրը։ Ահա թե ինչպես է այն նայում. Այն պարունակում է ամենօրյա առաջադրանքներ, գաղափարներ, գծագրեր, դիագրամներ, լուծումներ, սև հաշվապահություն, ծածկագիր և այլն:

Այս փուլում ինձ հաջողվեց ավարտել երեք նախագիծ (սա «վերջնականության» իմ ընկալմամբ է, քանի որ ցանկացած ապրանք կարելի է համեմատաբար անվերջ զարգացնել):

  • Նախագիծ 0: սա Architect Demo 3D տեսարան է, որը գրված է C#-ով, օգտագործելով Unity խաղի շարժիչը: macOS և Windows հարթակների համար:
  • Խաղ 1: Simple Snake (բոլորին հայտնի է որպես «Snake») խաղ Windows-ի համար: գրված է Ք.
  • Խաղ 2: Console խաղ Crazy Tanks (բոլորին հայտնի է որպես «Tanks»), արդեն գրված է C ++ (օգտագործելով դասեր) և նաև Windows-ի տակ:

Project 0 Architect Demo

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
3D Scene Architect Demo

Առաջին նախագիծն իրականացվել է ոչ թե C/C++, այլ C#-ով՝ օգտագործելով Unity խաղային շարժիչը։ Այս շարժիչը այնքան էլ պահանջկոտ չէր սարքաշարի նկատմամբ, որքան Անիրական շարժիչ, և ինձ թվում էր, որ ավելի հեշտ է տեղադրել և օգտագործել: Ես հաշվի չեմ առել այլ շարժիչներ:

Unity-ում ինձ համար նպատակը ինչ-որ խաղ զարգացնելը չէր։ Ես ուզում էի 3D տեսարան ստեղծել ինչ-որ կերպարով: Նա, ավելի ճիշտ Նա (ես մոդելավորել էի այն աղջկան, ում ես սիրահարվել էի =) պետք է շարժվեր և շփվեր արտաքին աշխարհի հետ: Կարևոր էր միայն հասկանալ, թե ինչ է Unity-ն, ինչ է զարգացման գործընթացը և որքան ջանք է պահանջվում ինչ-որ բան ստեղծելու համար: Ահա թե ինչպես է ծնվել Architect Demo նախագիծը (անունը հորինվել է գրեթե բամբասանքից)։ Ծրագրավորումը, մոդելավորումը, անիմացիան, տեքստուրավորումը ինձնից խլել են, հավանաբար, երկու ամիս ամենօրյա աշխատանք:

Ես սկսեցի YouTube-ում ուսուցողական տեսանյութերով, թե ինչպես ստեղծել 3D մոդելներ Blender. Blender-ը հիանալի անվճար գործիք է 3D մոդելավորման համար (և ավելին), որը չի պահանջում տեղադրում: Եվ ահա ինձ շոկ էր սպասվում... Պարզվում է, որ մոդելավորումը, անիմացիան, տեքստուրավորումը հսկայական առանձին թեմաներ են, որոնց վրա կարելի է գրքեր գրել։ Սա հատկապես վերաբերում է հերոսներին: Մատների, ատամների, աչքերի և մարմնի այլ մասերի մոդելավորման համար անհրաժեշտ կլինի անատոմիայի իմացություն: Ինչպե՞ս են դասավորված դեմքի մկանները: Ինչպե՞ս են մարդիկ շարժվում: Ես ստիպված էի ոսկորներ «տեղադրել» յուրաքանչյուր ձեռքի, ոտքի, մատի, բռունցքի մեջ:

Մոդելավորեք կլավիկուլը, լրացուցիչ ոսկրային լծակներ, որպեսզի անիմացիան բնական տեսք ունենա: Նման դասերից հետո հասկանում ես, թե ինչ հսկայական աշխատանք են անում անիմացիոն ֆիլմեր ստեղծողները՝ ընդամենը 30 վայրկյան տեսահոլովակ ստեղծելու համար։ Բայց 3D ֆիլմերը ժամերով տևում են: Եվ հետո մենք դուրս ենք գալիս կինոթատրոններից և ասում. Նրանք կարող էին ավելի լավ անել…» Հիմարներ:

Եվ ևս մեկ բան այս նախագծում ծրագրավորման մասին: Ինչպես պարզվեց, ինձ համար ամենահետաքրքիրը մաթեմատիկականն էր։ Եթե ​​դուք գործարկեք տեսարանը (հղումը դեպի պահեստը նախագծի նկարագրության մեջ), դուք կնկատեք, որ տեսախցիկը պտտվում է աղջկա կերպարի շուրջը գնդով: Տեսախցիկի նման պտույտը ծրագրավորելու համար ես նախ պետք է հաշվարկեի դիրքի կետի կոորդինատները շրջանագծի վրա (2D), իսկ հետո ոլորտի (3D): Զավեշտալին այն է, որ ես ատում էի մաթեմատիկան դպրոցում և գիտեի այն մինուսով: Մասամբ, հավանաբար, այն պատճառով, որ դպրոցում նրանք պարզապես չեն բացատրում ձեզ, թե ինչպես է դժոխային այս մաթեմատիկան կիրառվում կյանքում: Բայց երբ տարված ես քո նպատակով, երազի՛ր, այն ժամանակ միտքը մաքրվում է, բացահայտվում։ Եվ դուք սկսում եք բարդ առաջադրանքները ընկալել որպես հուզիչ արկած: Եվ հետո մտածում ես. «Դե, ինչո՞ւ *սիրելի* մաթեմատիկոսը չէր կարող սովորաբար ասել, թե ուր կարելի է հենվել այս բանաձևերի վրա»:

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Շրջանակի և գնդի վրա կետի կոորդինատները հաշվարկելու բանաձևերի հաշվարկ (իմ նոթատետրից)

Խաղ 1

  • Պլատֆորմ ` Windows (փորձարկվել է Windows 7, 10-ում)
  • Լեզուն, Կարծում եմ՝ մաքուր C-ով է գրված
  • Խաղի շարժիչ. Windows վահանակ
  • Ոգեշնչում: javidx9
  • Պահեստ: GitHub

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Պարզ օձ խաղ

3D տեսարանը խաղ չէ։ Բացի այդ, 3D օբյեկտների (հատկապես կերպարների) մոդելավորումն ու աշխուժացումը երկար ու դժվար է: Unity-ի հետ խաղալուց հետո հասկացա, որ պետք է շարունակեմ, ավելի ճիշտ՝ սկսել հիմքերից: Պարզ և արագ, բայց միևնույն ժամանակ գլոբալ մի բան՝ խաղերի կառուցվածքը հասկանալու համար:

Իսկ ի՞նչ ունենք մենք պարզ ու արագ։ Ճիշտ է, կոնսոլը և 2D: Ավելի ճիշտ՝ նույնիսկ կոնսոլն ու սիմվոլները։ Նորից սկսեցի ոգեշնչում փնտրել համացանցում (ընդհանուր առմամբ համացանցը համարում եմ XNUMX-րդ դարի ամենահեղափոխական ու վտանգավոր գյուտը)։ Ես փորեցի մի ծրագրավորողի տեսահոլովակը, ով սարքեց Tetris կոնսոլը: Եվ իր խաղի նմանությամբ նա որոշել է կտրել «օձին»։ Տեսանյութից ես իմացա երկու հիմնարար բաների մասին՝ խաղի հանգույցը (երեք հիմնական ֆունկցիաներով/մասերով) և ելք դեպի բուֆեր։

Խաղի հանգույցը կարող է այսպիսի տեսք ունենալ.

int main()
   {
      Setup();
      // a game loop
      while (!quit)
      {
          Input();
          Logic();
          Draw();
          Sleep(gameSpeed);  // game timing
      }
      return 0;
   }

Կոդը ներկայացնում է ամբողջ main() ֆունկցիան միանգամից։ Իսկ խաղային ցիկլը սկսվում է համապատասխան մեկնաբանությունից հետո։ Հանգույցում կան երեք հիմնական ֆունկցիաներ՝ Input(), Logic(), Draw(): Սկզբում մուտքագրեք տվյալները Մուտքագրեք (հիմնականում ստեղնաշարերի կառավարում), այնուհետև մուտքագրված տվյալների մշակում Logic, ապա ցուցադրում էկրանին՝ Draw: Եվ այսպես, յուրաքանչյուր շրջանակ: Անիմացիան ստեղծվում է այս կերպ. Դա նման է մուլտֆիլմերի: Սովորաբար մուտքագրված տվյալների մշակումը ամենաշատ ժամանակն է պահանջում և, որքան գիտեմ, որոշում է խաղի կադրերի արագությունը: Բայց այստեղ Logic() ֆունկցիան շատ արագ է։ Հետևաբար, շրջանակի արագությունը պետք է վերահսկվի Sleep() ֆունկցիայի միջոցով gameSpeed ​​պարամետրով, որը որոշում է այս արագությունը:

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
խաղային ցիկլ. Օձի ծրագրավորում նոթատետրում

Եթե ​​դուք մշակում եք խորհրդանշական կոնսոլային խաղ, ապա էկրանին տվյալների ցուցադրումը սովորական հոսքի ելքի «cout»-ի միջոցով չի աշխատի, դա շատ դանդաղ է: Հետևաբար, ելքը պետք է իրականացվի էկրանի բուֆերում: Այնքան ավելի արագ, և խաղը կաշխատի առանց խափանումների: Ճիշտն ասած, ես այնքան էլ չեմ հասկանում, թե ինչ է էկրանի բուֆերը և ինչպես է այն աշխատում: Բայց ես այստեղ կոդ օրինակ կբերեմ, և գուցե մեկնաբանություններում ինչ-որ մեկը կարողանա պարզաբանել իրավիճակը։

Ստանալով էկրանի բուֆեր (եթե ես կարող եմ այդպես ասել).

// create screen buffer for drawings
   HANDLE hConsole = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0,
 							   NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
   DWORD dwBytesWritten = 0;
   SetConsoleActiveScreenBuffer(hConsole);

Ուղղակի ելք դեպի որոշակի գծի գնահատականի գիծ (միավորների ցուցադրման գիծ).

// draw the score
   WriteConsoleOutputCharacter(hConsole, scoreLine, GAME_WIDTH, {2,3}, &dwBytesWritten);

Տեսականորեն այս խաղում ոչ մի բարդ բան չկա, ինձ թվում է մուտքի մակարդակի խաղի լավ օրինակ: Կոդը գրված է մեկ ֆայլում և դասավորված մի քանի ֆունկցիաներով։ Ոչ դասեր, ոչ ժառանգություն: Դուք ինքներդ կարող եք տեսնել ամեն ինչ խաղի սկզբնական կոդում՝ գնալով GitHub-ի պահեստ:

խաղ 2 Crazy Tanks

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Crazy Tanks խաղ

Վահանակով նիշեր տպելը, հավանաբար, ամենապարզ բանն է, որը դուք կարող եք վերածել խաղի: Բայց հետո հայտնվում է մեկ անախորժություն՝ կերպարները տարբեր բարձրություններ և լայնություններ ունեն (բարձրությունը լայնությունից մեծ է)։ Այսպիսով, ամեն ինչ անհամաչափ տեսք կունենա, և ներքև կամ վեր շարժվելը շատ ավելի արագ կթվա, քան ձախ կամ աջ շարժվելը: Այս էֆեկտը շատ նկատելի է «Snake»-ում (խաղ 1): «Տանկերը» (խաղ 2) նման թերություն չունեն, քանի որ այնտեղ ելքը կազմակերպվում է էկրանի պիքսելները տարբեր գույներով ներկելով։ Կարելի է ասել, որ ես ռենդերեր եմ գրել: Ճիշտ է, սա արդեն մի փոքր ավելի բարդ է, թեև շատ ավելի հետաքրքիր:

Այս խաղի համար բավական կլինի նկարագրել էկրանին պիքսելների ցուցադրման իմ համակարգը։ Կարծում եմ՝ սա խաղի հիմնական մասն է։ Եվ մնացած ամեն ինչ կարող եք ինքներդ ձեզ հետ մտածել:

Այսպիսով, այն, ինչ տեսնում եք էկրանին, պարզապես շարժվող գունավոր ուղղանկյունների հավաքածու է:

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Ուղղանկյուն հավաքածու

Յուրաքանչյուր ուղղանկյուն ներկայացված է թվերով լցված մատրիցով: Ի դեպ, կարող եմ առանձնացնել մեկ հետաքրքիր նրբերանգ՝ խաղի բոլոր մատրիցները ծրագրավորված են որպես միաչափ զանգված։ Ոչ թե երկչափ, այլ միաչափ։ Միաչափ զանգվածների հետ աշխատելը շատ ավելի հեշտ և արագ է:

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Խաղի տանկի մատրիցայի օրինակ

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Միաչափ զանգվածով խաղային տանկի մատրիցայի ներկայացում

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Միաչափ զանգվածով մատրիցային ներկայացման ավելի պատկերավոր օրինակ

Բայց զանգվածի տարրերին հասանելիությունը տեղի է ունենում կրկնակի օղակով, կարծես դա ոչ թե միաչափ, այլ երկչափ զանգված է: Սա արվում է, քանի որ մենք դեռ աշխատում ենք մատրիցներով:

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Միաչափ զանգվածի անցում կրկնակի օղակով: Y-ը տողի ID-ն է, X-ը սյունակի ID-ն է

Խնդրում ենք նկատի ունենալ, որ սովորական մատրիցային i, j նույնացուցիչների փոխարեն ես օգտագործում եմ x և y նույնացուցիչները: Այնպես որ, ինձ թվում է, որ դա ավելի հաճելի է աչքին և ավելի պարզ՝ ուղեղին։ Բացի այդ, նման նշումը հնարավորություն է տալիս հարմար կերպով նախագծել օգտագործվող մատրիցները երկչափ պատկերի կոորդինատային առանցքների վրա:

Այժմ պիքսելների, գույնի և ցուցադրման մասին: StretchDIBits ֆունկցիան (Header՝ windows.h; Library՝ gdi32.lib) օգտագործվում է ելքի համար։ Ի թիվս այլ բաների, այս գործառույթին փոխանցվում է հետևյալը. սարքը, որի վրա ցուցադրվում է պատկերը (իմ դեպքում սա Windows վահանակն է), պատկերի ցուցադրման մեկնարկի կոորդինատները, դրա լայնությունը / բարձրությունը և պատկերը: ինքն իրեն bitmap-ի (bitmap) տեսքով, որը ներկայացված է բայթերի զանգվածով: Bitmap որպես բայթերի զանգված:

StretchDIBits() ֆունկցիան աշխատում է.

// screen output for game field
   StretchDIBits(
               deviceContext,
               OFFSET_LEFT, OFFSET_TOP,
               PMATRIX_WIDTH, PMATRIX_HEIGHT,
               0, 0,
               PMATRIX_WIDTH, PMATRIX_HEIGHT,
               m_p_bitmapMemory, &bitmapInfo,
               DIB_RGB_COLORS,
               SRCCOPY
               );

Այս bitmap-ի համար հիշողությունը նախապես հատկացվում է VirtualAlloc() ֆունկցիայի միջոցով: Այսինքն՝ բայթերի անհրաժեշտ քանակությունը վերապահված է բոլոր պիքսելների մասին տեղեկությունները պահելու համար, որոնք հետո կցուցադրվեն էկրանին։

m_p_bitmapՀիշողության bitmap-ի ստեղծում.

// create bitmap
   int bitmapMemorySize = (PMATRIX_WIDTH * PMATRIX_HEIGHT) * BYTES_PER_PIXEL;
   void* m_p_bitmapMemory = VirtualAlloc(0, bitmapMemorySize, MEM_COMMIT, PAGE_READWRITE);

Կոպիտ ասած, bitmap-ը բաղկացած է մի շարք պիքսելներից: Զանգվածի յուրաքանչյուր չորս բայթը RGB պիքսել է: Մեկ բայթ մեկ կարմիր արժեքի համար, մեկ բայթ յուրաքանչյուր կանաչ արժեքի համար (G) և մեկ բայթ յուրաքանչյուր կապույտ գույնի համար (B): Բացի այդ, յուրաքանչյուր ներդիրում կա մեկ բայթ: Այս երեք գույները՝ Կարմիր / Կանաչ / Կապույտ (RGB) - խառնվում են միմյանց հետ տարբեր համամասնություններով, և ստացվում է պիքսելի գույնը:

Այժմ, կրկին, յուրաքանչյուր ուղղանկյուն կամ խաղային օբյեկտ ներկայացված է թվային մատրիցով: Խաղի այս բոլոր առարկաները տեղադրված են հավաքածուի մեջ: Եվ հետո դրանք տեղադրվում են խաղադաշտում՝ կազմելով մեկ մեծ թվային մատրիցա։ Ես մատրիցայի յուրաքանչյուր թիվ քարտեզագրեցի որոշակի գույնի: Օրինակ՝ 8 թիվը կապույտ է, 9 թիվը՝ դեղին, 10 թիվը՝ մուգ մոխրագույն և այլն։ Այսպիսով, մենք կարող ենք ասել, որ մենք ունենք խաղադաշտի մատրիցա, որտեղ յուրաքանչյուր թիվ ինչ-որ գույն է:

Այսպիսով, մենք ունենք մի կողմից ամբողջ խաղադաշտի թվային մատրիցա, իսկ մյուս կողմից՝ պատկերը ցուցադրելու բիթքարտեզ: Առայժմ bitmap-ը «դատարկ» է՝ այն դեռ տեղեկատվություն չունի ցանկալի գույնի պիքսելների մասին։ Սա նշանակում է, որ վերջին քայլը կլինի bitmap-ը լրացնելը յուրաքանչյուր պիքսելի մասին տեղեկատվությամբ՝ հիմնված խաղադաշտի թվային մատրիցայի վրա: Նման վերափոխման պատկերավոր օրինակ է ստորև ներկայացված նկարում:

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Բիթքարտեզը (Pixel matrix) լրացնելու օրինակ՝ հիմնված խաղադաշտի թվային մատրիցայի (Թվային մատրիցայի) վրա հիմնված տեղեկություններով (գունային ինդեքսները չեն համապատասխանում խաղի ցուցանիշներին)

Կներկայացնեմ նաև իրական կոդի մի կտոր խաղից։ Փոփոխական colorIndex-ին օղակի յուրաքանչյուր կրկնության ժամանակ նշանակվում է արժեք (գույնի ինդեքս) խաղադաշտի թվային մատրիցից (mainDigitalMatrix): Այնուհետև գույնն ինքնին գրվում է գունային փոփոխականին՝ ինդեքսի հիման վրա: Ավելին, ստացված գույնը բաժանվում է կարմիր, կանաչ և կապույտ հարաբերակցության (RGB): Եվ նահանջի (pixelPadding) հետ միասին այս տեղեկատվությունը նորից ու նորից գրվում է պիքսելին՝ բիթքարտեզում ձևավորելով գունավոր պատկեր։

Կոդն օգտագործում է ցուցիչներ և բիթային գործողություններ, որոնք դժվար է հասկանալ: Ուստի խորհուրդ եմ տալիս ինչ-որ տեղ առանձին կարդալ, թե ինչպես են աշխատում նման կառույցները։

Bitmap-ը լրացնելը խաղադաշտի թվային մատրիցայի հիման վրա տեղեկատվությամբ.

// set pixel map variables
   int colorIndex;
   COLORREF color;
   int pitch;
   uint8_t* p_row;
 
   // arrange pixels for game field
   pitch = PMATRIX_WIDTH * BYTES_PER_PIXEL;     // row size in bytes
   p_row = (uint8_t*)m_p_bitmapMemory;       //cast to uint8 for valid pointer arithmetic
   							(to add by 1 byte (8 bits) at a time)   
   for (int y = 0; y < PMATRIX_HEIGHT; ++y)
   {
       uint32_t* p_pixel = (uint32_t*)p_row;
       for (int x = 0; x < PMATRIX_WIDTH; ++x)
       {
           colorIndex = mainDigitalMatrix[y * PMATRIX_WIDTH + x];
           color = Utils::GetColor(colorIndex);
           uint8_t blue = GetBValue(color);
           uint8_t green = GetGValue(color);
           uint8_t red = GetRValue(color);
           uint8_t pixelPadding = 0;
 
           *p_pixel = ((pixelPadding << 24) | (red << 16) | (green << 8) | blue);
           ++p_pixel;
       }
       p_row += pitch;
   }

Համաձայն վերը նկարագրված մեթոդի՝ Crazy Tanks խաղում ձևավորվում է մեկ նկար (շրջանակ) և ցուցադրվում է էկրանին Draw() ֆունկցիայի վրա։ Input() ֆունկցիայի մեջ ստեղնաշարերը գրանցելուց և Logic() ֆունկցիայում դրանց հետագա մշակումից հետո ձևավորվում է նոր նկար (շրջանակ): Ճիշտ է, խաղային առարկաները կարող են արդեն այլ դիրք ունենալ խաղադաշտում և, համապատասխանաբար, գծված են այլ տեղում: Այսպես է լինում անիմացիան (շարժումը).

Տեսականորեն (եթե ոչինչ չես մոռացել), հասկանալով խաղի օղակը առաջին խաղից («Օձ») և երկրորդ խաղի էկրանին պիքսելների ցուցադրման համակարգը («Տանկեր») այն ամենն է, ինչ ձեզ հարկավոր է գրելու համար։ Windows-ի համար ձեր 2D խաղերից: Անձայն! 😉 Մնացած մասերը պարզապես հմայքի թռիչք են։

Իհարկե, «Tanks» խաղը շատ ավելի բարդ է նախագծված, քան «Snake»-ը։ Ես արդեն օգտագործել եմ C++ լեզուն, այսինքն՝ դասերով նկարագրել եմ տարբեր խաղի օբյեկտներ։ Ես ստեղծել եմ իմ սեփական հավաքածուն. կոդը կարող եք տեսնել headers/Box.h-ում: Ի դեպ, հավաքածուն, ամենայն հավանականությամբ, ունի հիշողության արտահոսք։ Օգտագործված ցուցիչներ. Աշխատել է հիշողության հետ: Ասեմ, որ գիրքն ինձ շատ օգնեց։ C++-ի սկիզբը խաղերի ծրագրավորման միջոցով. Սա հիանալի սկիզբ է C++-ում սկսնակների համար: Այն փոքր է, հետաքրքիր և լավ կազմակերպված։

Այս խաղը մշակելու համար պահանջվեց մոտ վեց ամիս: Գրում էի հիմնականում ճաշի և աշխատանքի ժամանակ խորտիկների ժամանակ։ Նա նստեց գրասենյակի խոհանոցում, թակեց ուտելիքը և կոդ գրեց։ Կամ տանը ընթրիքի համար: Այսպիսով, ես ստացա նման «խոհանոցային պատերազմներ»: Ինչպես միշտ, ակտիվորեն օգտվեցի նոթատետրից, և դրա մեջ ծնվեցին բոլոր կոնցեպտուալ բաները։

Գործնական մասի վերջում ես կհանեմ իմ նոթատետրից մի քանի սքանավորում։ Ցույց տալու համար, թե կոնկրետ ինչ էի գրում, նկարում, հաշվում, նախագծում…

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Տանկի պատկերի ձևավորում: Եվ սահմանումը, թե յուրաքանչյուր տանկ քանի պիքսել պետք է զբաղեցնի էկրանին

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Իր առանցքի շուրջ տանկի պտտման ալգորիթմի և բանաձևերի հաշվարկ

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Իմ հավաքածուի դիագրամը (հավանաբար, հիշողության արտահոսքով): Հավաքածուն ստեղծվել է որպես Կապված ցուցակ

DevOps C++ և «խոհանոցային պատերազմներ», կամ ինչպես սկսեցի խաղեր գրել ուտելիս
Եվ դրանք արհեստական ​​ինտելեկտը խաղի մեջ խրելու ապարդյուն փորձեր են

Теория

«Նույնիսկ հազար մղոն ճանապարհորդությունը սկսվում է առաջին քայլից» (Հին չինական իմաստություն)

Եկեք պրակտիկայից անցնենք տեսության: Ինչպե՞ս եք ժամանակ գտնում ձեր հոբբիի համար:

  1. Որոշեք, թե իրականում ինչ եք ուզում (ավաղ, սա ամենադժվարն է):
  2. Սահմանել առաջնահերթություններ.
  3. Զոհաբերեք բոլոր «ավելորդները»՝ հանուն ավելի բարձր առաջնահերթությունների։
  4. Ամեն օր շարժվեք դեպի ձեր նպատակները:
  5. Մի սպասեք, որ երկու-երեք ժամ ազատ ժամանակ կլինի հոբբիի համար։

Մի կողմից, դուք պետք է որոշեք, թե ինչ եք ուզում և առաջնահերթություն տալ: Մյուս կողմից, հնարավոր է հրաժարվել որոշ դեպքերից/նախագծերից՝ հօգուտ այս առաջնահերթությունների։ Այսինքն՝ ստիպված կլինեք զոհաբերել ամեն ինչ «ավելորդ»։ Ինչ-որ տեղ լսել եմ, որ կյանքում պետք է լինի առավելագույնը երեք հիմնական գործունեություն. Այդ ժամանակ դուք կկարողանաք լավագույնս վարվել դրանց հետ։ Եվ լրացուցիչ նախագծերը/ուղղությունները կսկսեն ծանրաբեռնել կորնին: Բայց այս ամենը, հավանաբար, սուբյեկտիվ է և անհատական։

Կա որոշակի ոսկե կանոն՝ երբեք մի ունեցեք 0% օր: Ես այդ մասին իմացա ինդի ծրագրավորողի հոդվածում: Եթե ​​դուք աշխատում եք նախագծի վրա, ապա ամեն օր ինչ-որ բան արեք դրա մասին: Եվ կարևոր չէ, թե որքան եք վաստակում: Գրեք մեկ բառ կամ մեկ տող կոդ, դիտեք մեկ ուսուցողական տեսանյութ կամ մեխեք մեկ մեխը գրատախտակին, պարզապես ինչ-որ բան արեք: Ամենադժվարը սկսելն է: Երբ սկսեք, հավանաբար կանեք մի փոքր ավելին, քան ցանկանում էիք: Այսպիսով, դուք անընդհատ շարժվելու եք դեպի ձեր նպատակը և, հավատացեք, շատ արագ: Ի վերջո, ամեն ինչի հիմնական արգելակը հետաձգումն է:

Եվ պետք է հիշել, որ պետք չէ թերագնահատել ու անտեսել ժամանակի ազատ «թափը» 5, 10, 15 րոպեում, սպասել մեկ-երկու ժամ տեւողությամբ ինչ-որ մեծ «գերանների»։ հերթ կանգնե՞լ ես։ Մտածեք ինչ-որ բան ձեր նախագծի համար: Դուք բարձրանում եք շարժասանդուղքով: Գրեք ինչ-որ բան նոթատետրում: Դուք ուտում եք ավտոբուսում: Լավ, կարդացեք մի հոդված: Օգտագործեք ամեն հնարավորություն։ Դադարեցրեք կատուներ և շներ դիտել YouTube-ում: Մի խառնվեք ձեր ուղեղին:

Եվ վերջինը. Եթե ​​այս հոդվածը կարդալուց հետո ձեզ դուր եկավ խաղեր ստեղծելու գաղափարը առանց խաղի շարժիչների օգտագործման, ապա հիշեք Քեյսի Մուրատորի անունը: Այս տղան ունի կայքը. «Դիտել -> ՆԱԽՈՐԴ ԴՐՎԱԾՆԵՐ» բաժնում դուք կգտնեք զարմանալի անվճար վիդեո ձեռնարկներ, թե ինչպես ստեղծել պրոֆեսիոնալ խաղ զրոյից: Windows-ի համար Intro to C-ի հինգ դասերից դուք կարող եք ավելին սովորել, քան համալսարանում սովորելու հինգ տարին (ինչ-որ մեկը այս մասին գրել է տեսանյութի տակ մեկնաբանություններում):

Քեյսին նաև բացատրում է, որ զարգացնելով ձեր սեփական խաղային շարժիչը, դուք ավելի լավ կհասկանաք գոյություն ունեցող շարժիչների մասին: Շրջանակների աշխարհում, որտեղ բոլորը փորձում են ավտոմատացնել, դուք կսովորեք, թե ինչպես ստեղծել, ոչ թե օգտագործել: Հասկացեք համակարգիչների էությունը: Եվ դուք կդառնաք նաև շատ ավելի խելացի և հասուն ծրագրավորող՝ պրոֆեսիոնալ:

Հաջողություն ձեր ընտրած ճանապարհին: Եվ եկեք աշխարհն ավելի պրոֆեսիոնալ դարձնենք:

Հեղինակ: Գրանկին Անդրեյ, DevOps



Source: www.habr.com