GameDev – Kiểm tra va chạm: hình tròn và chữ nhật

Basic Collision DemoThông thường các đối tượng trong game sẽ được xác định va chạm bằng cách đưa chúng về một dạng hình học cơ bản như hình chữ nhật, hình tròn. Bài viết này sẽ giúp bạn cách tính toán để kiểm tra va chạm giữa hai loại hình học này.

Xem Demo.

Giữa hai hình chữ nhật

Phương pháp: kiểm tra từng đỉnh của hình này có nằm bên trong hình kia không.

Rect.prototype.collideWidthRect = function(rect) {
	return this.contains(rect.left,rect.top) ||
		this.contains(rect.right,rect.top) ||
		this.contains(rect.right,rect.bottom) ||
		this.contains(rect.left,rect.bottom);
}

Cách trên không phải cách nhanh nhất, vì vậy bạn có thể dùng cách sau, đơn giản và hiệu quả hơn:

Rect.prototype.collideWidthRect = function(rect) {
	return !(this.left > rect.right ||
			this.right < rect.left ||
			this.top > rect.bottom ||
			this.bottom < rect.top);
}

Giữa hai hình tròn

Phương pháp: Bởi vì mọi điểm nằm trên đường tròn cách đều tâm, nên việc kiểm tra va chạm giữa hai hình tròn sẽ được xác định dựa vào khoảng cách tâm giữa chúng.
Để xác định khoảng cách giữa hai điểm, ta dựa vào định lý Pythagoras (Pythagorean theorem) . Ta coi khoảng cách giữa hai điểm là đường chéo của một tam giác vuông. Vậy độ lớn của đường chéo này là:

c² = a² + b²
=> c = sqrt(a² + b²)
Circle.prototype.collideWithCircle = function(circle){
	var dx = this.cx - circle.cx;
	var dy = this.cy - circle.cy;

	return Math.sqrt(dx*dx + dy*dy) <= this.radius+circle.radius;
}

Trong minh họa dưới đây, hai hình tròn có màu mặc định là xanh lá, khi va chạm nhau, chúng sẽ chuyển sang màu đỏ.

Two Circles - Collision delection

Giữa hình tròn và hình chữ nhật

Phương pháp: Gọi C là tâm và R là bán kính hình tròn. Ta sẽ tìm cách xác định điểm A là điểm gần nhất thuộc hình chữ nhật đến tâm C. Sau đó so sánh độ lớn của CA với R.
Khoảng cách giữa tâm C hình tròn và điểm A của hình chữ nhật được minh họa như hình dưới đây. Khi tâm hình tròn nằm bên trong hình chữ nhật, thì điểm C và A sẽ trùng nhau.

Closed point between rectangle and circleGọi rect là hình chữ nhật cần xác định va chạm. Ta có thuật toán để xác định điểm A như sau:

– B1: Gán A bằng với C.
– B2: Nếu C.X < rect.Left, đặt A.X = rect.Left. Ngược lại nếu C.X > rect.Right, đặt A.X = rect.Right.
– B3: Nếu C.Y < rect.Top, đặt A.Y = rect.Top. Ngược lại nếu C.Y > rect.Bottom, đặt A.Y = rect.Bottom.

Khi đã có điểm A, ta lại dùng công thức Pythagoras để so sánh với bán kính của hình tròn.

Circle.prototype.collideWithRect = function(rect){
	var px = this.cx;
	var py = this.cy;

	if(px < rect.left)
		px = rect.left;
	else if(px > rect.right)
		px = rect.right;

	if(py < rect.top)
		py = rect.top;
	else if(py > rect.bottom)
		py = rect.bottom;

	var dx = this.cx - px;
	var dy = this.cy - py;

	return (dx*dx + dy*dy) <= this.radius*this.radius;
}

YinYang’s Blog

Advertisements

14 thoughts on “GameDev – Kiểm tra va chạm: hình tròn và chữ nhật

  1. Cám ơn bạn đã hướng dẫn bài này bằng hình ảnh và code rất dễ hiểu.Nhưng cho mình xin hỏi.Mình có thắc mắc sau: như trong trường hợp va chạm thứ 3(Tròn vs HCN),ở 4 phía Left(rect.X – rect.W/2),Right(rect.X + rect.W/2),Top(rect.Y+rect.H/2),Bottom(rect.Y-rect.H/2)
    – Sau khi gán A = C ;
    – if(C.X <= Left ){ A.X = Left; }
    else(C.X <= Right ) { A.X = Right; }
    Vậy có cần xét thêm trường hợp :
    else if(Left <= C.X <= Right){?}
    và các hướng còn lại tương tự.

    Ý mình là nếu không xét thêm trường hợp tiếp điểm nằm khoảng giữa thì nó có tự hiểu giữ nguyên giá trị của A.X = C.X và hàm này có được thực thi đúng công thức hay không?Mình là người khá kỹ tính mà code chưa vững lắm nên mình mới thắc mắc.Rất mong bạn chỉ dẫn mình thêm.Chân thành cám ơn bạn.

    Phản hồi
  2. Mình hiểu rồi..xin lỗi và cám ơn bài viết của bạn rất nhiều..mình quên là khúc cuối vẫn có trường hợp xét <= r*r 🙂 hihi..nếu có choáng chỗ cmt cho mọi người thì bạn có thể tháo cmt của mình xuống :)..chúc bạn nhiều sức khỏe 🙂

    Phản hồi

Trả lời

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s