Làm cách nào tôi có thể vẽ một mũi tên ở cạnh màn hình chỉ vào một đối tượng ở ngoài màn hình?


12

Tôi muốn làm những gì được mô tả trong chủ đề này:

http://www.allegro.cc/forums/print-thread/283220

Tôi đã thử một loạt các phương pháp được đề cập ở đây.

Đầu tiên tôi đã thử sử dụng phương pháp được mô tả bởi Carrus85:

Chỉ cần lấy tỷ lệ của hai hypontenuses tam giác (không quan trọng bạn sử dụng cách nào để sử dụng cho cái kia, tôi đề nghị điểm 1 và điểm 2 là khoảng cách bạn tính toán). Điều này sẽ cung cấp cho bạn tỷ lệ phần trăm tỷ lệ của hình tam giác trong góc từ hình tam giác lớn hơn. Sau đó, bạn chỉ cần nhân deltax với giá trị đó để lấy offset tọa độ x và deltay với giá trị đó để lấy offset tọa độ y.

Nhưng tôi không thể tìm ra cách tính vật thể cách xa mép màn hình.

Sau đó, tôi đã thử sử dụng phương pháp đúc tia (điều mà tôi chưa bao giờ thực hiện trước đây) được đề xuất bởi 23yrold3yrold:

Bắn một tia từ giữa màn hình vào đối tượng ngoài màn hình. Tính vị trí trên hình chữ nhật mà tia giao nhau. Có tọa độ của bạn.

Trước tiên tôi tính toán cạnh huyền của tam giác được hình thành bởi sự khác biệt về vị trí x và y của hai điểm. Tôi đã sử dụng điều này để tạo ra một vector đơn vị dọc theo dòng đó. Tôi lặp qua vectơ đó cho đến khi tọa độ x hoặc tọa độ y tắt khỏi màn hình. Hai giá trị x và y hiện tại sau đó tạo thành x và y của mũi tên.

Đây là mã cho phương pháp đúc tia của tôi (được viết bằng C ++ và Allegro 5)

void renderArrows(Object* i)
{
    float x1 = i->getX() + (i->getWidth() / 2);
    float y1 = i->getY() + (i->getHeight() / 2);

    float x2 = screenCentreX;
    float y2 = ScreenCentreY;

    float dx = x2 - x1;
    float dy = y2 - y1;
    float hypotSquared = (dx * dx) + (dy * dy);
    float hypot = sqrt(hypotSquared);

    float unitX = dx / hypot;
    float unitY = dy / hypot;

    float rayX = x2 - view->getViewportX();
    float rayY = y2 - view->getViewportY();
    float arrowX = 0;
    float arrowY = 0;

    bool posFound = false;
    while(posFound == false)
    {
        rayX += unitX;
        rayY += unitY;

        if(rayX <= 0 ||
            rayX >= screenWidth ||
            rayY <= 0 ||
            rayY >= screenHeight)
        {
            arrowX = rayX;
            arrowY = rayY;
            posFound = true;
        }               
    }

    al_draw_bitmap(sprite, arrowX - spriteWidth, arrowY - spriteHeight, 0);
}

Điều này đã tương đối thành công. Mũi tên được hiển thị ở phần dưới cùng bên phải của màn hình khi các đối tượng nằm ở phía trên và bên trái màn hình như thể các vị trí của mũi tên được vẽ đã được xoay 180 độ quanh tâm màn hình.

Tôi cho rằng điều này là do thực tế là khi tôi tính toán cạnh huyền của tam giác, nó sẽ luôn dương bất kể sự khác biệt về x hay khác biệt trong y là âm.

Nghĩ về nó, việc truyền tia dường như không phải là một cách tốt để giải quyết vấn đề (do thực tế là nó liên quan đến việc sử dụng sqrt () và một vòng lặp lớn).

Câu trả lời:


6

Vì vậy, bạn có hai tọa độ hoặc vectơ, một là trung tâm của màn hình (C từ bây giờ trở đi) và cái còn lại là đối tượng của bạn (P từ bây giờ trở đi.)

Nếu bạn biết một số phép toán, bạn có thể biết rằng một dòng có thể được biểu thị dưới dạng gốc và vectơ chỉ hướng. Nguồn gốc là trung tâm màn hình của bạn, trong khi vectơ chỉ hướng có thể được trừ C từ P. Phương trình này cũng có thể được biểu thị ở dạng tham số, về cơ bản là giống nhau:

