O'zimiz o'yin yaratamiz: Mini gonka (hamma tanidigigan)

Salom. Hozirgi kunda o'yinlar juda ko'p, lekin boshlovchi dasturchilar uchun ushbu maqola ast qotishi mumkin. Biz ushbu maqolada OpenGL va SDL kutubxonasidan foydalanamiz. Chunki bu kutubxona opensource bo'lib Android, iOs, Linux, Windows, MacOS platformalarida ishlay oladi.

SDL haqida shu yerdan o'qishingiz mumkin: www.libsdl.org/

Man bu o'yinni tuzguncha Visual Studio 2010 dan foydalandim. Dasturlash tili C/C++.

Ishni boshlashdan oldin www.libsdl.org/download-2.0.php ssilkadan Development Libraries :: SDL2-devel-2.0.1-VC.zip ni ko'chirib olamiz. Bu SDL kutubxonasi bo'lib dasturlash uchun zarur bo'lgan fayllar mavjud.

Endi VS2010 ni ishga tushirib, CTRL+SHIFT+N ni bosib Visual C++ bo'limidan Win32 ga tegishli Win32 Console Application ni tanlaymiz. Proyekt nomini Gonka deb OK ni bosamiz. Keyin Next ni bosib, «Empty project» ni tanlab FINISH ni bosamiz. Keyin shu proyektni ichiga main.cpp fayl yaratamiz.

Endi c:\devlibs\sdl\ (bu manda siz boshqa joyda qilsangiz ham bo'ladi) ichiga SDL2-devel-2.0.1-VC.zip ni ochib tashlimiz, shunda c:\devlibs\sdl\ ning ichida include, lib papkalari paydo bo'lishi lozim.

VS ga o'tib, ALT+F7 (Project => Properties) ga kiramiz va quyidagi sozlashlarni amalga oshiramiz:

1. Configuration Properties -> C/C++ -> General -> Additional include directories = c:\devlibs\sdl\include\



2. Configuration Properties -> Linker -> General -> Additional library directories = c:\devlibs\sdl\lib\x86\



3. Configuration Properties -> Linker -> Input -> Additional Dependencies = opengl32.lib;SDL2.lib;SDL2main.lib;%(AdditionalDependencies)



4. Va oxirgisi: Configuration Properties -> Debugging -> Environment = PATH=%PATH%;c:\devlibs\sdl\lib\x86\ bu SDL.DLL faylini bizni dastur qo'llash olishi uchun kerak. Agar siz oxirig EXE faylni bitta joyga ko'chirmoqchi bo'lsangiz SDL.DLL ni ham qo'shib ko'chiring. Aks holda SDL.DLL topilmadi degan xato beradi.

Agar sozlashlarni qilib bo'lgan bo'lsangiz main.cpp faylga quyidagini yozing va F5 ni bosing. Agar qizil oyna chiqsa demak hammasi OK, ishlashda davom etamiz.

#include <stdio.h>
#include <stdlib.h>

//GL ni yuklash
#include "windows.h"
#include <gl/GL.h>

//SDL ni yuklash
#include <SDL.h>
#define PROGRAM_NAME "Mini gonka"

/* Xatolikni chiqaradigan funksiya */
void sdldie(const char *msg)
{
    printf("%s: %s\n", msg, SDL_GetError());
    SDL_Quit();
    exit(1);
}
 
int main(int argc, char *argv[])
{
    SDL_Window *mainwindow; /* Oynda o'zgaruvchisi */
    SDL_GLContext maincontext; /* OpenGL konteksi o'zgaruvchisi */
 
    if (SDL_Init(SDL_INIT_VIDEO) < 0) /* Initsalizatsiya SDL. Umuman tekshirish. */
        sdldie("Initsalizatsiya SDL da xatolik"); /* Agar xatolik bo'lsa */
 
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); /* Double buffer qo'shish */
 
    //Oyna yaratish, o'lchami 300x450 bo'lgan
    mainwindow = SDL_CreateWindow(PROGRAM_NAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        300, 450, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    if (!mainwindow) /* Agar yaratib bo'lmasa */
        sdldie("Oynani yaratishda xatolik");
 
    /* OpenGL oynasini yaratish */
    maincontext = SDL_GL_CreateContext(mainwindow);
 
	//oyna o'lchamini berish
	glOrtho(0, 10, 15, 0, -1, 1);
	
    /* Bufferni tozalash rangi */
    glClearColor ( 1.0, 0.0, 0.0, 1.0 );
	glClear ( GL_COLOR_BUFFER_BIT );
    /* Qog'ozni almashtirish */
    SDL_GL_SwapWindow(mainwindow);

	//Main loop, ESC ni bosangiz chiqib ketadi
	SDL_Event e;
	while( SDL_WaitEvent(&e) )
	{
		if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) 
			break;
	}

	//tozalash va chiqish
    SDL_GL_DeleteContext(maincontext);
    SDL_DestroyWindow(mainwindow);
    SDL_Quit();
 
    return 0;
}


