Làm thế nào để xác định các ô trong lưới giao nhau với một tam giác đã cho?


9

Tôi hiện đang viết một mô phỏng AI 2D, nhưng tôi không hoàn toàn chắc chắn làm thế nào để kiểm tra xem vị trí của một tác nhân có nằm trong tầm nhìn của người khác hay không.

Hiện tại, phân vùng thế giới của tôi là phân vùng không gian ô đơn giản (một lưới). Tôi muốn sử dụng một hình tam giác để thể hiện trường nhìn, nhưng làm thế nào tôi có thể tính toán các ô giao nhau với hình tam giác?

Tương tự như hình ảnh này: nhập mô tả hình ảnh ở đây

Các vùng màu đỏ là các ô tôi muốn tính toán, bằng cách kiểm tra xem tam giác có giao nhau với các ô đó hay không.

Cảm ơn trước.

BIÊN TẬP:

Chỉ để thêm vào sự nhầm lẫn (hoặc thậm chí có thể làm cho nó dễ dàng hơn). Mỗi ô có một vectơ cực tiểu và cực đại trong đó cực tiểu là góc dưới bên trái và cực đại là góc trên cùng bên phải.


Bạn không thể chia các ô thành các hình tam giác và kiểm tra tam giác?
Vịt Cộng sản

Các tế bào không phải là đa giác vật lý, chỉ là một biểu diễn không gian và nó tận dụng thời gian truy cập O (1) của một mảng. Nếu tôi có một vòng tròn lân cận xung quanh tác nhân, để ước tính các ô, tôi có thể tạo AABB bằng bán kính của vòng tròn và dễ dàng tìm thấy các giao điểm. Vấn đề ở đây là chỉ muốn các tế bào ở trước mặt tôi. Tôi chắc chắn có một số phương trình hình học để giúp đỡ, tôi không thể nghĩ ra bất kỳ điều gì cho cuộc sống của tôi.
Ray Dey

Câu trả lời:


6

Tính ba góc của tam giác fov của bạn, xoay chúng để đối mặt với cách chính xác và như vậy, sau đó thực hiện một trong các:

1) thực hiện kiểm tra điểm trong tam giác cho tất cả các mục tiêu tiềm năng

2) tính hộp giới hạn của tam giác này và thực hiện kiểm tra điểm trong tam giác cho tất cả các mục tiêu tiềm năng trong các ô trong hộp giới hạn này - đây sẽ là mã rất đơn giản để gỡ lỗi

Một cách tiếp cận tương tự là sử dụng một hình tứ giác chứ không phải là một lưới và thực hiện các giao điểm trên đó. Nếu truy cập ô O (1) đang tăng tốc cho bạn, thì chỉ cần kiểm tra tất cả các ô trong giới hạn của tam giác fov cho tam giác phải nhanh đến mức tức thì. Khi bạn đang xem xét các tùy chọn khác, tôi cho rằng không phải vậy và O (1) thực sự đang mất một bộ nhớ cache lớn khi bạn sử dụng bộ nhớ cache. Tất nhiên, bạn có thể nhìn vào hướng dẫn tìm nạp trước để chú thích đi bộ hộp giới hạn của bạn với ...

3) 'rasterise' tam giác này và kiểm tra các ô mà nó 'vẽ' - có thể là mã hiệu quả nhất, nhưng có lẽ chỉ là một chút khi tôi suy đoán tất cả bị chi phối bởi bộ nhớ cache và phụ thuộc vào mức độ phức tạp của các tế bào của bạn và mức độ chiếm dụng họ đang.

Một cách tiếp cận khác là kết xuất FOV thành một bitmap ngoài màn hình và sau đó đọc giá trị pixel cho từng đối tượng của bạn; bạn không thể 'trộn màu' nhưng với số lượng đối tượng hạn chế và bằng cách chọn cẩn thận màu sơn của bạn, bạn có thể suy ra ai đã nhìn thấy ai. Cách tiếp cận này tương tự như có bao nhiêu trò chơi tìm ra những gì người dùng đã nhấp vào - họ vẽ cảnh ngoài màn hình bằng cách sử dụng màu sắc vững chắc cho các khu vực nhấn. GPU rất nhanh khi lấp đầy tam giác ...


+1 cảm ơn vì điều này, tôi đã sử dụng hộp giới hạn cho hình tam giác để nhanh chóng chọn các ô thích hợp và đã sử dụng kiểm tra điểm trong tam giác để xác định thành viên nào của các ô đó nằm trong Trường quan sát :)
Ray Dey

3

Giải pháp chính tắc trong trình kết xuất phần mềm (phải thực hiện thuật toán chính xác này mỗi khi chúng quét hình tam giác), tôi tin rằng, để quét tam giác một hàng pixel mỗi lần. Các cạnh trái và phải của mỗi hàng và được tính bằng cách đi xuống các cạnh của tam giác bằng Bresenham , và sau đó bạn điền vào hàng giữa chúng.

Tôi đang xem qua nhiều chi tiết nhưng đó là ý tưởng cơ bản. Nếu bạn săn lùng "phần mềm kết xuất" và "rasterization tam giác", có lẽ bạn sẽ tìm thấy thêm một số chi tiết. Đây là một vấn đề được giải quyết tốt. Card đồ họa của bạn đang làm điều này hàng triệu lần một khung hình.

