Lập trình game là làm gì?

Như tên gọi của nó, lập trình game đơn giản là xây dựng, thiết kế và phát triển game phục vụ người chơi. Công việc cụ thể của lập trình game là lên ý tưởng, phát triển ý tưởng, quản lý dự án, xây dựng kịch bản trò chơi, màn chơi,.. Sau đó là lập trình rồi vẽ đồ họa của game, chơi thử tìm lỗi, sửa lỗi game và cuối cùng là tung ra cộng đồng. Nghề này phù hợp với những bạn yêu thích chơi game, đam mê công nghệ và sáng tạo.

Các ngôn ngữ các bạn có thể sử dụng để lập trình game : C, C++, C#, Java, Python,…

Cơ hội và việc làm

Nghành này không được giảng dạy rộng rãi nên sẽ là thách thức về sự tìm tòi và tự nghiên cứu, tích lũy kinh nghiệm nếu bạn nếu muốn theo. Qua tìm hiểu mình có tổng hợp lại các cơ hội và vị trí việc làm trong lĩnh vực lập trình game để các bạn tham khảo như sau:

  • Game programmer
  • AI programmer
  • Engine programmer
  • Network engineer
  • Graphics programmer

Các bước cơ bản để lập trình game

Game về cơ bản là 1 vòng lặp vô hạn với các chức năng sau :

Hiển thị

Đã là game thì hiển thị không thể thiếu, lúc đầu các bạn chỉ làm cho phần hiển thị thật đơn giản, các bạn đừng quá chú tâm vào việc làm sao cho thật đẹp, chỉ làm tượng trưng thôi, khi nào game hoàn thiện cơ bản thì các bạn hãy chú tâm đến phần đẹp, việc đầu tiên là game phải chạy được đã.

Nhận lệnh từ người chơi, điều khiển

Khi đã hiển thị được các phần của game ra màn hình thì tiếp theo việc các bạn cần làm là điều khiển, việc điều khiển được xem là phần khó nhất và quan trọng nhất của game, ở bước này các bạn muốn game của mình hay, hấp dẫn thì việc ứng dụng các kiến thức toán học, vật lí,… là không thể thiếu. Ví dụ: ứng dụng tốc độ rơi tự do trong game khủng long lúc rớt mạng mà các bạn vẫn quen thuộc, phương trình chuyển động của các nhân vật trong game,…

Xử lí

Đây là 1 bước để tăng thêm độ hấp dẫn các game mà các bạn lập trình, phần này các bạn sẽ thiết lập 1 số các chức năng, vật phẩm (item) , xử lí các trường hợp có thể xảy ra, …

Win, lose

lập trình game về cơ bản là 1 vòng lặp vô hạn, để xử lí việc thắng hay thua game thì các bạn chỉ việc thoát vòng lặp game và thực hiện các chức năng khác.

Code một chương trình di chuyển đối tượng

Có thể các bạn sẽ hơi khó hình dung, sau đây mình sẽ hướng dẫn các bạn code 1 chương trình đơn giản có thể di chuyển 1 đối tượng tự do trên màn hình console, để đơn giản mình sẽ sử dụng ngôn ngữ lập trình C.

Đầu tiên thì như mình đã nói vòng lặp game có dạng:

while (1) {
	//hiển thị
	//nhận lệnh, điều khiển
	//xử lí
	//win,lose
}

Phần1: Khởi tạo

Trước tiên, màn hình console là một màn hình có mặc định nền đen chữ trắng, chiều ngang 80, chiều dọc 25, để đơn giản thì các bạn có thể định nghĩa ngay từ đầu chương trình để dễ gọi và sử dụng :

#define consoleWidth 80
#define consoleHeight 25

Về vấn đề di chuyển chúng ta sẽ tạo 1 kiểu dữ liệu riêng cho việc di chuyển để tiện sử dụng và gọi:

enum DiChuyen{ UP, DOWN, LEFT, RIGHT};

Tiếp theo mình sẽ khởi tạo 1 struct đối tượng:

struct DoiTuong{
	char s[10];      //hình dáng đối tượng
	int x,y;            //ở đây x là hoành độ, y là tung độ của đối tượng
	DiChuyen dc;     // trạng thái di chuyển của đối tượng(đã khởi tạo kiểu dữ liệu 
};

Phần 2: Chương trình chính

Việc khởi tạo đã xong chúng ta sẽ đi vào chương trình chính:

