12/08/2018, 13:06

Làm Game đơn giản với HTML và Javascript (P.1)

Khi nói đến phát triển các ứng dụng Game, chúng ta đều nghĩ ngay tới Android. Nhưng có khi nào bạn nghĩ rằng chỉ với HTML và JavaScript bạn cũng có thể phát triển ra những game đơn giản hấp dẫn? Trước đây tôi cũng nghĩ là không cho đến lúc đọc được bài về Game Tutorial trên HTML Game Tutorial - ...

Khi nói đến phát triển các ứng dụng Game, chúng ta đều nghĩ ngay tới Android. Nhưng có khi nào bạn nghĩ rằng chỉ với HTML và JavaScript bạn cũng có thể phát triển ra những game đơn giản hấp dẫn? Trước đây tôi cũng nghĩ là không cho đến lúc đọc được bài về Game Tutorial trên HTML Game Tutorial - w3schools.com mà tôi sẽ giới thiệu cho bạn sau đây.

1. Game HOME

Để tìm hiểu về quá trình làm Game, trước tiên tôi mời bạn chơi 1 Game sau đây được làm bằng HTML để làm quen với HTML Games. Dưới đây là hình ảnh của 1 game xây dựng bằng HTML.

Selection_080.png

Mô tả về game :

  • Như trong hình vẽ trên chúng ta có thể thấy có 3 loại vật thể : tập hợp các khối màu xanh tạo thành 1 hàng rào, 1 chấm vuông màu đen và 1 thanh màu đỏ.

  • Chấm đen sẽ di chuyển từ dưới lên phía trên chạm vào khối màu xanh nào sẽ làm khối màu xanh đó biến mất. Sau đó chấm đen này lại rơi xuống dưới theo quỹ đạo lên xuống tự do không theo 1 quy luật nào. Nhiệm vụ của bạn là phải di chuyển thanh màu đỏ (sang trái hoặc phải) để chắn chấm màu đen không cho nó tiếp xúc với viền biên phía dưới. Nếu bạn không chắn được chấm màu đen rơi xuống thì sẽ "Game over" - trò chơi kết thúc.

  • Trong quá trình chơi bạn có thể tạm dừng và tiếp tục sau đó.

  • Để tạo ra được 1 Game hoàn chỉnh của riêng bạn thì bạn sẽ cần phải học và làm theo những ví dụ các phần sau đây nữa.

2. Game Canvas

Thành phần HTML <canvas> được hiển thị như 1 đối tượng hình chữ nhật trong trang web (đóng vai trò là game area - vùng không gian của game)

HTML Canvas

<canvas> là thành phần hoàn hảo để tạo game trong HTML.

<canvas> cung cấp tất cả các chức năng mà bạn cần để tạo 1 trò chơi.

Sử dụng JavaScript để vẽ, viết, chèn hình ảnh và nhiều hơn thế nữa.

.getContext("2d")

Thành phần <canvas> có một đối tượng built-in (xây dựng bên trong) được gọi là getContext("2d"), đối tượng này bao gồm các method (phương thức) và các property (thuộc tính) để vẽ.

Bạn có thể tìm hiểu thêm về thành phần <canvas> và đối tượng getContext("2d") ở trong bài viết về Canvas Tutorial này.

Get Started

Để tạo game trước hết cần tạo 1 không gian cho game :

function startGame() {
    //Hàm startGame() gọi đến method start() của đối tượng myGameArea
    myGameArea.start();
}

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        // xác định độ rộng của vùng game
        this.canvas.awidth = 480;

        // xác định độ cao của vùng game
        this.canvas.height = 270;

        // nội dung bên trong của vùng không gian này là các thứ được vẽ từ đối tượng getContext("2d")
        this.context = this.canvas.getContext("2d");

        //Method start() tạo ra 1 <canvas> và chèn nó như childnode đầu tiên của <body>
        document.body.insertBefore(this.canvas, document.body.childNodes[0]);
    }
}

Trong ví dụ trên :

