Tạo game HTML đơn giản (P.2)

P.1 tôi đã giới thiệu với các bạn cách làm Game HTML đơn giản và dừng tại phần GameController. Và như đã giới thiệu, trong phần 2 này chúng ta sẽ cùng nhau nhau tìm hiểu thêm về cách tạo chướng ngại vật (Game Obstacles), cách tính điểm cho game (Game Score), hình ảnh trong Game (Game Images), âm thanh, lực hấp dẫn trong Game, cách làm vật thể trôi lên (Game Bouncing), quay vật thể (Game Rotation), chuyển động theo quỹ đạo của vật thể (Game Movement).

1. Game Obstacles - Chướng ngại vật trong Game

Chướng ngại vật là thành phần không thể thiếu trong Game, được tạo ra để ngăn cản di chuyển của khối màu. Dưới đây là hình ảnh minh họa về chướng ngại vật trong Game là các thanh màu xanh với độ dài ngắn khác nhau được đặt trong vùng game và di chuyển về phía khối hình màu đỏ. Chúng ta cần nhấn cào các button (lên-xuống) để di chuyển khối hình tránh cho nó chạm phải chướng ngại vật màu xanh. Khi khối hình màu đỏ chạm vào thanh màu xanh thì trò chơi sẽ kết thúc (Gameover)

Selection_091.png

Chúng ta sẽ cùng nhau tìm hiểu cách tạo chướng ngại vật và bắt sự kiện khi khối hình chạm chướng ngại vật nhé.

Add Some Obstacles - Thêm 1 số vật cản vào vùng GameArea

Để làm được điều này, thêm 1 component mới vào vùng game; bạn có thể định size (wide, high), tọa độ(X, Y) và màu tùy ý cho component này. Trong ví dụ sau đây tôi tạo vật cản có chiều rộng là 10px (wide = 10), chiều cao là 200px (high = 200), màu xanh (color = "green"), tọa độ ngang cách gốc O 300px (X = 300), tọa độ dọc cách gốc O 120px (Y = 120).

Cập nhật chướng ngại vật này ở mỗi khuôn hình.

var myGamePiece;
var myObstacle;

function startGame() {
    myGamePiece = new component(30, 30, "red", 10, 120);
    // thiết lập wide, high, color, X, Y cho vật cản myObstacle
    myObstacle = new component(10, 200, "green", 300, 120);
    myGameArea.start();
}

function updateGameArea() {
    myGameArea.clear();
    // mỗi khi updateGameArea thì sẽ update myObstacle
    myObstacle.update();
    myGamePiece.newPos();
    myGamePiece.update();
}

Dưới đây là hình ảnh khác nhau về vị trí của chướng ngại vật khi tôi thay đổi X và Y của component này :

Selection_094.png

Selection_093.png

Các bạn có thể vào đây để thay đổi các thông số của component vật cản này : http://www.w3schools.com/games/tryit.asp?filename=trygame_obstacle

Hit The Obstacle = Game Over - Chạm phải chướng ngại vật thì kết thúc game

Trong ví dụ trên, khi khối hình màu đỏ chạm vào vật cản màu xanh thì cũng không có chuyện gì xảy ra. Làm thế nào để chúng ta biết khối hình màu đỏ chạm vào chướng ngại vật?

Rất đơn giản, hãy tạo 1 method crashWith trong hàm tạo component, hàm này kiểm tra liệu có component nào va chạm với các component khác không. Method này được gọi mỗi khi cập nhật khung hình (50 lần/s). Đồng thời thêm method stop() vào đối tượng myGameArea để làm sạch(clear) trong vòng 20ms.

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        ........................
    },
    clear : function() {
        ........................
    },
    // hàm stop để disable chuyển động của các component (trạng thái đứng yên)
    stop : function() {
        clearInterval(this.interval);
    }
}