x = (P.x - C.x)t + C.x;
y = (P.y - C.y)t + C.y;

Thấy (P.? - C.?)chút không? Đó là vectơ chỉ đường của bạn (như tôi đã nói, trừ C khỏi P). C.?Bit cuối cùng là nguồn gốc của dòng.

tlà một biến mà có thể thay đổi từ 0đến 1, 0là nguồn gốc của vector (nếu bạn hoạt động, xywoulld trở C.xC.y), 1là đối tượng của bạn phối hợp (một lần nữa, điều hành, nó sẽ trở thành P.xP.y, hoặc "kết thúc" của vector, nếu bạn muốn) và các giá trị ở giữa nội suy giữa hai đầu của phân khúc của bạn. Bạn cũng có thể gán các giá trị bên ngoài: bên dưới 0bạn sẽ đảo ngược hướng vectơ của mình và ở trên 1bạn sẽ "mở rộng" vectơ của mình hơn nữa theo cùng một hướng.

Một khi bạn có được điều này, nó sẽ khá dễ dàng. Mục tiêu của bạn là tìm điểm của vectơ này ( xycho một giá trị nhất định t) trong đó X=WIDTHhoặc Y=HEIGHT, bất cứ điều gì đến trước. Như bạn có thể thấy, tlà biến duy nhất của bạn ở đây:

(0)
WIDTH = (P.x - C.x)t + C.x;
and
HEIGHT = (P.y - C.y)t + C.y;

Hoặc diễn đạt lại:

(1)
t = (WIDTH - C.x)/(P.x - C.x)
and
t = (HEIGHT - C.y)/(P.y - C.y)

Điều này sẽ có được điểm cắt của đường được xác định bởi vectơ của bạn ở viền bên phải và trên cùng của bạn. Điều tương tự cũng xảy ra đối với các viền trái và dưới màn hình của bạn, nơi bạn cần kiểm tra lại 0cả hai trường hợp, không WIDTHHEIGHT.

Vì cuối cùng nó sẽ cắt các đường viền, thậm chí ngoài màn hình, tgiá trị thấp nhất sẽ là điểm liên lạc đầu tiên của bạn. Đảo ngược hoạt động và áp dụng tgiá trị tìm thấy của bạn trên các phương trình tại (0)(cùng giá trị cho cả hai!) Sẽ mang lại một giá trị mới (x,y), sẽ là tọa độ cắt của bạn.

Có thể có một số lỗi toán học hoặc sự khác biệt thực hiện cho vấn đề của bạn, nhưng đó là ý tưởng cơ bản. Tôi cũng để lại một số phần (luôn có bốn trường hợp cắt và bạn chỉ cần một phần) nhưng một chút suy nghĩ sẽ đưa bạn đến một giải pháp cuối cùng :)


Cảm ơn. Tôi sẽ cho nó đi. EDIT: Vì tò mò, bạn có nghĩ phương pháp này là phương pháp mà Carrus85 đã mô tả (sử dụng tỷ lệ của hypotenuse) không?
Adam Henderson

1
@AdamHenderson Tôi rất vui lòng giúp đỡ :) Hãy nhớ rằng bạn có thể giữ vectơ chỉ đường của mình để bạn có thể vẽ mũi tên của mình sau này. Bạn có thể chuẩn hóa nó để có được vectơ chỉ hướng đơn nhất của mình, trừ đi số arrow-lengthlần từ vectơ cắt "et voila", bạn có nguồn gốc và đích đến cho mũi tên của mình.
kaoD

1
@AdamHenderson trực quan đó là điều tương tự, vì dòng của bạn là thôi miên mà anh ấy đang nói đến. Thực tế, nó không giống nhau, vì đề xuất của anh ấy liên quan đến các góc (và do đó lượng giác) mà tôi nghĩ là quá mức cho việc này. Điều này hoàn toàn không liên quan đến các hình tam giác (mặc dù bạn có thể nghĩ vectơ của mình là một hình tam giác trong đó cạnh huyền là vectơ và cả hai bên là xycác thành phần.)
kaoD

Cảm ơn một lần nữa! Bạn đã giải quyết vấn đề tiếp theo của tôi là chỉ mũi tên theo đúng hướng.
Adam Henderson

1
@AdamHenderson yep, đáy nếu trục bị lật. BTW, tôi khuyên bạn nên đăng một liên kết đến câu hỏi này trong diễn đàn của Allegro để tham khảo trong tương lai.
kaoD
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.