Nếu bạn muốn một giải pháp cụ thể hơn roguelike, đây là cách tôi triển khai FOV trong tôi. Nó dường như làm việc khá nhanh chóng. Về cơ bản, nó là một caster bóng đơn giản, hoạt động trên quãng tám, quét ra từ người chơi.


1
Đó là cách tiếp cận khá tuyệt vời.
Notabene

2

Tôi đang sử dụng một biến thể của thuật toán scanline để giải quyết chính xác cùng một vấn đề. Tôi bắt đầu bằng cách sắp xếp ba điểm tam giác theo chiều cao của chúng. Sau đó, về cơ bản tôi sẽ kiểm tra xem hai cạnh nằm ở bên trái hay bên phải. Đối với cạnh có hai cạnh, bạn phải đánh dấu hàng chúng ở nơi bạn thay đổi cạnh nào phân định các hàng của bạn. Đối với cạnh có một cạnh, bạn luôn có thể sử dụng nó.

Vì vậy, sau đó cho mỗi hàng, tôi biết hai cạnh nào phân định nó và tôi có thể tính các giới hạn trên và dưới theo hướng x. Nghe có vẻ khá phức tạp, nhưng nó ngưng tụ chỉ một vài dòng mã. Hãy chắc chắn rằng bạn xử lý trường hợp đặc biệt trong đó một cạnh hoàn toàn nằm ngang!


2

Làm thế nào về việc duy trì một phạm vi cột cho mỗi hàng trong tam giác? Những gì bạn có thể làm là đặt cột tối thiểu và tối đa cho mỗi hàng trong đó mỗi điểm và nơi mỗi đường tam giác đi qua một đường phân cách hàng ngang.

public class Point
{
    public float X;
    public float Y;
    public Point(float x, float y) { this.X = x; this.Y = y; }
}

public class Line
{
    float ROW_SIZE = 100f;
    float COL_SIZE = 100f;

    public Point P1, P2; // P1 has the lowest Y
    public float Slope, Intercept; // set in constructor
    public bool IsVertical;

    public Line(Point p1, Point p2)
    {
        if (p1.Y > p2.Y) { P1 = p2; P2 = p1; } // p1 has lowest Y
        else { P1 = p1; P2 = p2; }
        IsVertical = (p1.X == p2.X);
        if (!IsVertical) { Slope = (p2.Y - p1.Y) / (p2.X - p1.X); Intercept = p1.Y - Slope * p1.X; }
    }

    public void ExpandRanges(int[] minCol, int[] maxCol)
    {
        // start out at row, col where P1 is, which has lowest Y
        int row = (int)(P1.Y / ROW_SIZE);
        int col = (int)(P1.X / COL_SIZE);
        int lastRow = (int)(P2.Y / ROW_SIZE);
        int lastCol = (int)(P2.X / COL_SIZE);

        // expand row to include P1
        minCol[row] = Math.Min(col, minCol[row]); maxCol[row] = Math.Max(col, maxCol[row]);

        // now we find where our line intercepts each horizontal line up to P2
        float currY = P1.Y;
        float currX = P1.X;
        while (row < lastRow)
        {
            row = row + 1;
            float rowY = row * ROW_SIZE;
            float diffY = rowY - currY;
            float diffX = IsVertical ? 0f : diffY / Slope;
            currY = currY + diffY;
            currX = currX + diffX;
            col = (int)(currX / COL_SIZE);

            // expand rows above and below dividing line to include point
            minCol[row - 1] = Math.Min(col, minCol[row - 1]);
            maxCol[row - 1] = Math.Max(col, maxCol[row - 1]);
            minCol[row] = Math.Min(col, minCol[row]);
            maxCol[row] = Math.Max(col, maxCol[row]);
        }

        // expand last row to include P2
        minCol[lastRow] = Math.Min(lastCol, minCol[lastRow]);
        maxCol[lastRow] = Math.Max(lastCol, maxCol[lastRow]);
    }

    public static void Test()
    {
        Point p1 = new Point(160, 250);
        Point p2 = new Point(340, 250);
        Point p3 = new Point(250, 40);
        Line l1 = new Line(p1, p2);
        Line l2 = new Line(p2, p3);
        Line l3 = new Line(p3, p1);

        Line[] lines = { l1, l2, l3 };

        int rowCount = 4;
        int[] minCol = new int[rowCount];
        int[] maxCol = new int[rowCount];
        for (int i = 0; i < rowCount; i++)
        {
            minCol[i] = int.MaxValue;
            maxCol[i] = int.MinValue;
        }

        for (int i = 0; i < lines.Length; i++)
            lines[i].ExpandRanges(minCol, maxCol);

        for (int i = 0; i < rowCount; i++)
            Console.WriteLine("Row {0}:  {1} - {2}", i, minCol[i], maxCol[i]);
    }
}

Đầu ra:

Row 0:  2 - 2
Row 1:  1 - 3
Row 2:  1 - 3
Row 3:  2147483647 - -2147483648

1

Có một số công việc thuật toán được thực hiện trong cộng đồng roguelike liên quan đến FOV / LOS / chiếu sáng trong một thế giới dựa trên gạch.

Có lẽ bạn có thể tìm thấy một cái gì đó trên trang này có thể được sử dụng để giúp giải quyết vấn đề của bạn: http://roguebasin.roguelikedevelopment.org/index.php?title=Field_of_Vision

Cụ thể "FOV cho phép" có thể được áp dụng nhiều nhất cho tình huống của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.