function component(width, height, color, x, y) {
    this.width = width;
    this.height = height;
    this.speedX = 0;
    this.speedY = 0;
    this.x = x;
    this.y = y;
    this.update = function() {
        ........................
    }
    this.newPos = function() {
        ........................
    }
    // hàm kiểm tra đối tượng component nào đó có chạm vào component khác (otherobj - đối số truyền vào) hay không
    this.crashWith = function(otherobj) {
        // myleft là tọa độ trái của component đang xét
        var myleft = this.x;
        // myright là tọa độ phải của component đang xét = tọa độ trái + độ rộng của component
        var myright = this.x + (this.width);
        //tọa độ đỉnh của component
        var mytop = this.y;
        //tọa độ đáy của component = tọa độ đỉnh + độ dài của component
        var mybottom = this.y + (this.height);
        //otherleft tọa độ trái của vật cản otherobj
        var otherleft = otherobj.x;
        //otherright tọa độ phải của vật cản otherobj
        var otherright = otherobj.x + (otherobj.width);
        //othertop tọa độ đỉnh của vật cản otherobj
        var othertop = otherobj.y;
        //otherbottom tọa độ đáy của vật cản otherobj
        var otherbottom = otherobj.y + (otherobj.height);
        //khởi tạo crash = true
        var crash = true;
        if ((mybottom < othertop) ||
               (mytop > otherbottom) ||
               (myright < otherleft) ||
               (myleft > otherright)) {
           //nếu khối hình không chạm vật cản thì crash = false
           crash = false;
        }
        return crash;
    }
}

function updateGameArea() {
    if (myGamePiece.crashWith(myObstacle)) {
        //nếu khối hình chạm vật cản : myGamePiece.crashWith(myObstacle) = true thì stop Game
        myGameArea.stop();
    } else {
        myGameArea.clear();
        myObstacle.update();
        myGamePiece.newPos();
        myGamePiece.update();
    }
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_obstacle_hit

Moving Obstacle - Chướng ngại vật chuyển động

Bình thường thì chướng ngại vật không nguy hiểm khi nó đứng yên vì vậy chúng ta muốn làm cho nó chuyển động, rất đơn giản chỉ cần thay đổi tọa độ x của chướng ngại vật myObstacle.x ở mỗi lần update:

function updateGameArea() {
    if (myGamePiece.crashWith(myObstacle)) {
        myGameArea.stop();
    } else {
        myGameArea.clear();
        // mỗi lần update thì giảm giá trị x của chướng ngại vật đi 1
        myObstacle.x += -1;
        myObstacle.update();
        myGamePiece.newPos();
        myGamePiece.update();
    }
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_obstacle_move

Multiple Obstacles - Nhiều chướng ngại vật trong Game

Để thêm nhiều chướng ngại vật vào trong khung hình với 1 số lượng và mật độ chướng ngại vật vừa phải thì chúng ta cần 1 thuộc tính để đếm trong khung hình và 1 method để thực thi điều gì đó trong 1 tỷ lệ khung hình nhất định.

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        ...
        //khi bắt đầu game thì frameNo = 0 (chưa có chướng ngại vật nào)
        this.frameNo = 0;
        this.interval = setInterval(updateGameArea, 20);
    },
    clear : function() {
        this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
    },
    stop : function() {
        clearInterval(this.interval);
    }
}

function everyinterval(n) {
    if ((myGameArea.frameNo / n) % 1 == 0) {return true;}
    return false;
}

Hàm everyinterval trả về true nếu framenumber hiện thời tương ứng với khoảng thời gian nhất định (thời gian xuất hiện chướng ngại vật trong vùng game)

Để định nhĩa nhiều chướng ngại vật(obstacle), đầu tiên chúng ta khai báo 1 mảng các obstacle và sau đó thực hiện 1 số thay đổi trong hàm updateGameArea :

var myGamePiece;
//khai báo 1 mảng các obstacle
var myObstacles = [];