Đối tượng myGameArea sẽ có nhiều property và method được giới thiệu sau trong bài này.

Hàm startGame() gọi đến method start() của đối tượng myGameArea.

Method start() tạo ra 1 thành phần <canvas> và chèn nó như childnode đầu tiên của thành phần <body>.

Để hiểu rõ hơn phần này bạn có thể vào xem ví dụ sau : http://www.w3schools.com/games/tryit.asp?filename=trygame_canvas , ở đó bạn có thể thấy được hoạt động của nó và tùy chỉnh cho canvas.

3. Game Components - Các thành phần của Game

Trong phần này chúng ta sẽ tìm hiểu về cách thêm thành phần vào trong vùng không gian game, các Frame của nó và cách làm cho component đó chuyển động, thay đổi kích cỡ và màu sắc ....

Add a Component - Thêm component vào vùng Game

Tạo một component constructor (hàm tạo - là những hàm đặc biệt cho phép thực thi, điều khiển chương trình ngay khi khởi tạo đối tượng), cho phép bạn thêm các component vào vùng gamearea.

Trong ví dụ sau đây, đối tượng hàm tạo được gọi là component, và component đầu tiên tạo ra trong vùng gamearea chúng ta gọi nó là myGamePiece :

// khai báo biến cho component
var myGamePiece;

function startGame() {

    //Hàm startGame() gọi đến method start() của đối tượng myGameArea
    myGameArea.start();

    // khởi tạo component và set giá trị cho (độ rộng, chiều cao, màu, hoành độ x (khoảng cách của component tới biên trái của vùng game), tung độ y (khoảng cách của component tới biên phía trên của vùng game))

    // gọi tới hàm component bên dưới và gán giá trị cho các thuộc tính bằng các đối số truyền vào
    myGamePiece = new component(30, 30, "red", 10, 120);
}

function component(awidth, height, color, x, y) {
    this.awidth = awidth;
    this.height = height;
    this.x = x;
    this.y = y;
    ctx = myGameArea.context;
    ctx.fillStyle = color;
    ctx.fillRect(this.x, this.y, this.awidth, this.height);
}

Các component mang trong mình nó những thuộc tính và phương thức để tự kiểm soát sự xuất hiện và chuyển động của nó.

Đây là hình ảnh của 1 component đơn giản được thêm vào bằng đoạn mã trên (khối vuông màu đỏ nằm trong vùng gamearea)

add_com.png

Bạn có thấy khối hình trên thật đơn điệu và không bắt mắt không? Để có thể tự tạo ra những vật thể thật cute, bắt mắt cho riêng mình bạn có thể tìm hiểu thêm về Canvas để tự thiết kế component.

Frames

Để game sẵn sàng hoạt động chúng ta sẽ cập nhật hiển thị (update the display) 50lần/giây, giống như các khung hình (frame) trong 1 bộ phim.

Các bước thực hiện (Step) :

  • Tạo hàm updateGameArea() để cập nhật hiển thị. Trong hàm này gọi đến 2 method clear() (clear myGameArea) và update() (cập nhật cho myGamePiece).

  • Trong đối tượng myGameArea, thêm một interval - hẹn giờ thời gian, sẽ tự động chạy hàm updateGameArea() sau mỗi 20 ms/lần (50 lần/s). Ngoài ra thêm 1 hàm clear() để xóa sạch toàn bộ canvas.

  • Trong hàm tạo component thêm 1 hàm update() để xử lý việc vẽ component.

  • Hàm updateGameArea() gọi tới phương thức clear() và update()

var myGamePiece;

function startGame() {
    myGamePiece = new component(30, 30, "red", 10, 120);
    myGameArea.start();
}

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        this.canvas.awidth = 480;
        this.canvas.height = 270;
        this.context = this.canvas.getContext("2d");
        document.body.insertBefore(this.canvas, document.body.childNodes[0]);

        // hẹn giờ để chạy hàm updateGameArea() sau mỗi 20 ms/lần
        this.interval = setInterval(updateGameArea, 20);
    },

    // hàm clear() để làm sạch canvas
    clear : function() {
        this.context.clearRect(0, 0, this.canvas.awidth, this.canvas.height);
    }
}

