Kiểm tra va chạm dựa trên pixel

Một phần của tài liệu Lý thuyết và demo thực hành về lập trình game 2D với API Canvas trong Html5 (Trang 64 - 69)

Các đối tượng đồ họa (hoặc hình ảnh) trong game thường được một giới hạn trong một khung bao hình chữ nhật có nền trong suốt (pixel có alpha = 0). Như vậy đối với các đối tượng phức tạp và muốn kiểm tra va chạm chính xác, ta cần kiểm tra các pixel có độ alpha > 0 của hai đối tượng đồ họa có cùng nằm trên một vị trí hay không.

65 | P a g e

1. Một wrapper của Image

Để tiện xử lý các hình ảnh trong canvas dưới dạng một đối tượng trong game với các chức năng cần thiết, ta tạo một lớp ImageObj chứa bên trong một đối tượng Image để lưu trữ hình ảnh. Phương thức quan trọng mà ImageObj phải có là draw(), tuy nhiên việc nạp ảnh có thể diễn ra khá lâu vì vậy ta cần một cách thức xử lý trường hợp này. Chẳng hạn ta sẽ viết ra một dòng thông báo thay thế cho ảnh với kích thước mặc định trong trường hợp ảnh chưa được tải xong:

function ImageObj(){ // ... this.draw = function(context){ if(ready){ context.drawImage(this.img,this.left,this.top); } else{

// image has not finished loading // draw something useful instead context.save(); context.fillText("Image is not ready",this.left+10,this.top+10); context.restore(); } context.strokeRect(this.left,this.top,this.width,this.height); context.stroke(); }; // ... }

Chưa đủ, để đối tượng ImageObj có thể tự vẽ lại sau ảnh được nạp xong, đồng thời lấy được đối tượng ImageData (chứa mảng các pixel), ta sẽ viết một số lệnh xử lý trong sự kiện onload của Image.

function ImageObj(){ // ...

var self = this;

this.img.onload = function(){ self.width = this.width; self.height = this.height;

ready = true; // this image is ready to use

// draw image after loading

context.clearRect(self.left,self.top,self.width,self.height); self.draw(context);

// get ImageData from this image

self.data =

context.getImageData(self.left,self.top,self.width,self.height).data; };

this.img.src = url; }

66 | P a g e Do vấn đề bảo mật, ta sẽ không lấy được ImageData của các ảnh không nằm trong host hiện tại (khác host mà script được thực thi).

2. Xác định vùng giao hai hình chữ nhật

Thay vì lặp qua toàn bộ hai hình ảnh và kiểm tra từng pixel của chúng. Ta sẽ giới hạn lại phần ảnh cần kiểm tra bằng cách xác định vùng giao giữa hai hình ảnh. Phần này cũng giúp ta xác định nhanh hai đối tượng có thể xảy ra va chạm hay không.

function findIntersectionRect(img1,img2){ var rect = { left: Math.max(img1.left,img2.left), top: Math.max(img1.top,img2.top), right: Math.min(img1.left+img1.width,img2.left+img1.width), bottom: Math.min(img1.top+img1.height,img2.top+img2.height) }; if(rect.left>rect.right || rect.top>rect.bottom) return null; return rect; } Xem Demo.

67 | P a g e

3. Kiểm tra va chạm

Nếu đã tìm hiểu về đối tượng ImageData, bạn biết rằng các pixel sẽ được lưu trữ trong một mảng một chiều. Mỗi pixel bao gồm bốn phần tử đứng liền nhau trong mảng theo thứ tự là [Red, Green, Blue, Alpha]. Như vậy một ảnh có kích thước 20×30 sẽ có 600 pixel và có 600×4=2400 phần tử trong ImageData.

function checkPixelCollision(img1,img2){ if(!img1.data || !img2.data)

return null;

var rect = findIntersectionRect(img1,img2); if(rect)

{

// this array will hold all collision points of two images var points = [];

for(var i=rect.left;i<=rect.right;i++){

for(var j=rect.top;j<=rect.bottom;j++){ var index1 = ((i-img1.left)+(j- img1.top)*img1.width)*4+3; (adsbygoogle = window.adsbygoogle || []).push({});

var index2 = ((i-img2.left)+(j- img2.top)*img2.width)*4+3;

if(img1.data[index1+3]!=0 && img2.data[index2+3]!=0)

{

points.push({x:i,y:j});

// you can exit here instead of continue looping } } } return { rect: rect, points: points }; } return null; }

Để tăng tốc độ kiểm tra va chạm, thay vì lặp qua từng pixel, bạn có thể lặp ngắt quãng n pixel (theo cả 2 chiều ngang và dọc) tùy theo mức độ yêu cầu chính xác của ứng dụng. Như vậy số lần lặp để kiểm tra sẽ giảm đi 2n lần tương ứng. Dưới đây là ảnh minh họa việc thay đổi bước tăng của vòng lặp từ 1 lên 3. Vùng màu đỏ là các pixel có độ alpha > 0 thuộc cả hai ảnh:

69 | P a g e

E. Kỹ thuật lập trình Game – Nâng cao

Một phần của tài liệu Lý thuyết và demo thực hành về lập trình game 2D với API Canvas trong Html5 (Trang 64 - 69)