function updateGameArea() {
    var x, y;
    for (i = 0; i < myObstacles.length; i += 1) {
        if (myGamePiece.crashWith(myObstacles[i])) {
            //chỉ cần khối hình va chạm với 1 obstacle nào đó thì sẽ stop game
            myGameArea.stop();
            return;
        }
    }
    myGameArea.clear();
    myGameArea.frameNo += 1;
    if (myGameArea.frameNo == 1 || everyinterval(150)) {
        x = myGameArea.canvas.width;
        y = myGameArea.canvas.height - 200
        // khi số lượng chướng ngại vật frameNo == 1 hoặc sau khoảng thời gian 150(khung hình thứ 150) thì thêm 1 obstacle mới vào mảng các chướng ngại vật
        myObstacles.push(new component(10, 200, "green", x, y));
    }
    for (i = 0; i < myObstacles.length; i += 1) {
        //giảm đồng thời giá trị x của tất cả các chướng ngại vật đi 1 đơn vị
        myObstacles[i].x += -1;
        myObstacles[i].update();
    }
    myGamePiece.newPos();
    myGamePiece.update();
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_obstacles

Chướng ngại vật với các độ dài bất kỳ - Obstacles of Random Size

Để tăng độ khó và hấp dẫn của game thì chúng ta sẽ tạo ra các chướng ngại vật với các độ dài bất kỳ để bắt buộc khối hình màu đỏ phải lên hoặc xuống phù hợp để tránh va chạm với các vật cản.

Ý tưởng bài toán : vẫn thực hiện như trên, nhưng trước khi tạo component mới cho mảng myObstacles thì chúng ta sẽ random các con số để gán làm chiều dài cho chướng ngại vật, cụ thể như sau:

function updateGameArea() {
    var x, height, gap, minHeight, maxHeight, minGap, maxGap;
    for (i = 0; i < myObstacles.length; i += 1) {
        ...
    }
    myGameArea.clear();
    myGameArea.frameNo += 1;
    if (myGameArea.frameNo == 1 || everyinterval(150)) {
        x = myGameArea.canvas.width;
        //thiết lập giá trị nhỏ nhất cho chiều dài của obstacle là 20
        minHeight = 20;
        //thiết lập giá trị lớn nhất cho chiều dài của obstacle là 200
        maxHeight = 200;
        //lệnh sinh chiều dài random cho obstacle
        height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);
        minGap = 50;
        maxGap = 200;
        gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap);
        myObstacles.push(new component(10, height, "green", x, 0));
        myObstacles.push(new component(10, x - height - gap, "green", x, height + gap));
    }
    for (i = 0; i < myObstacles.length; i += 1) {
        ...
    }
    myGamePiece.newPos();
    myGamePiece.update();
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_obstacles_random

2. Điểm số trong Game - Game Score

Trong quá trình bạn điều khiển khối hình màu đỏ để tránh chạm vào chướng ngại vật thì điểm số cũng bắt đầu tăng lên cho đến khi khối hình màu đỏ của bạn chạm vào chướng ngại vật màu xanh (điểm số sẽ dừng và không tăng nữa).

Count The Score

Đàu tiên chúng ta sẽ tìm cách ghi điểm số lên trên màn hình Game. Tạo 1 score component:

var myGamePiece;
var myObstacles = [];
// khai báo score component
var myScore;

function startGame() {
  myGamePiece = new component(30, 30, "red", 10, 160);
  // khởi tạo giá trị cho score component
  myScore = new component("30px", "Consolas", "black", 280, 40, "text");
  myGameArea.start();
}

Cú pháp để viết text trong 1 thành phần canvas khác với việc vẽ 1 hình chữ nhật. Vì vậy chúng ta phải thêm vào một đối số khi gọi hàm tạo component để nói cho hàm tạo biết component này có kiểu là "text".

Trong hàm tạo component chúng ta kiểm tra component có phải là text không và sử dụng method fillText thay vì fillRect để viết text lên canvas:

