NỘI DUNG BÀI VIẾT
Hôm nay, tôi sẽ giúp bạn bắt đầu dự án phát triển trò chơi JavaScript để xây dựng Tetris. Đến cuối bài viết, bạn sẽ có tất cả các nền tảng cần thiết để tiếp tục tự xây dựng.
Học một ngôn ngữ lập trình mới rất khó và không phải ai cũng học theo cách giống nhau. Đối với nhiều người, khám phá thực hành về một dự án hoặc hướng dẫn tương tác là chìa khóa để học tập lâu dài.
Đặc biệt đối với các ngôn ngữ trực quan như JavaScript, việc xây dựng dự án giúp cung cấp ngữ cảnh về cách thức và lý do sử dụng các khái niệm cơ bản trong các ứng dụng khác nhau. Nó cũng giúp xây dựng sơ yếu lý lịch của bạn vì bạn có thể hiển thị cho nhà tuyển dụng một bộ sưu tập các dự án tuyệt vời để thể hiện động lực và kỹ năng của một lập trình viên cho bạn.
Tetris là gì?
Tetris là một trò chơi arcade cổ điển được tạo ra vào năm 1984 bởi Alexey Pajitnov. Trò chơi yêu cầu người chơi phải xoay và di chuyển các mảnh Tetris rơi xuống. Người chơi xóa các đường bằng cách hoàn thành các hàng ngang của khối mà không có ô trống. Nếu các quân cờ đạt đến đỉnh, trò chơi kết thúc.
Tetris là một dự án phổ biến cho phép các nhà phát triển trò chơi có tham vọng thực hành kỹ năng của họ trong một môi trường đơn giản. Ví dụ: bạn sẽ được thực hành thực tế với các khái niệm thiết kế trò chơi cần thiết, chẳng hạn như thiết kế vòng lặp trò chơi và triển khai các cơ chế trò chơi phổ biến như điều khiển của người dùng, theo dõi điểm số và phát hiện va chạm.
Không giống như các trò chơi phức tạp hơn, hành vi và hình ảnh của Tetris rất đơn giản. Điều này cho phép bạn thực hành áp dụng các kiến thức cơ bản về JavaScript để phát triển trò chơi hơn là tìm ra hoạt ảnh hoặc biểu đồ hành vi người chơi phức tạp.
Đối với ví dụ này, chúng tôi sẽ bắt đầu bằng cách sử dụng các công cụ đơn giản nhất và xây dựng độ phức tạp cho đến cuối.
Để tạo Tetris, bạn cần biết:
Tạo kiểu cho trò chơi
Đầu tiên, hãy thiết lập các yếu tố giao diện người dùng cơ bản: khu vực chơi, nút bắt đầu và các chỉ số để theo dõi điểm số, đường và cấp độ. Chúng tôi sẽ sử dụng Flexbox và CSS Grid để định vị các phần tử một cách chính xác.
<!-- index.html -->
<div class="grid">
<canvas id="board" class="game-board"></canvas>
<div class="right-column">
<div>
<h1>TETRIS</h1>
<p>Score: <span id="score">0</span></p>
<p>Lines: <span id="lines">0</span></p>
<p>Level: <span id="level">0</span></p>
<canvas id="next" class="next"></canvas>
</div>
<button onclick="play()" class="play-button">Play</button>
</div>
</div>
Code language: HTML, XML (xml)
// styles.css
.grid {
display: grid;
grid-template-columns: 320px 200px;
}
.right-column {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.game-board {
border: solid 2px;
}
.play-button {
background-color: #4caf50;
font-size: 16px;
padding: 15px 30px;
cursor: pointer;
}
Code language: PHP (php)
Một phần cơ bản của trò chơi những năm 80 là font chữ bitmap rất dễ nhận biết. Press start 2P là một phông chữ miễn phí của Google mà bạn có thể sử dụng để mô phỏng cảm giác.
Để thêm phông chữ, bạn cần liên kết đến nó trong phần <head>
của tài liệu HTML và đặt nó thành phông chữ mong muốn trong CSS style sheet.
<!--index.html-->
<link
href="https://fonts.googleapis.com/css?family=Press+Start+2P"
rel="stylesheet"
/>
Code language: HTML, XML (xml)
// styles.css
* {
font-family: 'Press Start 2P', cursive;
}
Code language: JavaScript (javascript)
Cuối cùng, viết mã cơ sở hạ tầng của bảng trò chơi bằng JavaScript. Bạn sẽ cần thêm các phần tử <script>
vào cuối tài liệu HTML để nhập JavaScript của chúng tôi.
Phần dưới cùng của tài liệu HTML của bạn sẽ trông như thế này:
<script type="text/javascript" src="constants.js"></script>
<script type="text/javascript" src="board.js"></script>
<script type="text/javascript" src="piece.js"></script>
<script type="text/javascript" src="main.js"></script>
</body>
</html>
Code language: HTML, XML (xml)
constants.js
sẽ chứa mã cho bảng chơi tĩnh của bạn. Những giá trị này sẽ không bao giờ thay đổi bất kể hành động của người chơi. Bảng chơi sẽ bao gồm 10 cột và 20 hàng, với kích thước khối là 30.
//constants.js
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = 30;
Code language: JavaScript (javascript)
Sau đó, trong tệp main.js
sẽ bao gồm một số mã để thao tác tài liệu object
, cung cấp giao diện có thể lập trình cho tài liệu HTML. Loại tài liệu này được gọi là Mô hình Đối tượng Tài liệu (DOM) .
Bạn có thể sử dụng DOM để gọi getElementByID
đến cho phép bạn nhắm mục tiêu các phần tử cụ thể và tự động chia tỷ lệ trò chơi để phù hợp với kích thước cửa sổ trình duyệt của người dùng. Điều này sử dụng phần tử canvas
mới với HTML5, cho phép tạo và sử dụng các hình dạng 2D một cách dễ dàng.
Tệp main.js
sẽ trông như thế này:
//main.js
const canvas = document.getElementById('board');
const ctx = canvas.getContext('2d');
// Calculate size of canvas from constants.
ctx.canvas.width = COLS * BLOCK_SIZE;
ctx.canvas.height = ROWS * BLOCK_SIZE;
// Scale blocks
ctx.scale(BLOCK_SIZE, BLOCK_SIZE);
Code language: JavaScript (javascript)
Cuối cùng, bạn sẽ có các tệp sau:
<!--index.html-->
<html>
<head>
<link
href="https://fonts.googleapis.com/css?family=Press+Start+2P"
rel="stylesheet"
/>
</head>
<body>
<div class="grid">
<canvas id="board" class="game-board"></canvas>
<div class="right-column">
<div>
<h1>TETRIS</h1>
<p>Score: <span id="score">0</span></p>
<p>Lines: <span id="lines">0</span></p>
<p>Level: <span id="level">0</span></p>
<canvas id="next" class="next"></canvas>
</div>
<button onclick="play()" class="play-button">Play</button>
</div>
</div>
</body>
Code language: HTML, XML (xml)
//main.js
const canvas = document.getElementById('board');
const ctx = canvas.getContext('2d');
// Calculate size of canvas from constants.
ctx.canvas.width = COLS * BLOCK_SIZE;
ctx.canvas.height = ROWS * BLOCK_SIZE;
// Scale blocks
ctx.scale(BLOCK_SIZE, BLOCK_SIZE);
Code language: JavaScript (javascript)
//constants.js
const COLS = 10;
const ROWS = 20;
const BLOCK_SIZE = 30;
Code language: JavaScript (javascript)
//styles.css
* {
font-family: 'Press Start 2P', cursive;
}
.grid {
display: grid;
grid-template-columns: 320px 200px;
}
.right-column {
display: flex;
flex-direction: column;
justify-content: space-between;
}
.game-board {
border: solid 2px;
}
.play-button {
background-color: #4caf50;
font-size: 16px;
padding: 15px 30px;
cursor: pointer;
}
Code language: PHP (php)
Giao diện người dùng đã hoàn thành
Thiết kế bảng
Bây giờ, hãy đã tạo một vùng chứa cho trò chơi của mình, đã đến lúc bắt đầu viết code logic. Đầu tiên, bạn cần bảng để có thể vẽ các mảnh rơi và theo dõi trạng thái trò chơi.
Bảng và các mảnh đều là ứng cử viên sáng giá cho một lớp. Bạn có thể tạo một phiên bản mới Board
khi bắt đầu một trò chơi mới và một phiên bản mới Piece
mỗi khi một phần mới tham gia trò chơi.
Đối với lớp học Board
, bạn sẽ tạo một tệp board.js
mới. Bạn muốn bảng tham chiếu đến canvas mỗi khi trò chơi bắt đầu nên hãy đưa ctx
vào hàm Board
đã tạo. Bao gồm từ khóa this
để cho phép bạn đặt và truy cập các thuộc tính bên trong ctx
.
//board.js
class Board {
constructor(ctx) {
this.ctx = ctx;
}
}
Code language: JavaScript (javascript)
Bảng Tetris bao gồm nhiều ô riêng lẻ trống hoặc bị chiếm dụng. Bạn hãy đại diện cho các ô trống có 0
và các ô bị chiếm với các số nguyên 1-7
đại diện cho màu sắc.
Để biểu diễn các hàng và cột của bảng, bạn sử dụng mảng 2D (ma trận). Như vậy sẽ có mảng các số nguyên để đại diện cho một hàng và một mảng các hàng để đại diện cho toàn bộ bảng.
Vì tất cả các trò chơi đều bắt đầu với một bảng trống, bạn cần một phương thức trả về một bảng trống. Có thể sử dụng phương thức mảng fill()
dựng sẵn để điền tất cả các phần tử của mỗi hàng vào 0
. Hàm tạo sẽ gọi phương thức này để tất cả các trò chơi bắt đầu trống.
Tệp board.js
của mình bây giờ sẽ giống như sau:
//board.js
class Board {
constructor(ctx) {
this.ctx = ctx;
this.grid = this.getEmptyBoard();
}
getEmptyBoard() {
return Array.from(
{length: ROWS}, () => Array(COLS).fill(0)
);
}
}
Code language: JavaScript (javascript)
Cuối cùng, quay lại main.js
để thêm chức năng trò chơi mới này vào nút chơi.
function play() {
board = new Board(ctx);
console.table(board.grid);
}
Code language: JavaScript (javascript)
Bây giờ bảng trò chơi của bạn đã được thiết lập! Bạn có thể sử dụng console.table()
để xem ma trận điều khiển bảng.
Tạo canvas
Bây giờ tôi sẽ đảm bảo rằng phần tử canvas
của bạn đã sẵn sàng để sử dụng. Khung vẽ cung cấp một khung trống cho trò chơi của mình.
Tôi cũng có thể thêm bối cảnh vẽ 2D trên canvas để vẽ hình dạng, văn bản, hình ảnh và các đối tượng khác. Nó hoạt động tương tự như các chương trình như MS Paint ở chỗ bạn có thể chọn loại cọ vẽ và màu sắc sau đó vẽ bằng mã.
Đầu tiên, tôi muốn đảm bảo rằng canvas có kích thước phù hợp. Nó có kích thước 300×150 pixel theo mặc định nhưng tôi muốn nó mở rộng quy mô bằng cách sử dụng code đã thêm ở trên.
Để làm như vậy, tôi thêm một phân tử canvas
vào index.html
:
<canvas id="canvas"></canvas>
Code language: HTML, XML (xml)
Sau đó, thêm tham chiếu đến phần tử <canvas>
trong phần tử HTML trong DOM (Mô hình đối tượng tài liệu) bằng getElementById
phương pháp này.
let canvas = document.getElementById('canvas');
Code language: JavaScript (javascript)
Bây giờ mình sẽ sử dụng bối cảnh canvas để kết xuất một số phần.
Bạn có thể sử dụng phương thức HTMLCanvasElement.getContext()
này để lấy bối cảnh canvas nơi chúng ta kết xuất đồ họa. Phương thức này cần một đối số nên sẽ chuyển '2d'
để lấy bối cảnh kết xuất 2D.
let ctx = canvas.getContext('2d');
Code language: JavaScript (javascript)
Trước khi có thể vẽ, cần phải chọn màu bằng phương pháp fillStyle()
này.
ctx.fillStyle = 'red';
Code language: JavaScript (javascript)
Sau đó, chúng tôi có thể sử dụng phương thức fillRect()
từ API ngữ cảnh để vẽ một hình chữ nhật đơn giản với màu đỏ đã chọn của mình. fillRect()
nhận 4 đối số: tọa độ x và y nơi bắt đầu của hình dạng và chiều rộng/chiều cao của hình chữ nhật.
ctx.fillRect(x, y, width, height);
Code language: CSS (css)
Vì tất cả các mảnh Tetris đều là tập hợp các hình vuông, bạn có thể sử dụng phương pháp vẽ duy nhất này cho tất cả các mảnh của mình!
Ảnh động
Bây giờ bạn có các công cụ để vẽ đồ họa của mình, bạn phải có khả năng di chuyển chúng.
Canvas sử dụng kết xuất ngay lập tức : Các hình dạng đã vẽ được hiển thị ngay lập tức trên màn hình, nhưng không được lưu trữ dưới dạng các đối tượng hình dạng. Thay vào đó, canvas chỉ nhận dạng hình dạng dưới dạng các pixel được lấp đầy, có nghĩa là chúng ta không thể di chuyển hình dạng trong một mảnh.
Để hiển thị một hình dạng chuyển động, mình phải xóa hình dạng cũ bằng cách sử dụng clearRect()
và vẽ lại nó ở vị trí mới bằng cách sử dụng fillRect()
. Hoạt ảnh canvas về cơ bản giống như hoạt ảnh chuyển động dừng vì chúng di chuyển một chút trong mỗi khung hình.
Hãy xem ví dụ này:
const {width, height} = this.ctx.canvas;
ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 10, 10);
ctx.clearRect(0, 0, width, height);
ctx.fillRect(1, 1, 10, 10);
Code language: JavaScript (javascript)
Ở đây, tôi chọn màu xanh lam làm màu của mình, sau đó tô một hình chữ nhật tại điểm 0,0
. Sau đó, tôi xóa toàn bộ canvas bằng cách sử dụng clearRect()
và chuyển chiều rộng và chiều cao của toàn bộ canvas. Cuối cùng, tôi vẽ một hình chữ nhật mới có cùng kích thước và màu sắc tại 1,1
.
Từ góc nhìn của người dùng, hình chữ nhật di chuyển xuống dưới và sang phải trên màn hình.
Bây giờ bạn đã thiết lập canvas và công cụ vẽ của mình, bạn đã có tất cả các công cụ cần thiết để bắt đầu chơi mã hóa và một bộ sưu tập các phần trò chơi!
Các bước tiếp theo cho trò chơi của bạn
Đây là một khởi đầu tuyệt vời cho dự án danh mục đầu tư tiếp theo của bạn. Bây giờ bạn đã xây dựng nền tảng của trò chơi, bước tiếp theo của bạn là tạo các đối tượng vẽ mỗi phần trò chơi Tetris độc đáo bằng màu sắc của riêng nó.
Mỗi loại quân cờ sẽ được thể hiện bằng ma trận 3×3 trong đó quân cờ là các ô được lấp đầy và không gian trống xung quanh giúp quay xung quanh ô trung tâm.
[2, 0, 0],
[2, 2, 2],
[0, 0, 0];
Code language: CSS (css)
Cách tốt nhất để làm điều này là với một lớp học Piece
.
Bạn cũng sẽ phải thêm hỗ trợ bàn phím để người dùng có thể điều khiển các phần. Cách tốt nhất để làm điều này là sử dụng hỗ trợ sự kiện bàn phím được tích hợp sẵn trong các trình duyệt hiện đại. Bạn có thể đặt chương trình để nghe các sự kiện bàn phím như keydown
, keyup
v.v. ở cấp tài liệu bằng cách sử dụng phương pháp addEventListener()
này.
Sau các bước này, bạn sẽ chuyển sang thêm các tính năng nâng cao hơn như:
- Thêm phát hiện va chạm và bộ ngẫu nhiên mảnh
- Thêm xóa dòng nếu một hàng được lấp đầy
- Theo dõi điểm số, cấp độ và điểm số cao trong quá khứ
- Tăng khả năng phản hồi với JavaScript không đồng bộ
Cảm ơn bạn đã theo dõi bài viết! Chúc các bạn học tập vui vẻ!
Các bạn có thể tham khảo các bài viết hay về JavaScript tại đây.
Hãy tham gia nhóm Học lập trình để thảo luận thêm về các vấn đề cùng quan tâm.
TỔNG HỢP TÀI LIỆU HỌC LẬP TRÌNH CƠ BẢN CHO NGƯỜI MỚI BẮT ĐẦU
KHOÁ HỌC BOOTCAMP JAVA/JAVASCRIPT/PHP TRỞ THÀNH LẬP TRÌNH VIÊN TRONG 5-6 THÁNG