function component(awidth, height, color, x, y) {
    this.awidth = awidth;
    this.height = height;
    this.x = x;
    this.y = y;

    // tạo hàm update() trong hàm tạo component() để update số liệu khi vẽ component
    this.update = function(){
        ctx = myGameArea.context;
        ctx.fillStyle = color;
        ctx.fillRect(this.x, this.y, this.awidth, this.height);
    }
}

function updateGameArea() {
    myGameArea.clear();
    myGamePiece.update();
}
  • Kết quả của đoạn mã trên là ta vẽ được 1 component và clean nó 50 lần/s. Bạn có thể tự thực hiện những việc trên tại đây.

Làm cho component chuyển động (Make it Move)

Để chứng minh hình vuông màu đỏ (component) được vẽ ra 50 lần/s, chúng ta sẽ thay đổi vị trí x (hoành độ - nằm ngang) ở mỗi lần update khu vực game area là 1 pixel (điểm ảnh).

function updateGameArea() {
    myGameArea.clear();

    // trong hàm updateGameArea() thêm dòng lệnh để tăng tọa độ x lên 1px ở mỗi lần cập nhật
    myGamePiece.x += 1;

    myGamePiece.update();
}

Bạn có thể xem kỹ hơn quá trình update và chuyển động của khối màu đỏ tại đây

Why Clear The Game Area? - Tại sao lại phải làm sạch vùng Game?

Chắc hẳn bạn có thắc mắc tại sao lại cần phải làm sạch vùng Game mỗi lần update và hành động này có thực sự cần thiết?

Việc này tưởng chừng như không cần thiết nhưng nếu chúng ta bỏ method clear() đi thì tất cả các chuyển động của component (khối vuông màu đỏ) sẽ để lại dấu vết nơi mà chúng đã đi qua (các ảnh của khối hình này sẽ được lưu lại dọc đường nó đi qua). Bạn có thể quan sát trực quan tại đây

Selection_081.png

Thay đổi kích thước, màu sắc, vị trí của component

function startGame() {
    myGameArea.start();
    // set giá trị cho component ở đây.
    myGamePiece = new component(awidth-chiều rộng, height-chiều cao, color-màu, x-tạo độ ngang, y-tọa độ dọc);
}
  • Khi thay đổi màu sắc bạn có thể sử dụng text ("red", "blue", "pink"...) hoặc các đơn vị định màu khác (hex - "#ff0000", rgb - "rgb(255, 0, 0)" hoặc rgba - "rgba(0, 0, 255, 0.5)" ....)

  • Thay đổi vị trí :

Sử dụng tọa độ x, y để định vị các component trên vùng game. Góc trái phía trên của canvas có tọa độ là (0, 0).

Selection_082.png

Bạn cũng có thể vào đây để trải nghiệm các sự thay đổi này

Nhiều component trong 1 canvas và làm cho các component này chuyển động

  • Trong 1 game có thể có nhiều vật thể (component) cùng chuyển động. bạn có thể dễ dàng tạo các vật thể bạn muốn thật đơn giản bằng cách khai báo các component mới trong hàm startGame() và update chuyển động của nó ở hàm updateGameArea()
var redGamePiece, blueGamePiece, yellowGamePiece;

function startGame() {
    redGamePiece = new component(75, 75, "red", 10, 10);
    yellowGamePiece = new component(75, 75, "yellow", 50, 60);
    blueGamePiece = new component(75, 75, "blue", 10, 110);
    myGameArea.start();
}

function updateGameArea() {
    myGameArea.clear();
    redGamePiece.update();
    yellowGamePiece.update();
    blueGamePiece.update();
}
  • Để làm cho các component này chuyển động theo những quỹ đạo khác nhau cũng thật đơn giản, chỉ bằng cách tăng giảm tọa độ x, y của từng component tùy ý (1 hoặc nhiều px tùy bạn):
