Cơ Bản Về Game Loops - Vòng Lặp Game

Cơ Bản Về Game Loops - Vòng Lặp Game

Game loops - vòng lặp game? Nó là gì ?

Game loop - hay vòng lặp game là một trong những Game Design Pattern được sử dụng phổ biến nhất, là "kim chỉ nam" của mọi trò chơi điện tử nói chung hay trò chơi nói rêng. Gần như hầu hết tất cả các trò chơi đều có nó, và gần như ít có cái nào giống hẳn cái nào, thêm vào đó cũng có một vài phần mềm ứng dụng không phải là game cũng dùng nó (Nói không đâu xa, mình vừa học mấy môn dùng nhúng với Arduino cũng toàn là loop cả ^^)

Game loops và Event loops - khác nhau thế nào?

Các ứng dụng hồ họa UI hiện đại ngày nay thường sẽ có một vòng lặp mà theo đó sẽ xử lý các sự kiện tới từ người dùng như sau (chúng ta có thể sẽ không thể thấy nó quá rõ ràng nhưng ở đâu nó cũng có từ C,C++ hay Java, JS,...):

while(true){
	SuKien* su_kien = choSuKien();
	xuLySuKien(su_kien);
}

Trong vòng lặp này, chương trình sẽ đợi một sự kiện đầu vào của người dùng - cái click chuột hay nhấn phím. Sau đó nó sẽ xử lý sự kiện đó thông qua một hàm xử lý riêng biệt với các tác vụ được thực thi khi sự kiện đã diễn ra, và sau đó cho đến khi việc xử lý hoàn tất, thì chương trình sẽ không thể bắt được các sự kiện tiếp theo đến từ người dùng. Việc này với các ứng dụng thường sẽ không phải là vấn đề to tát, nhưng với một trò chơi điện tử, nó sẽ là một vấn đề hơi bị to đấy.

Không như đa số các ứng dụng, các trò chơi điện tử vẫn sẽ tiếp tục chuyển động ngay cả khi người chơi không thực thi bất kì hành động gì. Nếu như bạn cứ ngồi đó và nhìn chằm chằm vào cái màn hình, trò chơi không hề bị đóng băng. Hoạt ảnh vẫn diễn ra, hiệu ứng hình ảnh âm thanh vẫn ở đó. Và nếu như bạn không may mắn như tôi, thì thằng yasuo team địch chắc hẳn vẫn đang hasagi thẳng vô con tướng của bạn và bạn đang bất lực nhìn nó chết một cách không thể đớn đau hơn T_T.

Đây là một trong những mục tiêu chính của một vòng lặp game thực thụ: nó xử lý đầu vào người sử dụng, nhưng không chờ đợi bất kì điều gì. Theo đó vòng lặp sẽ tiếp tục xoay vòng:

while(true){
	xuLyDauVao();
	capNhat();
	xuatDoHoa();
}

Chúng ta sẽ chắt lọc chúng ở phần sau, nhưng các thành phần cơ bản của một vòng lặp trò chơi thì đều ở đây. xuLyDauVao() giám sát bất kì đầu vào người dùng nào xảy ra từ lần gọi trước đó. Sau đó, capNhat() đưa việc mô phỏng trò chơi tiến thêm một bước. Nó thường sẽ cập nhật lại AI và tương tác vật lý(thường theo thứ tự đó). Cuối cùng, xuatDoHoa() vẽ trò chơi ra màn hình để người chơi có thể nhìn thấy điều xảy ra.

Thời gian - vấn đề muôn thủa?

Như tôi và có lẽ bạn đều sẽ có một câu hỏi chung nhất: Vậy cái vòng lặp đó xoay nhanh như thế nào? Mỗi vòng lặp trò chơi giúp phát triển trạng thái của trò chơi bởi một khoảng nào đó. Theo góc nhìn của một cư dân trong thế giới trò chơi, thì cái bộ đếm thời gian của họ đã tiến lên một chút phía trước rồi.

Cùng lúc đó, đồng hồ thực tế của người chơi cũng đang nhảy lên như vậy. Và để tính toán việc một vòng lặp game quay nhanh thế nào so với thời gian thực, thì định nghĩa về "frames per second - khung hình trên giây" cũng vì thế mà ra đời. Hãy liên tưởng như bạn chơi Liên minh đi, hơn 60FPS thì múa yasuo cứ phải gọi là mướt mườn mượt. Còn nếu nó thấp, thì đúng kiểu chơi game stop-motion, giảm cả khả năng múa thông thạo 7 của bạn còn 1/10 :))))