Biz hozir o'yin tuzish bilan ovoramiz, keling SDL_GL_DOUBLEBUFFER, SDL_GL_DEPTH_SIZE, glClearColor, GL_COLOR_BUFFER_BIT,… kabi terminlar haqida yana bitta maqola yozaman. Umuman OpenGL qanday ishlaydi mavzusida. Hozircha umumiy qilib tushintirib ketaman. Ya'ni hamma qismini bitta bitta funksiya qilaman va funksiyani nima ish qilishini tushuntiraman.

Bizning gonkamiz quyidagi ko'rinishda bo'ladi:



Ha bu o'sha gonka, ko'pchlikni esidan ham chiqqan bo'lsa kerak. Bu NSF Most Wanted masu boshlovchi dasturchilar uchun undanda azizroq gonka bo'ladi.

Keling endi o'zimizga oddiy maqsad qo'ysak. Bu o'yinni yasash uchun bizga asosiy narsa bu to'rt burcha chizishdir.

Bizning 4 burcha chizadigan funksiyamiz
void draw4burchak(int x, int y, int color)
{
	glBegin(GL_QUADS);

	if (color == 0)
		glColor3ub(0, 0, 0); //qora rang
	else
		glColor3ub(52, 111, 255); // ko'k rang

	glVertex2i(x, y);
	glVertex2i(x + 1, y);
	glVertex2i(x + 1, y + 1);
	glVertex2i(x, y + 1);
	glEnd();
}
ko'rinishida bo'ladi. x, y qaysi nuqtaligi ([0, 0] — chap yuqori nuqta, color = 0 — bu qora, aks holda ko'k rang)

Endiki masala mashinani chizishdir.
void drawcar(int x, int y, int color)
{
	draw4burchak(x + 1, y, color);

	draw4burchak(x, y + 1, color);
	draw4burchak(x + 2, y + 1, color);

	draw4burchak(x + 1, y + 2, color);

	draw4burchak(x, y + 3, color);
	draw4burchak(x + 2, y + 3, color);
}


Atrofidagi yo'llarni chizish
void drawyul(int pos)
{
	pos = pos % 3;
	for(int i = 0; i < 5; i++)
	{
		//chap taraf
		draw4burchak(0, 3 * i + pos, 0);
		draw4burchak(0, 3 * i + pos + 1, 0);

		//o'ng taraf
		draw4burchak(9, 3 * i + pos, 0);
		draw4burchak(9, 3 * i + pos + 1, 0);
	}
}


pos — yo'l harakatini hosil qilish uchun kerak.

Endi o'yinni yuragini yaratamiz ya'ni GAME LOOP ni, buning uchun main loop ni sal o'zgartiramiz. Qolgani o'ynni logikasi.

O'yin kodi:
#include <stdio.h>
#include <stdlib.h>
#include <ctime>

//GL ni yuklash
#include "windows.h"
#include <gl/GL.h>

//SDL ni yuklash
#include <SDL.h>
#define PROGRAM_NAME "Mini gonka"

/* Xatolikni chiqaradigan funksiya */
void sdldie(const char *msg)
{
    printf("%s: %s\n", msg, SDL_GetError());
    SDL_Quit();
    exit(1);
}

void draw4burchak(int x, int y, int color)
{
	glBegin(GL_QUADS);

	if (color == 0)
		glColor3ub(0, 0, 0); //qora rang
	else
		glColor3ub(52, 111, 255); // ko'k rang

	glVertex2i(x, y);
	glVertex2i(x + 1, y);
	glVertex2i(x + 1, y + 1);
	glVertex2i(x, y + 1);
	glEnd();
}

void drawcar(int x, int y, int color)
{
	draw4burchak(x + 1, y, color);

	draw4burchak(x, y + 1, color);
	draw4burchak(x + 2, y + 1, color);

	draw4burchak(x + 1, y + 2, color);

	draw4burchak(x, y + 3, color);
	draw4burchak(x + 2, y + 3, color);
}

void drawyul(int pos)
{
	pos = pos % 3;
	for(int i = -1; i < 5; i++)
	{
		//chap taraf
		draw4burchak(0, 3 * i + pos, 0);
		draw4burchak(0, 3 * i + pos + 1, 0);

		//o'ng taraf
		draw4burchak(9, 3 * i + pos, 0);
		draw4burchak(9, 3 * i + pos + 1, 0);
	}
}

int game_time = 0;
int game_time_interval = 50; //ms
float last_time = 0;
int car_position = 0;

int car1_position = 0, car2_position = 1;
int car1_position_y = 0, car2_position_y = -10;
int counter = 0;


//o'zgaruvchilarni joyiga qaytarish
void reset()
{
	MessageBoxA(NULL, "Yutqazdingiz", "Xabar", MB_OK);

	game_time = 0;
	last_time = 0;
	car_position = 0;

	car1_position = 0;
	car2_position = 1;
	car1_position_y = 0;
	car2_position_y = -10;
	counter = 0;
}

void drawscene()
{
	//vaqtni olish ms da
	SYSTEMTIME st;
	GetSystemTime(&st);
	float cur_time = st.wMinute * 60 * 1000 + st.wSecond * 1000 + st.wMilliseconds;

	//ekranni tozalash
	glClear(GL_COLOR_BUFFER_BIT);

	//obyektlarni chizish
	drawyul(game_time);
	drawcar(3 * car_position + 2, 11, 1);
	drawcar(3 * car1_position + 2, car1_position_y, 0);
	drawcar(3 * car2_position + 2, car2_position_y, 0);

	//ekranga chiqarish
	printf("\rOchko: %d          ", counter);

	//agar game interval ga to'g'ri keldi
	if (cur_time - last_time >= game_time_interval)
	{
		//o'yinni vaqtini oshiirhs
		game_time++;

		//2 ta mashina harakatini hosil qilish
		car2_position_y++;
		car1_position_y++;

		//ekranga ko'rinmiy qolsa, tepaga olib chiqish
		if (car1_position_y >= 15)
		{
			car1_position_y = -5;
			counter++;
		}

		if (car2_position_y >= 15)
		{
			car2_position_y = -5;
			counter++;
		}

		//oxirgi vaqtni saqlash
		last_time = cur_time;
	}

	//o'yinni vaqtini 0 ga tushirish
	if (game_time >= 100)
		game_time = 0;


	//mashina o'rilganligini tekshirish
	if (car1_position == car_position)
	{
		if (car1_position_y >= 9 &&  car1_position_y <= 14)
		{
			reset();
		}
	}
	else if (car2_position == car_position)
	{
		if (car2_position_y >= 9 &&  car2_position_y <= 14)
		{
			reset();
		}
	}
}

int main(int argc, char *argv[])
{

	/* O'yinni to'xtatish o'zgaruvchisi */
	int isGameRunning = 1;

	SDL_Window *mainwindow; /* Oynda o'zgaruvchisi */
    SDL_GLContext maincontext; /* OpenGL konteksi o'zgaruvchisi */
	SDL_Thread *thread; /* Game LOOP paroki */

    if (SDL_Init(SDL_INIT_VIDEO) < 0) /* Initsalizatsiya SDL. Umuman tekshirish. */
        sdldie("Initsalizatsiya SDL da xatolik"); /* Agar xatolik bo'lsa */
 
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); /* Double buffer qo'shish */

    //Oyna yaratish, o'lchami 300x450 bo'lgan
    mainwindow = SDL_CreateWindow(PROGRAM_NAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        300, 450, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
    if (!mainwindow) /* Agar yaratib bo'lmasa */
        sdldie("Oynani yaratishda xatolik");
 
    /* OpenGL oynasini yaratish */
    maincontext = SDL_GL_CreateContext(mainwindow);
 
	//oyna o'lchamini berish
	glOrtho(0, 10, 15, 0, -1, 1);

	/* Bufferni tozalash rangi */
	glClearColor ( 0.93, 0.93, 0.93, 1.0 );

	SDL_Event e;

	//game loop
	while( isGameRunning )
	{
		//klaviatura bosilganligini tekshiradi
		if (SDL_PollEvent(&e))
		{
			if (e.type == SDL_KEYDOWN) 
			{
				switch(e.key.keysym.sym)
				{
					case SDLK_ESCAPE:
						isGameRunning = false;
						break;

					case SDLK_LEFT:
						car_position = 0;
						break;

					case SDLK_RIGHT:
						car_position = 1;
						break;
				}
			}
			
		}

		drawscene();

		SDL_GL_SwapWindow(mainwindow);
	}

	//o'yin tugasa, ya'ni oyna yopilsa
	isGameRunning = 0;

	//tozalash va chiqish
    SDL_GL_DeleteContext(maincontext);
    SDL_DestroyWindow(mainwindow);
    SDL_Quit();
 
    return 0;
}


Umuman olganda bu o'yinni OpenGL va SDL ni ishlatmasdan ham oddiyroq yo'lda tuzsa bo'lardi. Lekin asosiy maqsad OpenGL va SDL dan foydalanishni o'rgatish edi.

Nasib qilsa keyingi maqolalarimda shu o'yinni DEBUG ya'ni ketma-ket analiz qilamiz.

O'yinni ko'chirish

2 комментария

mageUz
Boshlanmasdan tugab qolyabdi, yutqazdingiz degan xabar bilan. Ikki mashina oralig'i 5 birlik, mashina uzunligi 4 birlik, mashinani olib o'tishga ulgurmayabmiz :). Tezlik ham yuqoridi.
0
shranet
Man 55 ta mashinani o'tkazguncha o'ynadim :)
0