ฉันจะวาดลูกศรที่ขอบของหน้าจอที่ชี้ไปยังวัตถุที่อยู่นอกหน้าจอได้อย่างไร


12

ฉันต้องการทำสิ่งที่อธิบายไว้ในหัวข้อนี้:

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

ฉันได้ลองวิธีการต่าง ๆ ที่กล่าวถึงที่นี่

ก่อนอื่นฉันพยายามใช้วิธีที่อธิบายโดย Carrus85:

ลองหาอัตราส่วนของสามเหลี่ยมไฮโปเทนไนต์สามเหลี่ยมสองอัน (ไม่สำคัญว่าคุณจะใช้ triagle ตัวไหนสำหรับอันอื่นฉันขอแนะนำจุดที่ 1 และจุดที่ 2 ตามระยะทางที่คุณคำนวณ) นี่จะให้เปอร์เซ็นต์อัตราส่วนของสามเหลี่ยมที่มุมจากสามเหลี่ยมขนาดใหญ่ จากนั้นคุณก็คูณค่าลบด้วยค่านั้นเพื่อให้ได้ค่าพิกัด x พิกัดและเลื่อนตามค่านั้นเพื่อให้ได้ค่าชดเชยพิกัด y

แต่ฉันไม่สามารถหาวิธีคำนวณว่าวัตถุอยู่ห่างจากขอบของหน้าจอมากแค่ไหน

ฉันลองใช้การฉายรังสี (ซึ่งไม่เคยทำมาก่อน) แนะนำโดย 23yrold3yrold:

ยิงรังสีออกจากกึ่งกลางของหน้าจอไปยังวัตถุที่อยู่นอกจอ คำนวณว่าจุดใดที่สี่เหลี่ยมผืนผ้าตัดกับแสง มีพิกัดของคุณ

ฉันคำนวณด้านตรงข้ามมุมฉากของสามเหลี่ยมที่เกิดขึ้นจากความแตกต่างในตำแหน่ง x และ y ของจุดสองจุด ฉันใช้สิ่งนี้เพื่อสร้างเวกเตอร์หน่วยตามเส้นนั้น ฉันวนลูปผ่านเวกเตอร์นั้นจนกระทั่งพิกัด x หรือพิกัด y ไม่อยู่บนหน้าจอ ค่า x และ y สองค่าปัจจุบันจากนั้นสร้างค่า x และ y ของลูกศร

นี่คือรหัสสำหรับวิธีการฉายรังสีของฉัน (เขียนใน C ++ และ 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);
}

นี่ค่อนข้างประสบความสำเร็จ ลูกศรจะปรากฏในส่วนด้านล่างขวาของหน้าจอเมื่อวัตถุอยู่ด้านบนและด้านซ้ายของหน้าจอราวกับว่าตำแหน่งของลูกศรที่ถูกวาดถูกหมุน 180 องศารอบจุดศูนย์กลางของหน้าจอ

ฉันคิดว่านี่เป็นเพราะความจริงที่ว่าเมื่อฉันคำนวณด้านตรงข้ามมุมฉากของสามเหลี่ยมมันจะเป็นค่าบวกเสมอไม่ว่าผลต่างของ x หรือความแตกต่างใน y จะเป็นลบหรือไม่

เมื่อคิดถึงเรื่องนี้การฉายรังสีไม่ได้เป็นวิธีที่ดีในการแก้ปัญหา (เนื่องจากความจริงที่ว่ามันเกี่ยวข้องกับการใช้ sqrt () และขนาดใหญ่สำหรับการวนรอบ)

คำตอบ:


6

ดังนั้นคุณจึงมีสองพิกัดหรือเวกเตอร์หนึ่งอันคือจุดกึ่งกลางของหน้าจอ (ต่อจากนี้ไป) และอีกอันคือวัตถุของคุณ (P จากนี้เป็นต้นไป)

ถ้าคุณรู้คณิตศาสตร์คุณอาจรู้ว่าเส้นหนึ่งสามารถแสดงเป็นจุดกำเนิดและเวกเตอร์ทิศทางได้ จุดกำเนิดคือศูนย์หน้าจอของคุณในขณะที่เวกเตอร์ทิศทางสามารถลบ C จาก P ได้สมการนี้ยังสามารถแสดงในรูปแบบพารามิเตอร์ซึ่งโดยพื้นฐานแล้วจะเหมือนกัน:

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

เห็น(P.? - C.?)ไหม นั่นคือเวกเตอร์บอกทิศทางของคุณ (ดังที่ฉันพูดแล้วลบ C ออกจาก P) C.?บิตสุดท้ายคือจุดเริ่มต้นของบรรทัด

