Hẳn là các anh em đã quá quen thuộc với trò chơi “Rắn săn mồi” à "Mãng xà online" thường có sẵn điện thoại di động 1200, 1202 thời ngày xửa này xưa rồi phải không nào. Có bao giờ các bạn nghĩ là sẽ tự tay viết trò chơi này chưa để có thể giải trí hoặc khoe với bạn bè chưa?

Hôm nay mình sẽ chia sẻ cho các bạn từng bước thực hiện để tạo game “Mãng xà online” này với HTML5 Canvas nhé.

Đầu tiên thì chúng ta setup 1 số file cần thiết, chơi game không thể nào thiếu giao diện được phải không nào

index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Snake Game</title>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<script src="./main.js"></script>

</html>

Trong file html, đơn giản chúng ta có thẻ canvasid="canvas" và thẻ script link đến file main.js

Setup gameboard

OK, bây giờ chúng ta sẽ tiến hành setup canvas

main.js

const canvas = document.getElementById("canvas");
canvas.width = 600;
canvas.height = 600;
canvas.style.border = '1px solid gray';

const ctx = canvas.getContext("2d");

Đầu tiên thì chúng ta sẽ truy cập vào canvas thông qua phương thức document.getElementById("canvas").

Sau đó set widthheight cho phần tử mà chúng ta vừa mới truy cập, để cho màu sắc hơn thì mình có set border color cho canvas

canvas.style.border = '1px solid gray'

Và quan trọng hơn là chúng ta cần phải truy cập vào phương thức vẽ 2d của canvas để có thể vẽ hình

const ctx = canvas.getContext("2d");

Để thực hiện game "Mãng xà online" này, chúng ta cần chia game board ra thành các ô vuông (block)

let width = canvas.width;
let height = canvas.height;

//Setting the block
let blockSize = 20;
let widthInBlocks = width / blockSize;
let heightInBlocks = height / blockSize;

Ở đây chúng ta sẽ chia game board thành các hàng và các cột để tạo các block, mỗi block có kích thước = 20

Các giá trị widthInBlocks, heightInBlocks chính là số cột và số hàng của game board sau khi đã tính toán

Hiển thị score

function drawScore() {
    ctx.font = "bold 20px Arial";
    ctx.fillStyle = "black";
    ctx.fillText(`Điểm: ${score}`, blockSize, blockSize * 2);
}

Để hiển thị score chúng ta định nghĩa func drawScore(). Trong func này chúng ta set một số thuộc tính khi hiển thị score như font (ctx.font), color (ctx.fillStyle), position (ctx.fillText)

Tiếp theo chúng ta thử kiểm tra xem phần score được hiển thị trên web như thế nào

let score;

//Start Game function
function init() {
    score = 0;
    drawScore();
}

window.onload = init;

Ở đây chúng ta định nghĩa function init(), function này sẽ bao gồm tất cả các giá trị khởi tạo ban đầu khi bắt đầu game.

Bên trong function này đầu tiên chúng ta khởi tạo giá trị score = 0 và gọi function drawScore() để hiển thị lên giao diện

Tiếp theo chúng ta sẽ lắng nghe sự kiện onload và gọi function init (onload là sự kiện khi trình duyệt đã load xong html, css, javascript, image, ...)

Kết quả ban đầu chúng ta được khi như sau

Vẽ game board và score

Bây giờ chúng ta sẽ đi định nghĩa từng đối tượng của game

Đầu tiên chính là đối tượng block, đây là thành phần cơ sở dùng để tạo ra các đối tượng khác (food, snake)

Đối tượng Block

class Block {
    constructor(col, row) {
        this.col = col;
        this.row = row
    }

Trong constructor , khởi tạo đối tượng block với col (số cột), row (số hàng)

Bên trong class Block, định nghĩa 2 method:

  • drawSquare() : để vẽ khối block

  • drawCircle() : để vẽ hình tròn bên trong khối block

drawSquare(color) {
    let x = this.col * blockSize;
    let y = this.row * blockSize;

    ctx.beginPath();
    ctx.fillStyle = color;
    ctx.rect(x, y, blockSize, blockSize);
    ctx.fill();
}

drawCircle(color) {
    // Tính toán vị trí tâm
    let centerX = this.col * blockSize + blockSize / 2;
    let centerY = this.row * blockSize + blockSize / 2;

    ctx.beginPath();
    ctx.fillStyle = color;
    ctx.arc(centerX, centerY, blockSize / 2, 0 , Math.PI * 2, false);
    ctx.fill();
}

Đối tượng Food

class Food {
    constructor(color) {
        this.position = new Block(10, 10);
        this.color = color;
    }

    draw() {
        this.position.drawCircle(this.color);
    }
}

Class Food giúp chúng ta định nghĩa các phương thức và thuộc tính liên quan đến đối tượng food (thức ăn)

Constructor giúp chúng ta khởi tạo nên đối tượng với các thuộc tính ban đầu. Trong này chúng ta có 2 thuộc tính là position (vị trí ban đầu của food) và color (màu sắc)

Tiếp theo là method draw() dùng để vẽ food. Ở đây chúng ta định nghĩa food là 1 đối tượng block hình tròn thì chỉ việc gọi method drawCircle() là xong

Đối tượng Snake

class Snake {
    constructor(color) {
        this.segments = [new Block(7,5), new Block(6,5), new Block(5,5)];
        this.color = color;
    }

    draw() {
        this.segments.forEach(segment => segment.drawSquare(this.color));
        this.segments[0].drawSquare('green');
    }
}

Trong constructor của class Snake, ta định nghĩa mảng segments, đây là mảng lưu giữ vị trí ban đầu của con rắn

Method draw() giúp chúng ta vẽ snake trên giao diện, để vẽ snake rất đơn giản, chúng ta chỉ cần duyệt qua mảng this.segments, với phần tử trong mảng này đều là 1 block nên chúng ta gọi method drawSquare() để vẽ

Riêng với thành phần đầu snake thì chúng ta hiển thị màu khác để dễ quan sát trong quá trình chơi game

let score;
let snake;
let food;

//Start Game function
function init() {
    score = 0;

    snake = new Snake('yellow');
    food = new Food('red');

    drawScore();
    snake.draw();
    food.draw();
}

Trong func init() chúng ta khởi tạo 2 đối tượng snakefood từ các class đã được định nghĩa trước đó

snake = new Snake('yellow');
food = new Food('red');

Với mỗi đối tượng vừa được khởi tạo chúng ta chỉ cần gọi method draw() tương ứng để vẽ các đối tượng trên game board

snake.draw();
food.draw();

Và đây là kết quả đến bước này của chúng ta

Hiển thị snake và food

Trông cũng ổn ổn rồi đấy chứ


Ở phần tiếp theo của bài viết này, mình sẽ hướng dẫn các bạn các chức năng còn lại bao gồm :

  • Di chuyển snake
  • Kiểm tra va chạm của snake với thân và với thành game board
  • Xử lý ăn điểm
  • ...

Source code của phần này mình để ở đây nhé : https://github.com/buihien0109/snake/tree/master/part-1

Các bạn có thể tham khảo thêm khóa học này nhé:

  • Javascript căn bản - Tổng hợp 12 game huyền thoại - tại đây.
  • Lập trình Game Javascript (trực tuyến có tương tác) - tại đây.