Tìm hiểu về Steering Behaviors (Phần 5) - Obstacle Avoidance

6
Nguyễn Thanh Long viết 5 năm trước

Tiếp nối series tìm hiểu về Steering Behaviors, lần này sẽ là một behavior giúp ích rất nhiều cho những những behavior đã giới thiệu. Đó là tránh đi những vật cản. Tất cả những behavior mà em đã giới thiệu kết hợp với behavior này khiến cho những con bot trở nên rất thật.

Lưu ý

Có một số cần lưu ý về behavior này.:

  • Thứ nhất là nó khác so với tài liệu nguồn của tác giả Fernando Bevilacqua tại phần 1. Vì tác giả của tài liệu này sử dụng cái mà em cho rằng không tối ưu lắm cho cách mà Unity hoạt động cái này sẽ nói sau.
  • Thứ 2 là do em quen sử dụng raycast cho object 3D hơn là 2D nên tại phần này sẽ sử dụng collider của object 3D để hoạt động, phần này hoàn toàn dễ dàng đổi sang 2D được.

Không để dài dòng nữa sau đây là cách mà behavior này được thực hiện trong Unity.

Khái niệm

Vấn đề cốt lõi của behavior này là sử dụng velocity hiện tại của Steering agent để có thể dự đoán được phía trước có vật cả hay không, để làm điều này ta sử dụng Physics.Raycast của Unity như sau
Physics.Raycast(transform.position, new Vector3(velocity.x, velocity.y), out hit, distance, obstacleMask)
trong hàm này thì param thứ nhất là vị trí cast ray, param thứ 2 là hướng của tia ray, out hit là kết quả trả ra, distance là độ dài của ray và obstacleMask là layer mask của những Object mà ta coi là vật cản.

Vật cản (Obstacle)

Cơ bản thì vật cản cần có những thuộc tính sau: alt text
Không cần để ý đến Animation làm gì cả hay chú ý đến Layer và Sphere Collider vì Physics.Raycast sẽ nhận diện collider của object 3D và Physics.Raycast2D sẽ nhận diện collider của object 2D (Circle Collider). Để cho thực sự tối ưu của behavior này mọi người nên dùng Sphere hoặc Circle để làm Collider cho vật cản thay vì những loại collider khác vì hình tròn dễ tính toán nhất :v

Steering Bot

Vật là thiết lập xong phần vật cản, sau đây sẽ sang tiêt mục chính:
Vector2 obstacleAvoidance()
{
Vector2 steering = Vector2.zero;
RaycastHit hit;
if (Physics.Raycast(transform.position, new Vector3(velocity.x, velocity.y), out hit, 5, obstacleMask))
{
Vector3 diff = transform.position - hit.collider.gameObject.transform.position;
steering += new Vector2(diff.x, diff.y);
}
steering = steering.normalized * max_avoid;
return steering;
}

Nhìn khác là quen thuộc như những behavior khác phải không. Đầu tiên chúng ta cần đầu ra cho Physics.Raycast đó là RaycastHit object, object này sẽ chứa toàn bộ thông tin physics của object mà Raycast chạm phải.
Sau khi "bắn" tia và nó chạm phải cài gì đó, tính toán chiều cần rẽ bằng cách tính diff như trên, thực ra thì nó giống như evade behavior thôi.
Cuối cùng tính độ lớn để có thể cộng vào steering tổng trong Update
Như vậy là xong rồi
Trong Update của obstacleAvoidance sẽ có steeringForce như sau:
steeringForce = steeringForce + obstacleAvoidance() + seek(Camera.main.ScreenToWorldPoint(Input.mousePosition));
Con bot này sẽ đuổi theo chuột và luôn tránh những vật cản trước nó như sau: alt text

Khá là đơn giản phải không! Tại đây em có sử dụng thêm hàm Debug.DrawRay(transform.position, new Vector3(velocity.x, velocity.y) * 1, Color.white); để show lên làm hình velocity hiện tại của con bot để hiểu rõ về cách mà behavior này hoạt động.

Ngoài lề

Nói về thuật toán của tác giả Fernando Bevilacqua, tác giả sử dụng việc tìm ra vật cản gần nhất bằng hàm
function findMostThreateningObstacle() :Obstacle {
var mostThreatening :Obstacle = null;
for (var i:int = 0; i < Game.instance.obstacles.length; i++) {
var obstacle :Obstacle = Game.instance.obstacles[i];
var collision :Boolean = lineIntersecsCircle(ahead, ahead2, obstacle);
// "position" is the character's current position
if (collision && (mostThreatening == null || distance(position, obstacle) < distance(position, mostThreatening))) {
mostThreatening = obstacle;
}
}
return mostThreatening;

Tuy hàm không viết bằng C# nhưng cũng nhìn ra được thuật toán sử dụng một vòng lặp tìm ra vật cản trong một list những vật cản, và bằng điều này dùng cho nhiều bot sẽ khiến cho thuật toán tính toán chậm đi rất nhiều.

Bình luận


White
{{ comment.user.name }}
Hay Bỏ hay
{{ comment.like_count}}
White

Nguyễn Thanh Long

12 bài viết.
0 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}

  Cùng một tác giả


{{like_count}}

kipalog

{{ comment_count }}

Bình luận


White
{{userFollowed ? 'Following' : 'Follow'}}
12 bài viết.
0 người follow

 Đầu mục bài viết

 Cùng một tác giả