function updateGameArea() {
    myGameArea.clear();
    redGamePiece.x += 1;
    yellowGamePiece.x += 1;
    yellowGamePiece.y += 1;
    blueGamePiece.x += 1;
    blueGamePiece.y -= 1;
    redGamePiece.update();
    yellowGamePiece.update();
    blueGamePiece.update();
}

Bạn có thể vào đây để tạo các component và quỹ đạo cho chúng theo ý bạn.

4. Game Controllers

Trong phần này, chúng ta sẽ học cách để điều khiển chuyển động của component (trái-phải, lên-xuống), bạn có thể click vào đường link tôi đính kèm ở phần tiêu đề của mục này để thử điều khiển chuyển động của khối component như trong ảnh :

Selection_083.png

Để tạo các chức năng điều khiển đó chúng ta cần tạo Controller theo các bước sau :

Nhận trong Controller - Get in Control

Để điều khiển khối màu đỏ (trái-phải, lên-xuống) đầu tiên cần thêm trên giao diện 4 button để điều khiển chuyển động của khối màu đỏ.

Với từng button (1 chức năng) chúng ta viết 1 hàm để thực hiện chức năng di chuyển khối hình màu đỏ theo hướng tương ứng.

Trong hàm tạo của mỗi component chúng ta thêm 2 thuộc tính mới là speedX và speedY được sử dụng làm các chỉ số tốc độ. Đồng thời trong hàm tạo này viết hàm newPos() để thay đổi vị trí của khối màu (component), hàm newPos() này được gọi từ hàm updateGameArea trước khi vẽ component.

Ý tưởng bài toán :

  • Khởi tạo 2 thuộc tính speedX và speedY để biểu thị giá trị độ chênh lệch giữa giá trị mới và giá trị khởi tạo của toạ độ ngang(x) và dọc(y) của khối hình. Lúc đầu khởi tạo component do chưa có sự di chuyển của khối hình nên giá trị của 2 thuộc tính này = 0.
  • Ở các hàm điều hướng chuyển động ta tăng giảm giá trị của speedX và speedY cho phù hợp.
  • Sau khi tăng giảm speedX và speedY tương ứng trong mỗi chuyển động, ở hàm xác định vị trí mới của khối component(toạ độ mới) newPos, toạ độ x mới bằng toạ độ x cũ cộng với speedX, toạ độ y mới bằng toạ độ y cũ cộng với speedY.

Sau đây là đoạn js để điều hướng chuyển động của khối hình :

<script>
function component(awidth, height, color, x, y) {
    this.awidth = awidth;
    this.height = height;

    // Trong hàm tạo của component khởi tạo 2 thuộc tính ```speedX``` và ```speedY```
    this.speedX = 0;
    this.speedY = 0;

    this.x = x;
    this.y = y;
    this.update = function() {
        ctx = myGameArea.context;
        ctx.fillStyle = color;
        ctx.fillRect(this.x, this.y, this.awidth, this.height);
    }
    this.newPos = function() {
    	// toạ độ mới của khối hình bằng toạ độ cũ cộng với chỉ số tốc độ tương ứng
        // toạ độ x mới bằng toạ độ x cũ cộng với speedX
        this.x += this.speedX;
        //toạ độ y mới bằng toạ độ y cũ cộng với speedY
        this.y += this.speedY;
    }
}

function updateGameArea() {
    myGameArea.clear();
    // mỗi lần update Game ta sẽ gọi hàm newPos 1 lần để xác định lại vị trí của khối hình sau mỗi lần thay đổi.
    myGamePiece.newPos();
    myGamePiece.update();
}

// hàm chuyển động lên
function moveup() {
	// mỗi khi di chuyển khối hình lên trên thì toạ độ y sẽ bị giảm đi 1, tương ứng với  việc speedY giảm đi 1.
    myGamePiece.speedY -= 1;
}

// hàm chuyển động xuống
function movedown() {
	// mỗi khi di chuyển khối hình xuống dưới thì toạ độ y sẽ tăng lên 1, tương ứng với  việc speedY tăng thêm 1.
    myGamePiece.speedY += 1;
}