int main(){
	DoiTuong dt;     // Phần khai báo
	// Khởi tạo giá trị đầu cho các phần của đối tượng
	strcpy(dt.s, "Hello"); // khởi tạo hình dạng (ở đây hình dạng là chữ Hello)
	dt.y=0;                         // khởi tạo tung độ đầu
	dt.x=consoleWidth/2;     // khởi tạo hoành độ đầu
	dt.dc=DOWN;                 //khởi tạo trạng thái di chuyển mặc định
	...
}

1. Vòng lặp game

while(1){
	...
	Sleep(200);     //nhịp game 200ms
}

Như các bạn đã biết tốc độ chạy mặc định của chương trình khá là nhanh nên để phù hợp với game thì cần giảm tốc độ chạy với hàm sleep() để điều khiển nhịp game 

Các bạn cần biết 1 số hàm cơ bản trong C như sau:

gotoXY(int column, int line);   //hiển thị đối tượng tại vị trí có tọa độ (column,line)
TextColor(int color)       //tô màu cho đối tượng với mã màu color
kbhit()                   // nhận biết có phím nhấn vào, hàm này sẽ trả về true khi có phím nhấn vào

2. Hiển thị

gotoXY(dt.x, dt.y);         // tọa độ nhảy của đối tượng
prints("%s",dt.s);          // in đối tượng ra màn hình
TextColor(8);                // tô màu với mã màu là 8 (tìm hiểu thêm mã màu trên internet)

3. Điều khiển đối tượng

if(kbhit()) {                // phát hiện có phím nhấn vào
       char key = _getch();            // lưu phím nhấn vào
       if(key == 'A' || key == 'a')            // nhấn A di chuyển sang trái
              dt.dc =LEFT;
       if(key == 'D' || key == 'd')            //nhấn D sang phải
              dt.dc = RIGHT;
       if(key == 'W' || key == 'w')           //nhấn W lên trên
              dt.dc = UP;
       if(key == 'S' || key == 's')             // nhấn S xuống dưới
              dt.dc = DOWN;
}

4. Xử lý

4.1. Xử lí chạm map

if(dt.y >= consoleHeight-1)              //chạm biên dưới
       dt.dc = UP;                                  // đt di chuyển lên trên
else if(dt.y <= 0)                               // chạm biên trên
       dt.dc = DOWN;                          // đt di chuyển xuống dưới
if(dt.x <= 0)                                      // chạm biên trái
       dt.dc = RIGHT;                          // đối tượng di chuyển sang phải
if(dt.x>=consoleWidth-1)                  // chạm biên phải
       dt.dc = LEFT;                            // đối tượng di chuyển sang trái

4.2. Thiết lập trạng thái di chuyển

Vị trí của đối tượng chính là toạ độ, thay đổi toạ độ để đối tượng di chuyển.

if (dt.dc == DOWN)                // DOWN = đi xuống, y tăng dần
       dt.y++;
else if (dt.dc == UP)                 // UP = đi lên y, giảm dần
       dt..y--;
if (dt.dc == LEFT)                   // LEFT = sang trái, x giảm dần
       dt.x--;
if (dt.dc == RIGHT)               //RIGHT = sang phải, x tăng dần
       dt.x++;

Về căn bản đoạn code trên đã đáp ứng hầu hết yêu cầu của một game bao gồm : Hiển thị, Điều khiển, Xử lí. Ban đầu sẽ khó cho các bạn hình dung được cách thực hiện vòng lặp game, nên các bạn đừng chỉ nhìn mà hãy mở máy ra và thực hành ngay để làm quen, hình dung rõ hơn.

Khi đã di chuyển được 1 đối tượng thì ắt hẳn 1 số ý tưởng đã nảy ra trong đầu các bạn rồi phải không?

Đây sẽ là nền tảng đầu, là khởi đầu của một game, các bạn có thể thêm một số phần cho đoạn code trên ví dụ như: vẽ khung giới hạn bằng vòng lặp for, làm cho màu đổi liên tục trong lúc di chuyển, ….

Khi đã hoàn thiện các phần căn bản của vòng lặp game thì việc tiếp theo các bạn cần làm là chú ý đến phần đồ họa của game nếu muốn game của mình hay, hấp dẫn, lôi cuốn người chơi. Hiện nay có rất nhiều app hỗ trợ các chức năng cơ bản cho việc lập trình game các bạn có thể tham khảo trên internet, nhưng nếu các bạn muốn nâng cao khả năng lập trình thì nên tự mình làm.

