Chào các bạn! Mùa đông năm nay tới muộn hơn mọi năm, nhưng nó lạnh và buốt giá hơn những năm trước nhiều!

Bạn đã có gấu chưa? nếu chưa, thì bạn có đứa bạn thân khác giới nào đó để ngồi thật sát cho đỡ lạnh chứ? nếu câu trả lời vẫn là không. Thì bài viblo này chính là dành cho bạn đó =)))

Bạn hãy cùng mình tạo ra trò chơi thú vị này nhé, nó sẽ giúp cái đầu của bạn phải hoạt động hết khả năng để có thể đạt được điểm cao, lúc đó bạn sẽ thấy ấm hơn chút đỉnh đó :v

Không nói vòng vo nữa, vào việc thôi 😉

Vậy, HTML5 là gì và có thể làm game không? Mình xin giải đáp 2 câu hỏi này như sau:

1. Hãy click vào dòng bạn đang đọc này để hiểu HTML5 là gì

2. Nó hoàn toàn có thể làm game các bạn nhé 😉

Ok, giờ thì đã hiểu đôi chút về HTML5, đã biết nó có thể làm game, và việc tiếp theo là tạo môi trường để có thể làm game thôi nào 😉

1. Download Visual Studio Code (mình dùng ubuntu vì vậy dùng bản này, các bạn có thể dùng các bản khác cho các nền tảng hệ điều hành khác nhau nhé)

Download Visual Studio Code

2. Tạo 1 file có tên gọi là crazemath.html (tạo 1 file bình thường rồi đổi tên và phần mở rộng là xong)

3. Mở file đó bằng visual studio code mà chúng ta đã cài đặt ở phía trên.

4. Viết những dòng code đầu tiên định dạng cho game.

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

    <head>
        <meta charset="UTF-8">
        <title>Craze Math</title>
    </head>

    <body>
        <script>
        </script>
    </body>
</html>

5. Khai báo các biến cần thiết cho game:

//kích thước của game
var WIDTH = 480,
       HEIGHT = 800;
//biến đồ họa
var canvas, ctx;
//nút bấm trong game
var btnTrue, btnFalse;
//đối tượng text sử dụng để hiển thị
var number1, number2, result, score, timer;
//biến lưu các giá trị trong game.
var time, currentTime, isResult, currentScore;
//biến sử dụng để đếm ngược thời gian
var timerHandle;
//biến để căn vị trí cho các nút
var marginbutton = 3 / 2;
var marginbottom = 2;

6. Tạo các property cho các biến

plus = {
            x: null,
            y: null,
            text: "+",
            fontFormat: "80pt Kremlin Pro Web",
            update: function() {},
            draw: function() {
                ctx.font = this.fontFormat;
                ctx.fillStyle = "White";
                ctx.textAlign = "center";
                ctx.fillText(this.text, this.x, this.y);
            }

        };

        number1 = {
            x: null,
            y: null,
            text: "",
            fontFormat: "80pt Kremlin Pro Web",
            update: function() {},
            draw: function() {
                ctx.font = this.fontFormat;
                ctx.fillStyle = "White";
                ctx.textAlign = "right";
                ctx.fillText(this.text, this.x, this.y);
            }

        };
        number2 = {
            x: null,
            y: null,
            text: "",
            fontFormat: "80pt Kremlin Pro Web",
            update: function() {},
            draw: function() {
                ctx.font = this.fontFormat;
                ctx.fillStyle = "White";
                ctx.textAlign = "left";
                ctx.fillText(this.text, this.x, this.y);
            }

        };
        result = {
            x: null,
            y: null,
            text: "",
            fontFormat: "80pt Kremlin Pro Web",
            update: function() {},
            draw: function() {
                ctx.font = this.fontFormat;
                ctx.fillStyle = "White";
                ctx.textAlign = "center";
                ctx.fillText(this.text, this.x, this.y);
            }

        };
        score = {
            x: null,
            y: null,
            text: "",
            fontFormat: "40pt Kremlin Pro Web",
            update: function() {
                this.text = currentScore;
            },
            draw: function() {
                ctx.font = this.fontFormat;
                ctx.fillStyle = "White";
                ctx.textAlign = "center";
                ctx.fillText(this.text, this.x, this.y);
            }

        };

        timer = {
            x: null,
            y: null,
            text: "",
            fontFormat: "40pt Kremlin Pro Web",
            update: function() {
                this.text = timer.text = currentTime;
            },
            draw: function() {
                ctx.font = this.fontFormat;
                ctx.fillStyle = "White";
                ctx.textAlign = "center";
                ctx.fillText(this.text, this.x, this.y);
            }

        };

        btnTrue = {
            x: null,
            y: null,
            width: 140,
            height: 100,
            update: function() {},
            draw: function() {
                ctx.fillRect(this.x, this.y, this.width, this.height);
                ctx.font = '30pt Kremlin Pro Web';
                ctx.fillStyle = "white";
                ctx.textAlign = "center";
                ctx.fillText('DÚQ', this.x + this.width / 2, this.y + this.height / 1.7);
            }
        };
        btnFalse = {
            x: null,
            y: null,
            width: 140,
            height: 100,
            update: function() {},
            draw: function() {
                ctx.fillRect(this.x, this.y, this.width, this.height);
                ctx.font = '30pt Kremlin Pro Web';
                ctx.fillStyle = "white";
                ctx.textAlign = "center";
                ctx.fillText('SAI', this.x + this.width / 2, this.y + this.height / 1.7);
            }
        };

