Chào mừng bạn đến với thế giới tuyệt vời của kế hoạch chuyển động phi tổng thể. Tôi khuyên bạn nên làm điều này bằng cách sử dụng một kế hoạch đường dẫn lưới mắt cáo . Các lựa chọn thay thế khác bao gồm RRT động lực học và tối ưu hóa quỹ đạo . Các hệ thống phi tổng thể bao gồm ô tô, thuyền, xe đạp hoặc bất kỳ thứ gì mà phương tiện không thể đi theo bất kỳ hướng nào nó muốn. Lập kế hoạch cho các hệ thống này khó hơn nhiều so với các hệ thống tổng thể và cho đến năm 2000 là trên cơ sở nghiên cứu học thuật. Ngày nay có rất nhiều thuật toán để lựa chọn trong đó hoạt động tốt.
Đây là cách nó hoạt động.
Tiểu bang
Cấu hình của chiếc xe của bạn q thực sự là một trạng thái 3D chứa x của xe, vị trí y và định hướng của nó t . Các nút trong thuật toán A * của bạn thực sự là các vectơ 3D.
class Node
{
// The position and orientation of the car.
float x, y, theta;
}
Hành động
Vậy còn các cạnh thì sao?
Điều đó hơi khó hơn, bởi vì chiếc xe của bạn thực sự có thể chọn vô số cách để xoay bánh xe. Vì vậy, chúng ta có thể làm cho điều này thể truy cập đến một kế hoạch lưới điện lưới bằng cách hạn chế số lượng các hành động của xe có thể mất đến một tập rời rạc, Một . Vì mục đích đơn giản, giả sử rằng chiếc xe không tăng tốc mà thay vào đó có thể thay đổi vận tốc tức thời. Trong trường hợp của chúng tôi, A có thể như sau:
class Action
{
// The direction of the steering wheel.
float wheelDirection;
// The speed to go at in m/s.
float speed;
// The time that it takes to complete an action in seconds.
float dt;
}
Bây giờ, chúng ta có thể tạo ra một bộ hành động riêng biệt mà chiếc xe có thể thực hiện bất cứ lúc nào. Ví dụ, một quyền cứng trong khi nhấn ga đầy đủ trong 0,5 giây sẽ trông như thế này:
Action turnRight;
turnRight.speed = 1;
turnRight.wheelDirection = 1;
turnRight.dt = 0.5;
Đặt xe ngược lại và lùi xe sẽ như thế này:
Action reverse;
reverse.speed = -1;
reverse.wheelDirection = 0;
reverse.dt = 0.5;
Và danh sách hành động của bạn sẽ như thế này:
List<Action> actions = { turnRight, turnLeft, goStraight, reverse ...}
Bạn cũng cần một cách xác định cách thức một hành động được thực hiện tại một nút dẫn đến một nút mới. Đây được gọi là động lực chuyển tiếp của hệ thống.
// These forward dynamics are for a dubin's car that can change its
// course instantaneously.
Node forwardIntegrate(Node start, Action action)
{
// the speed of the car in theta, x and y.
float thetaDot = action.wheelDirection * TURNING_RADIUS;
// the discrete timestep in seconds that we integrate at.
float timestep = 0.001;
float x = start.x;
float y = start.y;
float theta = start.theta;
// Discrete Euler integration over the length of the action.
for (float t = 0; t < action.dt; t += timestep)
{
theta += timestep * thetaDot;
float xDot = action.speed * cos(theta);
float yDot = action.speed * sin(theta);
x += timestep * xDot;
y += timestep * yDot;
}
return Node(x, y, theta);
}
Các ô lưới rời rạc
Bây giờ, để xây dựng lưới mắt cáo, tất cả những gì chúng ta cần làm là băm các trạng thái của xe vào các ô lưới rời rạc. Điều này biến chúng thành các nút riêng biệt có thể được theo sau bởi A *. Điều này là cực kỳ quan trọng bởi vì nếu không thì A * sẽ không có cách nào để biết liệu hai trạng thái xe có thực sự giống nhau để so sánh chúng hay không. Bằng cách băm đến các giá trị ô lưới số nguyên, điều này trở nên tầm thường.
GridCell hashNode(Node node)
{
GridCell cell;
cell.x = round(node.x / X_RESOLUTION);
cell.y = round(node.y / Y_RESOLUTION);
cell.theta = round(node.theta / THETA_RESOLUTION);
return cell;
}
Bây giờ, chúng ta có thể thực hiện kế hoạch A * trong đó GridCells là các nút, Hành động là các cạnh giữa các nút và Bắt đầu và Mục tiêu được thể hiện dưới dạng GridCells. Heuristic giữa hai GridCells là khoảng cách tính bằng x và y cộng với khoảng cách góc trong theta.
Theo con đường
Bây giờ chúng ta có một đường dẫn về GridCells và Hành động giữa chúng, chúng ta có thể viết một người theo dõi đường dẫn cho chiếc xe. Vì các ô lưới là rời rạc, chiếc xe sẽ nhảy vào giữa các ô. Vì vậy, chúng ta sẽ phải làm dịu chuyển động của chiếc xe dọc theo con đường. Nếu trò chơi của bạn đang sử dụng một động cơ vật lý, điều này có thể được thực hiện bằng cách viết một bộ điều khiển lái cố gắng giữ chiếc xe càng gần càng tốt với đường dẫn. Mặt khác, bạn có thể làm động đường dẫn bằng cách sử dụng các đường cong bezier hoặc đơn giản bằng cách lấy trung bình một vài điểm gần nhất trong đường dẫn.