Ví dụ đây là một game làm trên BuildBox

Demo Lập trình game Snake

Phần 1: Khởi tạo

//định nghĩa màn hình console, ở đây mình định nghĩa màn hình game (giới hạn chạy của game) thay vì màn hình console 
#define consoleWidth 41
#define consoleHeight 26
// tạo 1 enum trạng thái di chuyển
enum TrangThaiDC{ UP, RIGHT, LEFT, DOWN };

// khởi tạo tọa độ
struct ToaDoXY{
	int x;   //hoành độ
	int y;   //tung độ
};
// khởi tạo thức ăn cho rắn mang giá trị là tọa độ xuất hiện
struct ThucAn{
	ToaDoXY td;
};
// khởi tạo con rắn
struct Snake{
	ToaDoXY dot[100];   //tọa độ của con rắn
	int n;              // số đốt của con rắn(độ dài)
	TrangThaiDC tt;     //trạng thái di chuyển
};

Bây giờ là hàm khởi tạo giá trị đầu cho các đối tượng

void KhoiTao (Snake &snake, ThucAn &ta)
 {
	// khởi tạo snake
	snake.n=0;            //số đốt ban đầu bằng 1
	snake.dot[0].x=0;    //hoành độ của đốt đầu tiên 
	snake.dot[0].y=0;    //tung độ của đốt đầu tiên
	snake.tt=RIGHT;      //trạng thái di chuyển mặc định là sang phải

	//khởi tạo giá trị đầu của thức ăn
	ta.td.x=5;     //tung độ
	ta.td.y=10;    //hoành độ
}

Phần 2: Hiển thị

//hàm hiển thị
void HienThi( Snake snake, ThucAn ta, int score) {    //có thêm score để tính điểm
	clrscr();    //xóa màn hình 
	//vẽ khung cho game
	//vẽ biên dưới
	for(int i=0; i<consoleWidth; i++) {
		TextColor(8);  //màu khung
		gotoXY(i; consoleHeight-1);   //tọa độ vẽ
		putchar(219); //tham khảo thêm hàm này trên internet (in kí tự thứ 219 trong ASCII)
	}
	//vẽ biên bên phải
	for(i=0; i<consoleHeight; i++) {
		gotoXY(consoleWidth, i);
		putchar(219);
	}
	//thiết lập tọa độ nhảy, màu sắc và in thức ăn
	TextColor(4);
	gotoXY(ta.td.x, ta.td.y);  // tọa độ thức ăn
	putchar(3);
	//vẽ con rắn
	//vẽ phần đầu
	TextColor(4);
	gotoXY (snake.dot[0].x , snake.dot[0].y ); //tọa độ của đầu snake.dot[0]
	putchar(2);
	//vẽ phần thân
	for(int i=1; i<snake.n; i++) {
		TextColor(4);
		gotoXY ( snake.dot[i].x, snake.dot[i].y); // tọa độ con rắn(phần thân)
		putchar('o');
	}
	//hiển thị điểm số(lưu ý: hiển thị bên ngoài khung game)
	TextColor(10);
	gotoXY(consoleWidth + 2, 8);
	printf("SCORE : %d",score);
	//hiển thị thêm các thứ phụ khác
	gotoXY(consoleWidth + 2, consoleHeight - 2);
	printf("A : LEFT	S : DOWN	D : RIGHT	W : UP");
}

Phần 3: Điều khiển, di chuyển

Cách di chuyển của con rắn là tọa độ đốt sau thế chỗ vị trí tọa độ đốt trước, nên để mô phỏng cách di chuyển cách di chuyển của snake thì chỉ cần truyền tọa độ của đốt trước cho đốt cũ, phần đầu snake.dot[0] đóng vai trò là nguồn truyền trạng thái di chuyển.