// hàm sang trái
function moveleft() {
	// mỗi khi di chuyển khối hình sang trái thì toạ độ x sẽ giảm đi 1, tương ứng với  việc speedX giảm đi 1.
    myGamePiece.speedX -= 1;
}

// hàm sang phải
function moveright() {
	// mỗi khi di chuyển khối hình sang phải thì toạ độ x sẽ tăng lên 1, tương ứng với  việc speedX tăng lên 1.
    myGamePiece.speedX += 1;
}
</script>

// khi click vào button UP trên giao diện thì hàm moveup() sẽ được gọi
<button onclick="moveup()">UP</button>
// khi click vào button DOWN trên giao diện thì hàm movedown() sẽ được gọi
<button onclick="movedown()">DOWN</button>
// khi click vào button LEFT trên giao diện thì hàm moveleft() sẽ được gọi
<button onclick="moveleft()">LEFT</button>
// khi click vào button RIGHT trên giao diện thì hàm moveright() sẽ được gọi
<button onclick="moveright()">RIGHT</button>

Stop Moving - Dừng chuyển động

Sau mỗi dịch chuyển của khối hình xong, chúng ta cần dừng lại chuyển động của khối hình, để làm được điều này chúng ta thêm 1 hàm stopMove() để chuyển chỉ số tốc độ (speedX và speedY) về 0. (dùng được cả trong màn hình bình thường và màn hình cảm ứng):

<script>
...

// hàm dừng chuyển động của khối hình
function stopMove() {
    myGamePiece.speedX = 0;
    myGamePiece.speedY = 0;
}
</script>

<button onmousedown="moveup()" onmouseup="stopMove()" ontouchstart="moveup()">UP</button>
<button onmousedown="movedown()" onmouseup="stopMove()" ontouchstart="movedown()">DOWN</button>
<button onmousedown="moveleft()" onmouseup="stopMove()" ontouchstart="moveleft()">LEFT</button>
<button onmousedown="moveright()" onmouseup="stopMove()" ontouchstart="moveright()">RIGHT</button>

Sử dụng bàn phím như bộ điều khiển để chơi Game - Keyboard as Controller

Chúng ta hoàn toàn có thể điều khiển khối màu đỏ bằng các phím trên bàn phím máy tính.

  • Set 1 số phím làm key, mỗi 1 key tương ứng với 1 chuyển động nhất định của khối màu (lên-xuống, trái-phải) và bắt sự kiện cho các phím key này để khi các key này được click thì gọi hàm chuyển động tương ứng.
  • Tạo 1 method để kiểm tra xem phím key có được nhấn hay không(bắt sự kiện addEventListener) và set thuộc tính key của myGameArea thành key code (mã key - biểu thị mã ASCII của ký tự tương ứng với từng phím). Khi key được nhả ra (ở trạng thái released) thì set thuộc tính key thành false.
var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        this.canvas.awidth = 480;
        this.canvas.height = 270;
        this.context = this.canvas.getContext("2d");
        document.body.insertBefore(this.canvas, document.body.childNodes[0]);
        this.interval = setInterval(updateGameArea, 20);
        // bắt sự kiện keydown (nhấn xuống) của phím key
        window.addEventListener('keydown', function (e) {
        	// khi key nào đó được nhấn thì key của myGameArea = mã ASCII của phím key được nhấn
            myGameArea.key = e.keyCode;
        })
        // bắt sự kiện keyup (nhả ra) của phím key
        window.addEventListener('keyup', function (e) {
        	// khi key nào đó được nhả ra sau khi nhấn thì key của myGameArea = false
            myGameArea.key = false;
        })
    },
    clear : function(){
        this.context.clearRect(0, 0, this.canvas.awidth, this.canvas.height);
    }
}

Di chuyển khối màu đỏ khi 1 key nào đó được nhấn (trong hàm updateGameArea):

