4.1. Thiết kế chương trình
Dựa vào các phân tích, ta có thiết kế khung của một chương trình.
Hình 31. Biễu diễn khung thiết kế của chương trình
- Lớp Application là bộ giao tiếp giữa ứng dụng và các nền tảng.
- Lớp FileSystem là lớp trừu tượng được dùng để thực hiện các hành động đọc/ghi tập tin.
-Lớp VideoDriver: là lớp cài đặt các phương thức vẽ hình liên quan đến OpenGLES 2.0.
SVTH: Nhữ Thị Trà My- 08CNTT02 Trang 59
- Lớp Sprite2DManager, Sprite3DManager là lớp chịu trách nhiệm tải các đối tượng 3D cũng như giao diện 2D và vẽ lên trong chương trình.
Ở mỗi nền tảng các đối tượng này sẽ được kế thừa và cài đặt khác nhau nếu cần thiết.
Hình 32. Cách kế thừa các lớp trừ tượng trên các nền tảng khác nhau
Đây là bộ khung cần thiết để chúng ta tiến hành xây dựng các thành phần trong chương trình.
4.2. Vòng lặp trò chơi
Chúng ta thực hiện vòng lặp trò chơi qua hai phương thức của lớp Application, đó là phương thức Update() và Render().
- Phương thức Update: cập nhật trạng thái của trò chơi.
- Phương thức Render: Render nội dung của trò chơi ra màn hình thiết bị.
Do trò chơi bao gồm nhiều giao diện (bảng chọn chính, xem kỷ lục, xem giới thiệu, chơi game…). Chúng ta sẽ khai báo một biến trạng thái để lưu trữ trạng thái hiện tại. Sau đó ở hàm Update và Render, chúng ta sẽ dựa vào biến trạng thái này để cập nhật trò chơi.
void UpdateGame(int type) {
switch (s_iCurrentState) {
SVTH: Nhữ Thị Trà My- 08CNTT02 Trang 60 case GAME_START: UpdateGameStart(type); break; case MAIN_MENU: UpdateMainMenu(type); …
Ứng với mỗi trạng thái ta sử dụng một chỉ thị để xác định hành động hiện tại là Paint hay Render. Ngoài ra mỗi trạng thái cần có các hành động để tải và hủy bỏ các đối tượng trên.
- UPDATE: Cập nhật trạng thái hiện tại. - PAINT: Render trạng thái hiện tại.
- CTOR: Tải các đối tượng cần thiết để vẽ và tính toán trạng thái hiện tại. - DTOR: Hủy bỏ các biến đã sử dụng trong trạng thái hiện tại.
Hình 33. Biễu diễn vòng lặp của trò chơi
4.3. Nội dung trò chơi
Chúng ta định nghĩa các biến trạng thái rồi lần lượt cài đặt các nội dung như sau: Các biến dùng để vẽ và cập nhật trái cây:
enum {ST_NORMAL, ST_CUT, ST_HIDDEN};
struct Fruit { int status; float x; float y; float ax; float ay; int model; };
SVTH: Nhữ Thị Trà My- 08CNTT02 Trang 61
Fruit fruits[MAX];
Các biến dùng để lưu trữ và xử lí nhập từ người chơi: int blades[MAX_BLADE][2];
int bladesLength = 0;
Ta có vòng đời của một trái cây như sau:
Hình 34. Vòng đời của một trái cây
Các chức năng cài đặt:
4.3.1. Khởi tạo vị trí hiện tại của trái cây
// gán gia tốc fruits[i].ay = 0.28f; fruits[i].ax = (rand() % 10 - 5) * 0.01f; // gán vịtrí fruits[i].y = -2.8f; fruits[i].x = (rand() % 90) / 10.0f - 4.0f; // gán trạng thái fruits[i].status = ST_NORMAL;
// gán loại trái cây
fruits[i].model = (rand() % 3) * 3;
4.3.2. Cập nhật trạng thái của trái cây
// Tính toán lại gia tốc fruits[i].ay -= 0.007f; fruits[i].y += fruits[i].ay; fruits[i].x += fruits[i].ax; // Xác định lại trạng thái if (fruits[i].y < -3.0f) { fruits[i].status = ST_HIDDEN; }
SVTH: Nhữ Thị Trà My- 08CNTT02 Trang 62
4.3.3. Kiểm tra va chạm
Chúng ta kiểm tra cắt nhau giữa các điểm thuộc thanh kiếm và đường biên va chạm của trái cây như sau:
// ax, ay là tọa độ của trái cây.
float cx = blades[bladesLength - 2][0] + vx * j * stepLength;
float cy = blades[bladesLength - 2][1] + vy * j * stepLength;
if(fruits[i].status == ST_NORMAL && PointerInRect(cx, cy, ax - 56, ay - 58, 112, 116)) { // Đã cắt nhau…
4.3.4. Tính toán lại các trạng thái sau khi va chạm
fruits[i].ax += 0.02f * vx; fruits[i].ay += 0.02f * vy;
fruits[i].model = fruits[i].model + 1; fruits[i].status = ST_CUT;
Tuy nhiên bây giờ, trái cây của chúng ta đã được cắt làm 2: do đó, chúng ta sẽ có: fruits[i + 1].ax = -fruits[i].ax;
fruits[i + 1].x = fruits[i].x; fruits[i + 1].y = fruits[i].y; fruits[i + 1].ay = -fruits[i].ay;
fruits[i + 1].model = fruits[i].model + 1; fruits[i + 1].status = ST_CUT;
4.4. Đồ Họa
Sơ đồ hoạt động của OpenGLES 2.0 trong chương trình như sau:
Hình 35. Sơ đồ hoạt động của OpenGl ES 2.0 trong chương trình
SVTH: Nhữ Thị Trà My- 08CNTT02 Trang 63