//viết hàm điều khiển, di chuyển
void DieuKhien( Snake &snake ) {
	for (int i= snake.n -1 ; i>0; i--) {
		snake.dot[i] = snake.dot[i-1];
	}
	//điều khiển đầu snake(phần thân đã đi theo đầu nên chỉ cần điều khiển phần đầu)
	if (kbhit()) {		     //phát hiện có phím nhấn vào
		int key = _getch();   // lưu kí tự nhấn vào	
		// thiết lập lệnh di chuyển
		if ( key == 'A' || key == 'a' )
			snake.tt= LEFT;
		else if ( key == 'S' || key == 's')
			snake.tt= DOWN;
		else if ( key == 'D' || key == 'd')
 			snake.tt= RIGHT;
		else if ( key == 'W' || key == 'w')
			snake.tt= UP;
	}
	//thiết lập cách di chuyển của các trạng thái di chuyển UP, DOWN, LEFT, RIGHT
	if ( snake.tt == UP )          // UP : giảm tung độ (đi lên)
		snake.dot[0].y--;
	else if ( snake.tt == DOWN )	  //DOWN : tăng tung độ (đi xuống)
		snake.dot[0].y++;
	else if ( snake.tt == LEFT )	  //LEFT: giảm hoành độ (sang trái)
		snake.dot[0].x--;
	else if ( snake.tt == RIGHT )  //RIGHT: tăng hoành độ (sang phải)
		snake.dot[0].x++;
}

Phần 4: Xử lí

Khi con rắn ăn hoa quả (tức là tọa độ snake.dot[0] bằng tọa độ của thức ăn) cần xử lí các chức năng sau: số đốt tăng thêm 1, điểm tăng lên, thức ăn xuất hiện ở vị trí khác, tốc độ game (nhịp game) tăng lên để tăng độ khó,…(có thể thêm tùy các bạn)

//hàm xử lí các tình huống game
void XuLi(Snake &snake, ThucAn &ta , int &speed, int &score) {

	//tăng thêm đốt, tọa độ đốt trước bằng tọa độ đốt sau
	if(snake.dot[0].x == ta.td.x && snake.dot[0].y == ta.td.y) {
		for(int i = snake.n; i>0 ; i--) {
			snake.dot[i] = snake.dot[i-1]; //tọa độ đốt trước bằng tọa độ đốt sau
		}
		snake.n++;        //tăng số đốt lên 1
		//tốc độ tăng lên sau khi ăn mồi
		speed-=-5;
		if(tocdo<=0) {
			tocdo = 0;  // tốc độ đạt tối đa
		}
		//điểm tăng lên 1
		score+=1;
		//trạng thái di chuyển của snake sau khi ăn mồi
		if ( snake.tt == UP )
			snake.dot[0].y--;
		else if ( snake.tt == DOWN )
			snake.dot[0].y++;
		else if ( snake.tt == LEFT )
			snake.dot[0].x--;
		else if ( snake.tt == RIGHT )
			snake.dot[0].x++;
		//tọa độ mới của thức ăn sau khi con rắn ăn(xuất hiện ngẫu nhiên)
		ta.td.x = rand() % (consoleWidth-1);
		ta.td.y = rand() % (consoleHeight-1);
	}
}

Mình sẽ viết 1 hàm xử lí khi con rắn chạm tường (ở đây mình sẽ cho con rắn đi xuyên tường thay vì chạm tường chết) và chạm thân

//xử lí khi con rắn chạm tường, tự cham thân mình
int XuyenTuong( Snake &snake) {
	//đi xuyên tường
	if (snake.dot[0].x < 0)
		snake.dot[0].x = consoleWidth - 2;
	else if ( snake.dot[0].x >= consoleWidth-1 )
		snake.dot[0].x = 0;
	else if (snake.dot[0].y < 0)
		snake.dot[0].y = consoleHeight-2;
	else if (snake.dot[0].y >= consoleHeight-1)
		snake.dot[0].y = 0;
	//xử lí chạm thân	
	for (int i=1; i < snake.n ; i++) {
		if ( snake.dot[0].x == snake.dot[i].x && snake.dot[0].y == snake.dot[i].y) {
			return 1; // trẩ về 1 (game over)
		}
	}
	return 0;
}

Các bạn có thể cải tiến thêm đoạn code trên các chức năng khác như: thêm các vật phẩm, chướng ngại vật, các cách xử lí khác,… tùy sở thích mà các bạn có thể làm rất nhiều thứ thú vị (mình thì thêm các chướng ngại vật di chuyển, thêm chức năng chọn độ khó, các chức năng pause, exit, hiển thị thức ăn lớn nếu ăn 5 thức ăn nhỏ,…).

Leave a Reply

This site uses cookies to offer you a better browsing experience. By browsing this website, you agree to our use of cookies.