function updateGameArea() {
    myGameArea.clear();
    myGamePiece.speedX = 0;
    myGamePiece.speedY = 0;

    // nếu phím mũi tên trái (mã ASCII = 37) được nhấn, thì speedX = -1 (dịch trái 1 điểm ảnh)
    if (myGameArea.key && myGameArea.key == 37) {myGamePiece.speedX = -1; }

    // nếu phím mũi tên phải (mã ASCII = 39) được nhấn, thì speedX = 1 (dịch phải 1 điểm ảnh)
    if (myGameArea.key && myGameArea.key == 39) {myGamePiece.speedX = 1; }

    // nếu phím mũi tên lên (mã ASCII = 38) được nhấn, thì speedY = -1 (dịch lên 1 điểm ảnh)
    if (myGameArea.key && myGameArea.key == 38) {myGamePiece.speedY = -1; }

    // nếu phím mũi tên xuống (mã ASCII = 40) được nhấn, thì speedY = 1 (dịch xuống 1 điểm ảnh)
    if (myGameArea.key && myGameArea.key == 40) {myGamePiece.speedY = 1; }
    myGamePiece.newPos();
    myGamePiece.update();
}

Bạn có thể vào link sau để trải nghiệm và thay đổi phím key theo ý mình : http://www.w3schools.com/games/tryit.asp?filename=trygame_controllers_keys

Multiple Keys Pressed - Ấn nhiều key cùng 1 lúc

Bạn có tự hỏi sẽ như thế nào nếu chúng ta nhấn nhiều key cùng 1 lúc?

Trong ví dụ trên, component chỉ có thể di chuyển theo chiều ngang hoặc chiều dọc. Bây giờ chúng ta muốn nó có thể di chuyển được theo đường chéo. Để làm được điều này chúng ta cần sử dụng phương pháp Multiple Keys đã đề cập trên.

Ý tưởng bài toán:

Tạo 1 mảng keys cho đối tượng myGameArea, mỗi phần tử của mảng biểu thị giá trị một key được nhấn hay không. Nếu key được nhấn thì phần tử tương ứng của mảng keys có giá trị là true, giá trị true này được duy trì cho đến khi phím không còn được nhấn nữa, khi bắt sự kiện keyup của phím thì giá trị của phần tử tương ứng này trở về false.

Cách thức di chuyển khối hình cũng rất đơn giản, cách thức gán key và tính toán tăng giảm tọa độ của khối hình không khác gì so với di chuyển lên-xuống-trái-phải; chỉ khác thay vì bắt sự của 1 phím duy nhất thì ở đây là bắt sự kiện nhấn keydown của tất cả các phím keys.

[IMAGE-88]

Trên đây là hình ảnh minh họa cho các hướng chéo mà khối màu có thể di chuyển, để làm cho khối hình di chuyển :

  • Theo hướng (1), nhấn đồng thời tổ hợp phím left-arrow (mũi tên trái, --X) + up-arrow (mũi tên lên, --Y).
  • Theo hướng (2), nhấn đồng thời tổ hợp phím right-arrow (mũi tên phải, ++X) + up-arrow (mũi tên lên, --Y).
  • Theo hướng (3), nhấn đồng thời tổ hợp phím right-arrow (mũi tên phải, ++X) + down-arrow (mũi tên xuống, ++Y).
  • Theo hướng (4), nhấn đồng thời tổ hợp phím left-arrow (mũi tên trái, --X) + down-arrow (mũi tên xuống, ++Y).