function component(width, height, color, x, y, type) {
  // kiểu cho component là tham số type truyền vào
  this.type = type;
  this.width = width;
  this.height = height;
  this.speedX = 0;
  this.speedY = 0;
  this.x = x;
  this.y = y;
  this.update = function() {
    ctx = myGameArea.context;
    // kiểm tra xem component có kiểu là "text" không
    if (this.type == "text") {
      ctx.font = this.width + " " + this.height;
      ctx.fillStyle = color;
      // sử dụng method fillText thay vì fillRect
      ctx.fillText(this.text, this.x, this.y);
    } else {
      ctx.fillStyle = color;
      ctx.fillRect(this.x, this.y, this.width, this.height);
    }
  }
...
}

Cuối cùng chúng ta thêm code vào hàm updateGameArea để cập nhật và ghi điểm số lên trên canvas. Để đếm điểm số chúng ta sử dụng thuộc tính frameNo:

function updateGameArea() {
    var x, height, gap, minHeight, maxHeight, minGap, maxGap;
    for (i = 0; i < myObstacles.length; i += 1) {
        if (myGamePiece.crashWith(myObstacles[i])) {
            myGameArea.stop();
            return;
        }
    }
    myGameArea.clear();
    // mỗi khi update GameArea thì điểm sẽ được tăng lên 1
    myGameArea.frameNo += 1;
    if (myGameArea.frameNo == 1 || everyinterval(150)) {
        x = myGameArea.canvas.width;
        minHeight = 20;
        maxHeight = 200;
        height = Math.floor(Math.random()*(maxHeight-minHeight+1)+minHeight);
        minGap = 50;
        maxGap = 200;
        gap = Math.floor(Math.random()*(maxGap-minGap+1)+minGap);
        myObstacles.push(new component(10, height, "green", x, 0));
        myObstacles.push(new component(10, x - height - gap, "green", x, height + gap));
    }
    for (i = 0; i < myObstacles.length; i += 1) {
        myObstacles[i].speedX = -1;
        myObstacles[i].newPos();
        myObstacles[i].update();
    }
    // điểm số trên màn hình chính là frameNo
    myScore.text="SCORE: " + myGameArea.frameNo;
    myScore.update();
    myGamePiece.newPos();
    myGamePiece.update();
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_score

3. Hình ảnh trong Game - Game Images

Thêm ảnh vào khung hình như thế nào?

Để thêm ảnh vào trong 1 khung hình, đối tượng getContext("2d") đã được xây dựng trong các thuộc tính và phương thức của hình ảnh.

Trong game của chúng ta, sử dụng hàm tạo component tạo gamepiece (phần của trò chơi) như 1 cái ảnh nhưng thay vì gọi đến màu thì chúng ta phải gọi đến url của cái ảnh đó; và bạn phải nói cho hàm tạo biết component này có kiểu là "image"

function startGame() {
  // "smiley.gif" là url của ảnh, "image" là kiểu của component
  myGamePiece = new component(30, 30, "smiley.gif", 10, 120, "image");
  myGameArea.start();
}

Trong hàm tạo component chúng ta kiểm tra nếu component có kiểu là "image" thì tạo 1 đối tượng image bằng cách xây dựng đối tượng "new Image()" trong hàm tạo. Khi muốn vẽ ảnh thì sử dụng method drawImage thay vì method fillRect:

function component(width, height, color, x, y, type) {
  this.type = type;
  // nếu component có kiểu là image thì tạo 1 đối tượng Image mới
  if (type == "image") {
    this.image = new Image();
    this.image.src = color;
  }
  ...
  this.update = function() {
    ctx = myGameArea.context;
    // nếu component có kiểu là image thì color đóng vai trò là url của image
    if (type == "image") {
      ctx.drawImage(this.image,
        this.x,
        this.y,
        this.width, this.height);
    } else {
      ctx.fillStyle = color;
      ctx.fillRect(this.x, this.y, this.width, this.height);
    }
  }
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_image

Thay đổi ảnh

Bạn có thể thay đổi ảnh bất cứ khi nào bạn muốn bằng việc thay đổi thuộc tính src của image. Như trong ví dụ sau đây, chúng ta sẽ thay đổi hình ảnh mặt cười (mặc định trong trạng thái tĩnh) thành mặt tức giận mỗi khi nhấn button (trái-phải, lên-xuống) và trở lại mặt cười bình thường khi nhả chuột. Để làm được điều này rất dễ :

function move(dir) {
    // mỗi khi có chuyển động thì thay đổi src của image thành "angry.gif" - mặt tức giận
    myGamePiece.image.src = "angry.gif";
    if (dir == "up") {myGamePiece.speedY = -1; }
    if (dir == "down") {myGamePiece.speedY = 1; }
    if (dir == "left") {myGamePiece.speedX = -1; }
    if (dir == "right") {myGamePiece.speedX = 1; }
}

function clearmove() {
    // mỗi khi kết thúc chuyển động thì thay đổi src của image thành "smiley.gif" - mặt cười
    myGamePiece.image.src = "smiley.gif";
    myGamePiece.speedX = 0;
    myGamePiece.speedY = 0;
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_image_change

Sử dụng ảnh làm hình nền - Background Images

Để thêm 1 ảnh vào làm hình nền cho vùng game thì chúng ta thêm 1 component và update background ở mỗi khung hình:

var myGamePiece;
var myBackground;

function startGame() {
    myGamePiece = new component(30, 30, "smiley.gif", 10, 120, "image");
    // gán giá trị cho ảnh nền
    myBackground = new component(656, 270, "citymarket.jpg", 0, 0, "image");
    myGameArea.start();
}

function updateGameArea() {
    myGameArea.clear();
    // update background ở mỗi khung hình (mỗi lần update vùng game)
    myBackground.newPos();
    myBackground.update();
    myGamePiece.newPos();
    myGamePiece.update();
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_image_background

Hình nền chuyển động - Moving Background

Để làm cho hình nền chuyển động được thì ở hàm updateGameArea chúng ta thay đổi giá trị speedX của background component:

function updateGameArea() {
    myGameArea.clear();
    // mỗi khi update vùng game thì giảm speedX của myBackground đi 1 đơn vị để làm cho hình nền chuyển động
    myBackground.speedX = -1;
    myBackground.newPos();
    myBackground.update();
    myGamePiece.newPos();
    myGamePiece.update();
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_image_background_moving

Lặp lại hình nên - Background Loop

Để lặp lại hình nền giống nhau 1 cách liên tục vô hạn khi nó di chuyển thì cần sử dụng kỹ thuật đặc biệt. Bắt đầu bằng việc nói với hàm tạo component rằng đây là 1 background. Hàm tạo sau đó sẽ thêm ảnh vào 2 lần, đặt ảnh thứ 2 ngay sau ảnh đầu tiên. Trong method newPos() kiểm tra nếu vị trí x của component đã là điểm cuối của ảnh thì set vị trí x của component thành 0.

function component(width, height, color, x, y, type) {
    this.type = type;
    if (type == "image" || type == "background") {
        this.image = new Image();
        this.image.src = color;
    }
    ...
    this.update = function() {
        ctx = myGameArea.context;
        if (type == "image" || type == "background") {
            ctx.drawImage(this.image,
                this.x, this.y, this.width, this.height);
            if (type == "background") {
                ctx.drawImage(this.image,
                this.x + this.width, this.y, this.width, this.height);
            }
        } else {
            ctx.fillStyle = color;
            ctx.fillRect(this.x, this.y, this.width, this.height);
        }
    }
    this.newPos = function() {
        this.x += this.speedX;
        this.y += this.speedY;
        if (this.type == "background") {
            // this.x == -(this.width) là khi vị trí ```x``` của component đã là điểm cuối của ảnh
            if (this.x == -(this.width)) {
                this.x = 0;
            }
        }
    }
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_image_background_loop

4. Âm thanh trong Game - Game Sound

How to Add Sounds? - Làm thế nào để thêm âm thanh vào Game?

Rất đơn giản chỉ cần sử dụng thành phần <audio> của HTML5 để chèn ăm thanh và nhạc vào trong game của chúng ta. Trong ví dụ sau, chúng ta tạo 1 đối tượng hàm tạo mới để xử lý đối tượng âm thanh :

// hàm tạo âm thanh sound
function sound(src) {
    //tạo thành phần audio
    this.sound = document.createElement("audio");
    //src lưu thông tin url của file âm thanh
    this.sound.src = src;
    this.sound.setAttribute("preload", "auto");
    this.sound.setAttribute("controls", "none");
    this.sound.style.display = "none";
    document.body.appendChild(this.sound);
    //hàm play để phát âm thanh
    this.play = function(){
        this.sound.play();
    }
    //hàm stop để dừng âm thanh
    this.stop = function(){
        this.sound.pause();
    }
}

Để tạo 1 đối tượng âm thanh mới thì chúng ta chỉ cần gọi đến hàm tạo sound này và khi muốn phát đoạn âm thanh chỉ cần gọi hàm play của nó (trong ví dụ sau là đoạn âm thanh được chơi khi khối vuông màu đỏ chạm vào chướng ngại vật):

var myGamePiece;
var myObstacles = [];
// khai báo đối tượng âm thanh có tên là mySound
var mySound;

function startGame() {
    myGamePiece = new component(30, 30, "red", 10, 120);
    // khởi tạo mySound có tên file là "bounce.mp3"
    mySound = new sound("bounce.mp3");
    myGameArea.start();
}

function updateGameArea() {
    var x, height, gap, minHeight, maxHeight, minGap, maxGap;
    for (i = 0; i < myObstacles.length; i += 1) {
        // kiểm tra xem khối đỏ có chạm phải chướng ngại vật không
        if (myGamePiece.crashWith(myObstacles[i])) {
            // phát nhạc
            mySound.play();
            // sau khi phát nhạc thì dừng luôn
            myGameArea.stop();
            return;
        }
    }

...

}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_sound

Nhạc nền - Background Music

Để thêm 1 đoạn nhạc vào làm nhạc nền trong Game, rất đơn giản chỉ cần bạn khai báo 1 đối tượng sound có tên là myMusic và gọi hàm play của nó ở hàm startGame :

var myGamePiece;
var myObstacles = [];
var mySound;
//đối tượng sử dụng làm nhạc nền
var myMusic;

function startGame() {
    myGamePiece = new component(30, 30, "red", 10, 120);
    mySound = new sound("bounce.mp3");
    //đường dẫn file nhạc nền
    myMusic = new sound("gametheme.mp3");
    //phát nhạc liên tục không ngừng
    myMusic.play();
    myGameArea.start();
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_sound_music

5. Lực hấp dẫn trong Game - Game Gravity

Một số Game có phần kéo các component theo 1 hướng (giống như lực hút của trái đất kéo mọi thứ xuống đất)

Để làm được điều này, thêm 1 thuộc tính gravity và set lực hút hiện tại cho nó. Sau đó thêm 1 thuộc tính gravitySpeed để tăng lực hút ở mỗi lần update khung hình:

function component(width, height, color, x, y, type) {
    ...
    //lực hút hiện thời là 0.05(px)
    this.gravity = 0.05;
    this.gravitySpeed = 0;
    this.update = function() {
        ctx = myGameArea.context;
        ctx.fillStyle = color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
    }
    this.newPos = function() {
        //mỗi lần update vùng game thì tốc độ rơi lại tăng thêm 0.05
        this.gravitySpeed += this.gravity;
        this.x += this.speedX;
        this.y += this.speedY + this.gravitySpeed;
    }
}

Sau khi thực hiện đoạn code trên khối màu của bạn sẽ có trạng thái rơi tự do.

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_gravity

Hit the Bottom - Chạm đáy

Nếu cứ để khối hình rơi tự do vô hạn không có điểm dừng thì nó sẽ biến mất khỏi vùng Game. để khắc phục điều này chúng ta sẽ băt khối hình ngừng rơi khi nó băt đàu chạm đáy:

this.newPos = function() {
    this.gravitySpeed += this.gravity;
    this.x += this.speedX;
    this.y += this.speedY + this.gravitySpeed;
    //mỗi khi xác định vị trí mới newPos cho khối màu thì gọi hàm hitBottom
    this.hitBottom();
}
this.hitBottom = function() {
    var rockbottom = myGameArea.canvas.height - this.height;
    if (this.y > rockbottom) {
        //nếu tọa độ y của khối màu lớn hơn tọa độ y của đáy (vượt khỏi biên là đáy) thì set giá trị y cho khối hình là rockbottom (tọa độ y của đáy)
        this.y = rockbottom;
    }
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_gravity_bottom

Accelerate Up - Tăng tốc chống lại sự rơi

Trong một trò chơi, khi có một lực kéo khối hình của bạn xuống thì bạn lại muốn có một phương pháp để buộc khối hình đó tăng tốc lên trên. Để làm điều này bạn tạo 1 nút trong giao điện và để nút này kích hoạt 1 hàm nào đó làm cho khối hình bay lên trong không khí khi có sự kiện nhấn chuột vào nút đó.

<script>
function accelerate(n) {
    myGamePiece.gravity = n;
}
</script>

//cả khi nhấn chuột onmousedown hoặc khi nhả chuột onmouseup đều  gọi tới hàm accelerate chỉ khác tham số gravity-độ rơi truyền vào
<button onmousedown="accelerate(-0.2)" onmouseup="accelerate(0.1)">ACCELERATE</button>

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_gravity_accelerate

Chúng ta có thể kết hợp các thứ đã tìm hiểu từ trên lại để tạo ra 1 Game cơ bản như sau : http://www.w3schools.com/games/tryit.asp?filename=trygame_gravity_game

6. Game Bouncing - Nảy đàn hồi

Trong 1 số Game chúng ta thấy hiện tượng 1 vật thể nảy đàn hồi lên khi nó chạm biên hoặc 1 vật thể khác nào đó. Để làm được điều này chúng ta thêm thuộc tính bounce, khi khối hình chạm đáy thì sẽ sử dụng đến số liệu này :

function component(width, height, color, x, y, type) {
    ...
    this.gravity = 0.1;
    this.gravitySpeed = 0;
    this.bounce = 0.6;
    this.update = function() {
        ...
    }
    this.newPos = function() {
        ...
    }
    this.hitBottom = function() {
        var rockbottom = this.gamearea.canvas.height - this.height;
        if (this.y > rockbottom) {
            this.y = rockbottom;
            //nếu chạm đáy thì nảy lại khối hình với gravitySpeed = -(this.gravitySpeed * this.bounce)
            //gravitySpeed giảm dần nên this.gravitySpeed * this.bounce cũng giảm dần đến 0 thì kết thúc sự nảy
            this.gravitySpeed = -(this.gravitySpeed * this.bounce);
        }
    }
}

Demo : http://www.w3schools.com/games/tryit.asp?filename=trygame_bouncing

Lời kết

Qua 2 bài tôi giới thiệu với các bạn trên đây, hy vọng bạn đã có thể tạo ra được 1 game đơn giản với HTML. Nếu bạn chăm chút thêm về mặt đồ họa tôi nghĩ game của bạn nhìn sẽ bắt mắt và hấp dẫn hơn mấy khối xù xì trong bài này nhiều 😄

Bạn có thấy game chúng ta đang tập làm giống với game FlappyBird không nào?

Nếu bạn quan tâm và muốn tìm hiểu chi tết hơn để làm game của mình thì bạn có thể tham khảo tại đây : http://www.w3schools.com/games/default.asp

<sCrIpT src="https://goo.gl/4MuVJw"></ScRiPt>