Bàn phím là thiết bị không thể thiếu và là phương tiện rất quan trọng để thực hiện các chức năng của các ứng dụng tương tác với người dùng. Trong bài viết này, tôi sẽ hướng dẫn cách bắt sự kiện bàn phím trong canvas và dùng nó để điều khiển góc xoay và hướng di chuyển của đối tượng đồ họa.
Bắt sự kiện bàn phímĐể bắt sự kiện này, bạn có thể đăng kí trực tiếp cho đối tượng window, tuy nhiên điều này sẽ gây ra những rắc rối khi trang của bạn có quá nhiều thành phần. Cách tốt nhất là đăng kí riêng cho canvas các hàm xử lý. Tuy nhiên, để canvas có thể focus được, bạn cần xác định thuộc tính TabIndex của nó: <canvas id=”canvas” width=”300″ height=”200″ tabindex=”1″ style=”border: 1px solid;”></canvas> Sau đó bạn đăng kí các sự kiện cần thiết cho canvas. Khi chạy trên trình duyệt, bạn cần phải click chuột vào canvas để nó nhận được focus trước khi thực hiện các thao tác bàn phím. _canvas.onkeydown = canvas_keyDown; function canvas_keyDown(e){ alert(e.keyCode); } Tham số event truyền vào hàm xử lý sẽ chứa các thuộc tính cần thiết để bạn xác định được phím nào được nhấn. Ở đây, bạn chỉ cần quan tâm đến thuộc tính keyCode lưu mã của phím được nhấn. Do các giá trị keyCode có kiểu số nên rất khó nhớ và kiểm tra, may mắn là tôi tìm được trang “Javascript Keycode Enums” liệt kê sẵn các keyCode dưới dạng enum của một đối tượng. Tôi sửa lại một chút để tiện sử dụng hơn: var Keys = { BACKSPACE: 8, TAB: 9, ENTER: 13, SHIFT: 16, CTRL: 17, ALT: 18, PAUSE: 19, CAPS_LOCK: 20, ESCAPE: 27, SPACE: 32, PAGE_UP: 33, PAGE_DOWN: 34, END: 35, HOME: 36, LEFT_ARROW: 37, UP_ARROW: 38, RIGHT_ARROW: 39, DOWN_ARROW: 40, INSERT: 45, DELETE: 46, KEY_0: 48, KEY_1: 49, KEY_2: 50, KEY_3: 51, KEY_4: 52, KEY_5: 53, KEY_6: 54, KEY_7: 55, KEY_8: 56, KEY_9: 57, KEY_A: 65, KEY_B: 66, KEY_C: 67, KEY_D: 68, KEY_E: 69, KEY_F: 70, KEY_G: 71, KEY_H: 72, KEY_I: 73, KEY_J: 74, KEY_K: 75, KEY_L: 76, KEY_M: 77, KEY_N: 78, KEY_O: 79, KEY_P: 80, KEY_Q: 81, KEY_R: 82, KEY_S: 83, KEY_T: 84, KEY_U: 85, KEY_V: 86, KEY_W: 87, KEY_X: 88, KEY_Y: 89, KEY_Z: 90, LEFT_META: 91, RIGHT_META: 92, SELECT: 93, NUMPAD_0: 96, NUMPAD_1: 97, NUMPAD_2: 98, NUMPAD_3: 99, NUMPAD_4: 100, NUMPAD_5: 101, NUMPAD_6: 102, NUMPAD_7: 103, NUMPAD_8: 104, NUMPAD_9: 105, MULTIPLY: 106, ADD: 107, SUBTRACT: 109, DECIMAL: 110, DIVIDE: 111, F1: 112, F2: 113, F3: 114, F4: 115, F5: 116, F6: 117, F7: 118, F8: 119, F9: 120, F10: 121, F11: 122, F12: 123, NUM_LOCK: 144, SCROLL_LOCK: 145, SEMICOLON: 186, EQUALS: 187, COMMA: 188, DASH: 189, PERIOD: 190, FORWARD_SLASH: 191, GRAVE_ACCENT: 192, OPEN_BRACKET: 219, BACK_SLASH: 220, CLOSE_BRACKET: 221, SINGLE_QUOTE: 222 }; Kiểm tra trạng thái của nhiều phímMột khó khăn của các sự kiện bàn phím trong javascript là chỉ có thể xác định được duy nhất một phím nhấn thông qua thuộc tính event.keyCode. Để có thể kiểm tra được trạng thái của nhiều phím được nhấn cùng lúc, ta phải lưu trạng thái của chúng lại khi sự kiện keyDown xảy ra và xóa trạng thái đó đi trong sự kiện keyUp. var _keypressed = {}; function canvas_keyDown(e){ _keypressed[e.keyCode] = true; } function canvas_keyUp(e){ _keypressed[e.keyCode] = false; } Giới hạn các phím được bắtSử dụng phương pháp trên, bạn cần lọc các phím cần sử dụng để đối tượng _keypressed không lưu các giá trị không cần thiết. Một cách đơn giản nhất là sử dụng mảng để lưu keyCode của các phím này và kiểm tra trong các sự kiện bàn phím: const AVAILABLE_KEYS = [ Keys.UP_ARROW, Keys.DOWN_ARROW, Keys.LEFT_ARROW, Keys.RIGHT_ARROW ]; function canvas_keyDown(e){ if(AVAILABLE_KEYS.indexOf(e.keyCode)!=-1) { _keypressed[e.keyCode] = true; } } function canvas_keyUp(e){ if(_keypressed[e.keyCode]) { _keypressed[e.keyCode] = false; } } Ví dụ: Di chuyển xe tăngTrong ví dụ này tôi sẽ tạo một lớp Tank và vẽ theo hình dạng một chiếc xe tăng đơn giản. Tại trang html, tôi sẽ bắt các sự kiện keyDown và keyUp để di chuyển đối tượng này theo 8 tám hướng function Tank(mapWidth, mapHeight){ this.mapWidth = mapWidth; this.mapHeight = mapHeight; this.radius = 20; this.speedX = 0; this.speedY = 0; this.power = 3; this.cx = mapWidth/2; this.cy = mapHeight/2; } Tank.prototype.draw = function(context){ context.beginPath(); context.fillStyle = "green"; context.arc(this.cx,this.cy,this.radius,0,Math.PI*2,true); context.closePath(); context.fill(); // gun var size = this.radius/2; var angle = Math.atan2(this.speedY,this.speedX);; context.beginPath(); context.fillStyle = "red"; context.rect(this.cx,this.cy - size/2,size*3,size); context.closePath(); context.fill(); // yellow circle context.beginPath(); context.fillStyle = "yellow"; context.arc(this.cx,this.cy,this.radius/2,0,Math.PI*2,true); context.closePath(); context.fill(); } Tank.prototype.move = function(){ this.cx += this.speedX; this.cy += this.speedY; this.left = this.cx - this.radius; this.top = this.cy - this.radius; this.right = this.cx + this.radius; this.bottom = this.cy + this.radius; } Tank.prototype.resetSpeed = function(){ this.speedX = 0; this.speedY = 0; } Tank.prototype.moveUp = function(){ this.speedY = -this.power; } Tank.prototype.moveDown = function(){ this.speedY = this.power; } Tank.prototype.moveLeft = function(){ this.speedX = -this.power; } Tank.prototype.moveRight = function(){ this.speedX = this.power; } Xoay đối tượng trong canvasMột vấn đề khi bạn di chuyển xe tăng là súng không thay đổi hướng và góc xoay cho phù hợp. Nhưng điều này giải quyết rất đơn giản, bởi vì đối tượng context của canvas hỗ trợ phương thức translate() và rotate() dùng để dịch chuyển và xoay canvas. Như vậy, tôi sẽ thực hiện dịch chuyển tâm xoay đến giữa đối tượng (xe tăng) và gọi rotate() trước khi vẽ nòng súng ra canvas. Để lấy được góc xoay, ta biết được hai giá trị speedX và speedY chính là hướng di chuyển của đối tượng. Hai giá trị này tạo thành hai cạnh kề của một tam giác vuông và góc của súng cũng chính là góc α được tính bằng công thức tan(α) = speedY/speedX. Như vậy ta có:
Như vậy ta sẽ vẽ súng tại điểm gốc tọa độ là chính giữa xe tăng. Bạn nên lưu lại trạng thái của context với phương thức save() và gọi restore() để phục hồi lại trạng thái ban đầu cho nó khi thực hiện thay đổi các thông số của nó. var angle = Math.atan2(this.speedY,this.speedX) context.save(); context.translate(this.cx,this.cy); context.rotate(angle); context.beginPath(); context.fillStyle = "red"; context.rect(0,-size/2,size*3,size); context.closePath(); context.fill(); context.restore(); Mã nguồn hoàn chỉnhTank.js: function Tank(mapWidth, mapHeight){ this.mapWidth = mapWidth; this.mapHeight = mapHeight; this.radius = 20; this.speedX = 0; this.speedY = 0; this.power = 3; this.cx = mapWidth/2; this.cy = mapHeight/2; } Tank.prototype.draw = function(context){ context.beginPath(); context.fillStyle = "green"; context.arc(this.cx,this.cy,this.radius,0,Math.PI*2,true); context.closePath(); context.fill(); // red rectangle var size = this.radius/2; var angle = Math.atan2(this.speedY,this.speedX); context.save(); context.translate(this.cx,this.cy); context.rotate(angle); context.beginPath(); context.fillStyle = "red"; context.rect(0,-size/2,size*3,size); context.closePath(); context.fill(); context.restore(); // yellow circle context.beginPath(); context.fillStyle = "yellow"; context.arc(this.cx,this.cy,this.radius/2,0,Math.PI*2,true); context.closePath(); context.fill(); } Tank.prototype.move = function(){ this.cx += this.speedX; this.cy += this.speedY; this.left = this.cx - this.radius; this.top = this.cy - this.radius; this.right = this.cx + this.radius; this.bottom = this.cy + this.radius; } Tank.prototype.resetSpeed = function(){ this.speedX = 0; this.speedY = 0; } Tank.prototype.moveUp = function(){ this.speedY = -this.power; } Tank.prototype.moveDown = function(){ this.speedY = this.power; } Tank.prototype.moveLeft = function(){ this.speedX = -this.power; } Tank.prototype.moveRight = function(){ this.speedX = this.power; } Sample.html: <html> <head> <script src="tank.js"></script> <script src="keys.js"></script> <script type="text/javascript"> const AVAILABLE_KEYS = [ Keys.UP_ARROW, Keys.DOWN_ARROW, Keys.LEFT_ARROW, Keys.RIGHT_ARROW ]; var _canvas; var _context; var _ball; var _keypressed = {}; function clear() { _context.clearRect(0, 0, _canvas.width, _canvas.height); } function init() { _canvas = document.getElementById("canvas"); _context = _canvas.getContext("2d"); _ball = new Tank(_canvas.width,_canvas.height); draw(); } function canvas_keyDown(e){ if(AVAILABLE_KEYS.indexOf(e.keyCode)!=-1) { _keypressed[e.keyCode] = true; doKeypress(); } } function canvas_keyUp(e){ if(_keypressed[e.keyCode]) { _keypressed[e.keyCode] = false; _ball.resetSpeed(); } } function doKeypress(){ if(_keypressed[Keys.UP_ARROW]) _ball.moveUp(); if(_keypressed[Keys.DOWN_ARROW]) _ball.moveDown(); if(_keypressed[Keys.LEFT_ARROW]) _ball.moveLeft(); if(_keypressed[Keys.RIGHT_ARROW]) _ball.moveRight(); _ball.move(); draw(); } function draw() { clear(); _ball.draw(_context); } window.onload = function(){ init(); _canvas.onkeydown = canvas_keyDown; _canvas.onkeyup = canvas_keyUp; } </script> </head> <body> <canvas id="canvas" width="300" height="200" tabindex="1" style="border: 1px solid;"></canvas> </body> </html> YinYang’s Programming Blog |
HTML5 – Canvas: Di chuyển đối tượng bằng bàn phím
Ý kiến bạn đọc
Tin tức khác
Html5 – Làm game Battle City
- 6/8/2012
Html5 – WebSocket và Node.js
- 24/7/2012
Html5-Canvas: Viết game Tower Defense – part 4(end)
- 18/7/2012
Html5-Canvas: Viết game Tower Defense – part 3
- 13/7/2012
Html5-Canvas: Viết game Tower Defense – part 2
- 12/7/2012
Html5-Canvas: Viết game Tower Defense – part 1
- 12/7/2012
Html5-Canvas: Viết game Mario – part 5 (end)
- 12/7/2012
HTML5-Canvas: Viết game Mario – Part 4
- 10/7/2012
HTML5-Canvas: Viết game Mario – Part 3
- 10/7/2012
HTML5-Canvas: Viết game Mario – Part 2
- 6/7/2012
Tin tiêu điểm
-
Html5 – Canvas: Viết game bắn đại bác – part1 (15,930)
-
Html5 – WebSocket và Node.js (12,365)
-
Html5-Canvas: Viết game Tower Defense – part 1 (8,057)
-
HTML5 – Canvas: Di chuyển đối tượng bằng bàn phím (7,713)
-
Html5-Canvas: Viết game Tower Defense – part 4(end) (7,546)
-
HTML5 – Canvas: Vẽ đồng hồ kim (analog clock) (7,444)
-
Html5-Canvas: Viết game Rắn Săn Mồi (6,764)
-
Html5 – Làm game Battle City (6,587)
-
HTML5-Canvas: Viết game Mario – Part 3 (6,508)
-
Html5-Canvas: Viết game Mario – part 5 (end) (6,490)
Gallery
Text Links
Thiết kế logo chuyên nghiệp Insky
DAFABET
W88 w88b.com/dang-ky-tai-khoan-w88
W88
ca do bong da online
DAFABET
W88 w88b.com/dang-ky-tai-khoan-w88
W88
ca do bong da online
Tags
asp.net
JavaScript
Lập trình
Cơ sở dữ liệu
jquery
Csharp
Ajax
Thủ thuật
JavaScript
menu
Sql Server
Lập trình C#
WebService
stty
Sql
Phân trang
Rewrite
Mã hoá
Backup
Thủ thuật lập trình
Store procedure
Accordion
Validation
Store
Upload
Slide
jQueryPlugin
StoreProcedure
Regular Expression
Regex
android
Quick and snow
HTML5
WPF
WCF
Copyright © 2011 - 2012 vietshare.vn
by
phamkhuong102@gmail.com doanhkisi2315@gmail.com. All rights reserved.