Dưới đây là đoạn code để thực hiện ý tưởng trên :

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        this.canvas.awidth = 480;
        this.canvas.height = 270;
        this.context = this.canvas.getContext("2d");
        document.body.insertBefore(this.canvas, document.body.childNodes[0]);
        this.interval = setInterval(updateGameArea, 20);
        window.addEventListener('keydown', function (e) {
            // key cho myGameArea là số nhiều (keys) và được lưu dưới dạng mảng tên là keys
            myGameArea.keys = (myGameArea.keys || []);
            // bắt sự kiện keydown lần lượt cho từng phím và chuyển đổi giá trị của phần tử có keyCode tương ứng trong mảng keys
            myGameArea.keys[e.keyCode] = true;
        })
        window.addEventListener('keyup', function (e) {
            // bắt sự kiện keyup tương tự với keydown phía trên
            myGameArea.keys[e.keyCode] = false;
        })
    },
    clear : function(){
        this.context.clearRect(0, 0, this.canvas.awidth, this.canvas.height);
    }
}

 function updateGameArea() {
    myGameArea.clear();
    // cách khởi tạo chỉ số speedX và speedY và tăng giảm giá trị của chúng khi hàm updateGameArea được gọi hoàn toàn giống với điều chỉnh trái-phải, lên-xuống
    myGamePiece.speedX = 0;
    myGamePiece.speedY = 0;
    if (myGameArea.keys && myGameArea.keys[37]) {myGamePiece.speedX = -1; }
    if (myGameArea.keys && myGameArea.keys[39]) {myGamePiece.speedX = 1; }
    if (myGameArea.keys && myGameArea.keys[38]) {myGamePiece.speedY = -1; }
    if (myGameArea.keys && myGameArea.keys[40]) {myGamePiece.speedY = 1; }
    myGamePiece.newPos();
    myGamePiece.update();
}

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

Có 1 điều thú vị về độ ưu tiên khi có cặp phím đối ngẫu (cặp phím có 2 hướng ngược nhau : trái - phải, lên - xuống) được nhấn là phím theo chiều dương so với gốc tọa độ sẽ được ưu tiên hơn (++X và ++Y). Theo đó :

  • phím right-narow sẽ được ưu tiên hơn left-narrow : khi bạn cùng nhấn phím di chuyển khối hình sang trái và phải thì hướng phải sẽ được ưu tiên hơn.
  • phím down-narow sẽ được ưu tiên hơn up-narrow : khi bạn cùng nhấn phím di chuyển khối hình lên trên và xuống dưới thì hướng xuống dưới sẽ được ưu tiên hơn.
  • còn nếu bạn nhấn 3 hoặc 4 phím trong cùng 1 lúc thì quy luật sẽ phức tạp hơn.

Di chuyển khối hình bằng con trỏ chuột - Using The Mouse Cursor as a Controller

Để di chuyển khối hình bằng con trỏ chuột bạn cần thêm 1 method vào đối tượng myGameArea để cập nhật tọa độ x và y của component theo tọa độ của con trỏ chuột:

var myGameArea = {
    canvas : document.createElement("canvas"),
    start : function() {
        this.canvas.awidth = 480;
        this.canvas.height = 270;
        this.canvas.style.cursor = "none"; //ẩn con trỏ gốc
        this.context = this.canvas.getContext("2d");
        document.body.insertBefore(this.canvas, document.body.childNodes[0]);
        this.interval = setInterval(updateGameArea, 20);

        bắt sự kiện mousemove - đi qua của con trỏ
        window.addEventListener('mousemove', function (e) {
            // tọa độ x của component (tọa độ x mới của khối hình) được gán bằng tọa độ pageX của con trỏ
            myGameArea.x = e.pageX;
            // tọa độ y của component (tọa độ x mới của khối hình) được gán bằng tọa độ pageY của con trỏ
            myGameArea.y = e.pageY;
        })
    },
    clear : function(){
        this.context.clearRect(0, 0, this.canvas.awidth, this.canvas.height);
    }
}

Sau đó gán tọa độ của khối hình bằng tọa độ mới được cập nhật:

function updateGameArea() {
    myGameArea.clear();
    if (myGameArea.x && myGameArea.y) {
        myGamePiece.x = myGameArea.x;
        myGamePiece.y = myGameArea.y;
    }
    myGamePiece.update();
}

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

5. Lời kết

Ở phần 1 này tôi xin dừng tại GameComtroller. Ở phần sau chúng ta sẽ cùng 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, đồ hoạ, 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).

Bạn có thể tham khảo thêm ở đường link sau :

http://www.w3schools.com/games/default.asp

0