tเป็นตัวแปรซึ่งจะแตกต่างจาก0การ1, 0การเป็นที่มาของเวกเตอร์ (ถ้าคุณทำงานxและywoulld กลายเป็นC.xและC.y) 1เป็นวัตถุของคุณประสานงาน (อีกครั้งจากการดำเนินงานก็ต้องการกลายเป็นP.xและP.yหรือ "จบ" ของเวกเตอร์ หากคุณต้องการ) และค่าระหว่างการแก้ไขระหว่างปลายทั้งสองของกลุ่มของคุณ นอกจากนี้คุณยังสามารถกำหนดค่าภายนอก: ด้านล่าง0คุณจะได้รับทิศทางเวกเตอร์ของคุณย้อนกลับและด้านบน1คุณจะ "ขยาย" เวกเตอร์ของคุณต่อไปในทิศทางเดียวกัน

เมื่อคุณได้รับสิ่งนี้มันจะค่อนข้างง่าย จุดประสงค์ของคุณคือการหาจุดของเวกเตอร์นี้ ( xและyค่าที่กำหนดt) ที่X=WIDTHหรือY=HEIGHTอะไรก็ตามที่มาก่อน อย่างที่คุณเห็นtเป็นตัวแปรเดียวของคุณที่นี่:

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

หรือแสดงซ้ำ:

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

นี่จะเป็นจุดตัดของเส้นที่เวกเตอร์กำหนดไว้บนขอบด้านขวาและขอบบน เดียวกันจะไปสำหรับชายแดนด้านซ้ายและด้านล่างของหน้าจอของคุณที่คุณต้องตรวจสอบกับ0ทั้งสองกรณีไม่ได้และWIDTHHEIGHT

เนื่องจากในที่สุดมันจะตัดขอบแม้กระทั่งหน้าจอปิดtค่าต่ำสุดจะเป็นจุดแรกของการติดต่อของคุณ การย้อนกลับการดำเนินการและการใช้tค่าที่คุณพบกับสมการที่(0)(ค่าเดียวกันสำหรับทั้งคู่!) จะนำสิ่งใหม่(x,y)มาซึ่งจะเป็นพิกัดการตัดของคุณ

อาจมีข้อผิดพลาดทางคณิตศาสตร์หรือความแตกต่างของการใช้งานสำหรับปัญหาของคุณ แต่นั่นเป็นแนวคิดพื้นฐาน ฉันออกบางส่วนด้วย (มีสี่กรณีการตัดเสมอและคุณต้องการเพียงหนึ่ง) แต่ความคิดเล็กน้อยจะนำคุณไปสู่ทางออกสุดท้าย :)


ขอบคุณ ฉันจะไปเอง แก้ไข: จากความอยากรู้อยากเห็นคุณคิดว่าวิธีนี้เป็นวิธีที่ Carrus85 อธิบาย (ใช้อัตราส่วนของด้านตรงข้ามมุมฉาก) หรือไม่
Adam Henderson

1
@ AdamHenderson ฉันดีใจที่ได้ช่วย :) จำไว้ว่าคุณสามารถรักษาทิศทางเวกเตอร์ของคุณเพื่อให้คุณสามารถวาดลูกศรของคุณในภายหลัง คุณสามารถทำให้มันเป็นมาตรฐานเพื่อให้ได้เวกเตอร์ทิศทางรวมกัน, ลบมันarrow-lengthออกจากเวกเตอร์ตัด "et voila", คุณมีต้นทางและปลายทางสำหรับลูกศรของคุณ
kaoD

1
@ AdamHenderson มองเห็นมันเป็นสิ่งเดียวกันเนื่องจากบรรทัดของคุณคือด้านตรงข้ามมุมฉากที่เขาพูดถึง ในทางปฏิบัติมันไม่เหมือนกันเนื่องจากคำแนะนำของเขาเกี่ยวข้องกับมุม (และตรีโกณมิติดังนั้น) ซึ่งฉันคิดว่ามันเกินความจริงสำหรับเรื่องนี้ สิ่งนี้ไม่เกี่ยวข้องกับรูปสามเหลี่ยมเลย (แม้ว่าคุณจะคิดว่าเวกเตอร์ของคุณเป็นรูปสามเหลี่ยมที่ด้านตรงข้ามมุมฉากเป็นเวกเตอร์และทั้งสองด้านเป็นxและyส่วนประกอบ)
kaoD

ขอบคุณอีกครั้ง! คุณแก้ไขปัญหาต่อไปของฉันในการชี้ลูกศรไปในทิศทางที่ถูกต้อง
Adam Henderson

1
@ AdamHenderson อ๋อล่างถ้าแกนพลิก BTW ฉันขอแนะนำให้โพสต์ลิงก์ไปยังคำถามนี้ในฟอรัมของ Allegro เพื่อใช้อ้างอิงในอนาคต
kaoD
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.