7. Hàm main:

function main() {
            canvas = document.createElement("canvas");
            canvas.width = WIDTH;
            canvas.height = HEIGHT;
            ctx = canvas.getContext("2d");
            document.body.appendChild(canvas);

            //Binding the click event on the canvas
            canvas.addEventListener('click', function(evt) {
                var mousePos = getMousePos(canvas, evt);

                if (isInside(mousePos, btnTrue)) {
                    // alert('clicked true');
                    if (isResult) {
                        currentScore++;
                        randomMath();
                    } else {
                        endGame();
                    }
                } else if (isInside(mousePos, btnFalse)) {
                    if (!isResult) {
                        currentScore++;
                        randomMath();
                    } else {
                        endGame();
                    }
                }
            }, false);

            init();

            var loop = function() {
                update();
                draw();

                window.requestAnimationFrame(loop, canvas);
            }
            window.requestAnimationFrame(loop, canvas);
        }

8. Hàm khởi tạo

function init() {
            btnTrue.x = btnTrue.width / (marginbutton * 1.5);
            btnTrue.y = (HEIGHT - btnTrue.height * marginbottom);

            btnFalse.x = WIDTH - btnFalse.width * marginbutton;
            btnFalse.y = (HEIGHT - btnFalse.height * marginbottom);

            plus.x = WIDTH / 2;
            plus.y = 300;

            number1.x = 200;
            number1.y = 300;
            number1.text = 99;

            number2.x = WIDTH - 200;
            number2.y = 300;
            number2.text = 99;

            result.x = WIDTH / 2;
            result.y = 480;
            result.text = 1;

            currentScore = 0;
            score.x = WIDTH - 50;
            score.y = 50;
            score.text = 0;

            timer.x = 50;
            timer.y = 50;
            timer.text = 5;

            currentTime = 5;
            randomMath();
            timeCountdown();
        }

9. Hàm cập nhật liên tục

function update() {
            plus.update();
            btnTrue.update();
            btnFalse.update();
            number1.update();
            number2.update();
            result.update();
            score.update();
            timer.update();

        }

10. Hàm kết thúc game

function endGame() {
            alert('bạn dã wua với diểm số: ' + currentScore);
            currentScore = 0;
            score.text = currentScore;
            clearInterval(timerHandle);
            init();
        }

11. Hàm đếm ngược thời gian

function timeCountdown() {
            clearInterval(timerHandle);
            timerHandle = setInterval(function() {
                if (currentTime <= 0) {
                    endGame();
                } else {
                    currentTime--;

                }
            }, 1000);
        }

12. Hàm vẽ ra các thành phần đồ họa

function draw() {
            ctx.fillRect(0, 0, WIDTH, HEIGHT);
            ctx.fillStyle = "#41e2f4";
            ctx.save();

            plus.draw();
            number1.draw();
            number2.draw();
            result.draw();
            score.draw();
            timer.draw();

            ctx.fillStyle = "#4141f4";
            btnTrue.draw();
            ctx.fillStyle = "#f44141";
            btnFalse.draw();

            ctx.beginPath();
            ctx.moveTo(80, 360);
            ctx.lineTo(WIDTH - 80, 360);
            ctx.stroke();

            ctx.restore();
        }

13. Hàm tạo ra các phép tính ngẫu nhiên (các bạn có thể custom lại để có những phép toán phức tạp và khó hơn ở đây nhé 😀 )

function randomMath() {
            currentTime = 5;
            var num1 = getRandomInt(1, 100);
            var num2 = getRandomInt(1, 100);
            number1.text = num1;
            number2.text = num2;
            var equal = num1 + num2 + getRandomInt(0, 1) + getRandomInt(0, 1) * 10;
            result.text = equal;
            isResult = ((num1 + num2) == equal);
            timeCountdown();
        }

        function getRandomInt(min, max, range = 1) {
            return Math.floor(Math.random() * (max - min + range)) + min;
        }

14. Hàm lấy ra vị trí của trỏ chuột (phục vụ cho việc bắt sự kiện click chuột của các bạn)

function getMousePos(canvas, event) {
            var rect = canvas.getBoundingClientRect();
            return {
                x: event.clientX - rect.left,
                y: event.clientY - rect.top
            };
        }

15. Hàm kiểm tra xem vị trí chuột có nằm trên nút bấm hay không

function isInside(pos, rect) {
            return pos.x > rect.x && pos.x < rect.x + rect.width && pos.y < rect.y + rect.height && pos.y > rect.y
        }

16. Cuối cùng là chúng ta chạy hàm main để game bắt đầu hoạt động

main();

TADA….. vậy là chúng ta đã hoàn thành game rồi, bạn chỉ việc chạy file crazemath.html trên 1 trình duyệt web nào đó để có thể chơi game nhé! hãy gửi cho bạn bè cùng chơi để xem ai thông mình hơn học sinh lớp 2 nào =))))

P/s: thật ra game này mình đã từng làm trên UNITY rồi, các bạn có thể tham khảo link bên dưới để có được cái nhìn sơ bộ về việc làm game trên UNITY và HTML5 có gì giống và khác nhau nhé 😉
Hướng dẫn làm game crazemath bẳng UNITY
Link download bản apk đã hoàn thiện của game