Sẽ có hai yếu tố chính quyết định xem tốc độ khung hình sẽ như thế nào:

  • Khối lượng công việc phải làm cho mỗi khung hình: vật lý phức tạp, hay nhiều đối tượng trò chơi hay độ chi tiết đồ hoạt sẽ kéo dài thời gian xử lý cho mỗi khung hình
  • Tốc độ của nền tảng sử dụng: Bạn dùng CPU như nào, có card rời hay không, phần xử lý âm thanh hay lập lịch của hệ điều hành cũng sẽ gây những ảnh hưởng nhất định

Thời xưa ơi là xưa (khoảng thời kì các bác chơi điện tử bốn nút) thì những trò chơi đó đều sẽ được các nhà lập trình viên lập trình làm sao mà đạt được tốc độ mong muốn với lượng công việc được phân bố vừa đủ cho mỗi khung hình. Nhưng nếu bạn chơi nó với một cỗ máy khỏe hơn hay yếu hơn, thì theo lẽ đương nhiên trò chơi cũng vì đó sẽ tăng tốc hoặc chậm đi. Tất cả điều đó có thể thực hiện được là nhờ việc họ biết một cách chính xác CPU họ dùng là gì và từ đó lập trình chỉ rành riêng cho nó thôi.

Tuy nhiên ngày nay, có rất ít lập trình viên có đủ khả năng biết được chính xác phần cứng mà trò chơi của họ sẽ chạy trên, nhờ vào sự phát triển của công nghệ và sự đa dạng mẫu mã giữa các nhà cung cấp phần cứng. Thay vào đó, trò chơi của chúng ta cần phải bắt kịp và chạy được trên một cơ số các thiết bị khác nhau.

Chính điều này đã dẫn đến một trong những mục tiêu điển hình nữa của vòng lặp game: nó cần phải khiến trò chơi chạy ở một tốc độ nhất định mặc cho những khác biệt trên những phần cứng khác nhau

The Pattern - Mô hình

Một vòng lặp game sẽ chạy một cách liên tục trong suốt phần chơi. Mỗi lượt của vòng lặp, nó sẽ xử lý đầu vào người chơi mà không dừng việc nghe các dữ liệu đầu vào tiếp theo, cập nhật lại trạng thái trò chơi và xuất đồ họa của trò chơi. Nó sẽ theo dấu thời gian trôi qua nhằm kiểm soát tốc độ của phần chơi hiện tại.

Bạn sẽ dùng nó khi nào?

Tôi chắc chắn với bạn là kiểu gì bạn cũng sẽ sử dụng nó đấy. Trong trường hợp bạn như tôi, dùng game engine, thì bạn sẽ không phải tự mình viết nó, nhưng nó chắc chắc vẫn ở đấy.

Ngay cả khi bạn làm game theo lượt, bạn nghĩ bạn sẽ không dùng đến nó. Kiểu như trạng thái trò chơi sẽ không thay đổi cho đến khi người chơi đến lượt của mình? Nhưng đấy là trạng thái game, còn hình ảnh thì âm thanh thì vẫn cập nhật bạn nhé. Các hoạt ảnh và âm thanh vẫn sẽ tiếp tục chạy ngay cả khi trò chơi đang "đợi" cho đến khi đến lượt của bạn.

Luôn nhớ rằng

Vòng lặp game của bạn sẽ cần phải phối hợp với vòng lặp sự kiện ứng với từng nền tảng

Nếu như bạn xây dựng trò chơi của bạn trên một hệ điều hành hay nền tảng mà có Giao diện người dùng và vòng lặp sự kiện được xây dựng sẵn, thì bạn đã có 2 vòng lặp ứng dụng để sử dụng. Chúng cần phải được sử dụng một cách phù hợp

Hoặc bạn có thể tận dụng ngay vòng lặp sự kiện đó và biến nó thành vòng lặp trò chơi của bạn. Nhưng hãy cẩn thận về cách nó hoạt động, việc không nắm rõ cách hoạt động của loại vòng lặp bạn đang sử dụng sẽ dễ dẫn đến việc trò chơi của bạn không thể hoạt động một cách chính xác đâu đấy
Ở phần sau mình sẽ đưa ra một vài ví dụ cách sử dụng và một vài sự triển khai tiêu biểu trên một vài game engine mình đừng động vào, mọi người đón xem nha!