Hướng dẫn xây dựng trò chơi Tetris từ đầu bằng C++ và SFML
Chào mừng bạn đến với hướng dẫn chi tiết về cách xây dựng trò chơi Tetris từ đầu bằng C++ và SFML. Bài viết này sẽ giúp bạn hiểu rõ hơn về cách hoạt động của trò chơi, từ việc tạo ra các hình khối đến việc quản lý logic trò chơi. Hãy cùng bắt đầu nhé!
Giới thiệu về Tetris
Tetris là một trò chơi kinh điển mà ở đó, các hình khối (tetrominós) rơi xuống từ trên cao và bạn cần sắp xếp chúng sao cho không còn dòng nào bị thiếu. Mục tiêu là cố gắng không để các khối chồng lên nhau đến tận đỉnh. Một số tính năng nổi bật của trò chơi:
- Các hình khối rơi xuống và có thể di chuyển sang trái, phải hoặc xoay
- Khi một dòng được lấp đầy, nó sẽ biến mất và bạn sẽ nhận được điểm
- Trò chơi kết thúc khi các khối vượt qua đỉnh màn hình
Trò chơi Tetris không chỉ thú vị mà còn là một công cụ tuyệt vời để học lập trình, với nhiều khái niệm như mảng hai chiều, phát hiện va chạm, và xử lý dữ liệu.
Cấu trúc của trò chơi
1. Mô hình hóa các hình khối
Tetrominós là các hình dạng được tạo thành từ 4 ô vuông. Dưới đây là 7 hình dạng chính của tetrominós:
Tên hình khối | Hình dạng |
---|---|
I | ████ |
J | ██ █ █ |
L | █ █ ██ |
O | ██ ██ |
S | ██ ██ |
T | ███ █ |
Z | ██ ██ |
Mỗi hình khối có thể được đại diện bằng các chỉ số trong một mảng 4x4. Điều này giúp chúng ta dễ dàng quản lý vị trí của chúng trong không gian trò chơi.
2. Cấu trúc trường chơi
Trường chơi là nơi các hình khối sẽ rơi xuống. Ta có thể hình dung nó như một bảng ô vuông, trong đó mỗi ô có thể là trống (0) hoặc đã được lấp đầy (1 đến 7):
cpp
const int M = 20; // Chiều cao của trường chơi
const int N = 10; // Chiều rộng của trường chơi
int field[M][N] = {0}; // Khởi tạo trường chơi với tất cả ô trống
3. Các hình khối đang hoạt động
Mỗi hình khối sẽ được lưu trữ với các thông tin về vị trí của chúng:
cpp
struct Point {
int x, y; // Tọa độ của từng ô trong hình khối
};
Point a[4], b[4]; // a = vị trí hiện tại, b = vị trí trước đó
Các cơ chế chính của trò chơi
1. Kiểm tra va chạm
Một trong những chức năng quan trọng nhất là kiểm tra xem một hình khối có nằm ngoài giới hạn của trường chơi hay không:
cpp
bool check() {
for (int i = 0; i < 4; i++) {
if (a[i].x < 0 || a[i].x >= N || a[i].y >= M) return false;
else if (field[a[i].y][a[i].x]) return false;
}
return true; // Di chuyển hợp lệ
}
2. Di chuyển ngang
Khi người chơi nhấn phím để di chuyển hình khối, ta lưu trữ vị trí hiện tại và kiểm tra xem di chuyển có hợp lệ hay không:
cpp
for (int i = 0; i < 4; i++) {
b[i] = a[i]; // Lưu lại vị trí cũ
a[i].x += dx; // Di chuyển sang vị trí mới
}
if (!check()) {
for (int i = 0; i < 4; i++) {
a[i] = b[i]; // Quay lại vị trí cũ nếu không hợp lệ
}
}
3. Xoay hình khối
Xoay hình khối là một phần quan trọng trong trò chơi và có thể được thực hiện thông qua phép toán ma trận:
cpp
if (rotate) {
Point p = a[1]; // Giả định hình khối thứ hai là tâm xoay
for (int i = 0; i < 4; i++) {
int x = a[i].y - p.y;
int y = a[i].x - p.x;
a[i].x = p.x - x;
a[i].y = p.y + y;
}
if (!check()) {
for (int i = 0; i < 4; i++) {
a[i] = b[i];
}
}
}
4. Rơi tự động
Hệ thống thời gian sẽ tự động làm cho hình khối rơi xuống theo chu kỳ:
cpp
float timer = 0, delay = 0.3; // Thời gian giữa các lần rơi
if (timer > delay) {
for (int i = 0; i < 4; i++) {
b[i] = a[i];
a[i].y += 1; // Di chuyển xuống dưới
}
if (!check()) {
for (int i = 0; i < 4; i++) {
field[b[i].y][b[i].x] = colorNum; // Ghi hình khối vào trường chơi
}
// Tạo hình khối mới
colorNum = 1 + rand() % 7;
int n = rand() % 7;
for (int i = 0; i < 4; i++) {
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
}
timer = 0; // Đặt lại bộ đếm thời gian
}
Xóa dòng hoàn chỉnh
Khi một dòng hoàn chỉnh được tạo thành, chúng ta cần xóa nó ra khỏi trường chơi:
cpp
int k = M - 1; // Vị trí ghi
for (int i = M - 1; i > 0; i--) { // Đọc từ dưới lên
int count = 0;
for (int j = 0; j < N; j++) {
if (field[i][j]) count++;
field[k][j] = field[i][j]; // Sao chép dòng
}
if (count < N) k--;
}
Tạo hình khối ngẫu nhiên
Khi một hình khối được cố định, chúng ta tạo ra một hình khối mới ngẫu nhiên:
cpp
colorNum = 1 + rand() % 7; // Màu ngẫu nhiên
int n = rand() % 7; // Hình khối ngẫu nhiên
for (int i = 0; i < 4; i++) {
a[i].x = figures[n][i] % 2;
a[i].y = figures[n][i] / 2;
}
Kiểm tra Game Over
Trò chơi sẽ kết thúc khi không còn chỗ cho hình khối mới:
cpp
if (!check()) {
// Game Over
}
Kết luận
Xây dựng trò chơi Tetris bằng C++ và SFML không chỉ là một bài học về lập trình mà còn giúp bạn hiểu rõ các khái niệm cơ bản trong phát triển game. Hãy thử nghiệm và cải tiến trò chơi của bạn với các tính năng mới như điểm số, cấp độ khó, hoặc hệ thống dự đoán hình khối tiếp theo. Chúc bạn thành công!
Câu hỏi thường gặp
1. Tôi có thể sử dụng ngôn ngữ nào để phát triển Tetris?
Bạn có thể sử dụng bất kỳ ngôn ngữ lập trình nào, nhưng C++ và SFML là một sự lựa chọn tuyệt vời.
2. Có thể thêm âm thanh vào trò chơi không?
Có, bạn có thể sử dụng thư viện âm thanh của SFML để thêm âm thanh vào trò chơi.
3. Làm thế nào để tôi có thể cải thiện trò chơi này?
Bạn có thể thêm tính năng điểm số, cấp độ khó, hoặc hệ thống pause để làm cho trò chơi thú vị hơn.