Bagaimana saya bisa menggambar panah di tepi layar yang menunjuk ke objek yang mati layar?

12

Saya ingin melakukan apa yang dijelaskan dalam topik ini:

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

Saya telah mencoba berbagai metode yang disebutkan di sini.

Pertama saya mencoba menggunakan metode yang dijelaskan oleh Carrus85:

Ambil saja rasio dari kedua segitiga hypontenus (tidak masalah triagle mana yang Anda gunakan untuk yang lain, saya sarankan titik 1 dan titik 2 sebagai jarak yang Anda hitung). Ini akan memberi Anda persentase aspek rasio segitiga di sudut dari segitiga yang lebih besar. Kemudian Anda cukup mengalikan deltax dengan nilai itu untuk mendapatkan offset koordinat-x, dan menunda dengan nilai itu untuk mendapatkan offset koordinat-y.

Tetapi saya tidak dapat menemukan cara untuk menghitung seberapa jauh objek tersebut berada jauh dari tepi layar.

Saya kemudian mencoba menggunakan ray casting (yang belum pernah saya lakukan sebelumnya) yang disarankan oleh 23yrold3yrold:

Tembakan sinar dari tengah layar ke objek offscreen. Hitung di mana pada persegi panjang sinar berpotongan. Itu koordinatmu.

Saya pertama kali menghitung sisi miring dari segitiga yang dibentuk oleh perbedaan posisi x dan y dari dua titik. Saya menggunakan ini untuk membuat vektor satuan di sepanjang garis itu. Saya memutar-mutar vektor itu sampai koordinat x atau koordinat y tidak ada di layar. Dua nilai x dan y saat ini kemudian membentuk x dan y dari panah.

Berikut adalah kode untuk metode pengecoran sinar saya (ditulis dalam C ++ dan 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);
}

Ini relatif sukses. Panah ditampilkan di bagian kanan bawah layar ketika objek berada di atas dan kiri layar seolah-olah lokasi di mana panah ditarik telah diputar 180 derajat di sekitar tengah layar.

Saya berasumsi ini karena fakta bahwa ketika saya menghitung sisi miring dari segitiga, itu akan selalu positif terlepas dari apakah perbedaan dalam x atau perbedaan dalam y adalah negatif.

Berpikir tentang hal itu, ray casting sepertinya bukan cara yang baik untuk menyelesaikan masalah (karena fakta bahwa itu melibatkan penggunaan sqrt () dan besar untuk loop).

Adam Henderson
sumber

Jawaban:

6

Jadi Anda memiliki dua koordinat atau vektor, satu adalah tengah layar (C mulai sekarang) dan yang lainnya adalah objek Anda (P mulai sekarang.)

Jika Anda tahu beberapa matematika, Anda mungkin tahu bahwa garis dapat dinyatakan sebagai asal dan vektor arah. Asal adalah layar-pusat Anda, sedangkan vektor arah dapat ditemukan mengurangkan C dari P. Persamaan ini juga dapat dinyatakan dalam bentuk parametrik, yang pada dasarnya sama:

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

Lihat (P.? - C.?)sedikit? Itu vektor arah Anda (seperti yang saya katakan, kurangi C dari P). C.?Bit terakhir adalah asal dari baris.

tadalah variabel yang dapat bervariasi dari 0menjadi 1, 0menjadi asal vektor (jika Anda beroperasi, xdan akan ymenjadi C.xdan C.y), 1menjadi objek koordinat Anda (sekali lagi, operasi, itu akan menjadi P.xdan P.y, atau "akhir" dari vektor, jika Anda mau) dan nilai di antara interpolasi antara kedua ujung segmen Anda. Anda juga dapat menetapkan nilai luar: di bawah ini 0Anda akan mendapatkan arah vektor terbalik dan di atas 1Anda akan "memperluas" vektor Anda lebih jauh ke arah yang sama.

Setelah Anda mendapatkan ini, itu menjadi sangat mudah. Tujuan Anda adalah menemukan titik vektor ini ( xdan yuntuk nilai tertentu t) di mana X=WIDTHatau Y=HEIGHT, apa pun yang lebih dulu. Seperti yang Anda lihat, tsatu-satunya variabel Anda di sini:

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

Atau mengekspresikannya kembali:

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

Ini akan mendapatkan titik potong dari garis yang ditentukan oleh vektor Anda di batas kanan dan atas Anda. Hal yang sama berlaku untuk batas kiri dan bawah layar Anda, di mana Anda perlu memeriksa 0kedua kasus, bukan WIDTHdan HEIGHT.

Karena pada akhirnya akan memotong perbatasan, bahkan di luar layar, nilai terendah takan menjadi titik kontak pertama Anda. Membalik operasi dan menerapkan tnilai yang Anda temukan pada persamaan di (0)(nilai yang sama untuk keduanya!) Akan membawa yang baru (x,y), yang akan menjadi koordinat pemotongan Anda.

Mungkin ada beberapa kesalahan matematika atau perbedaan implementasi untuk masalah Anda, tetapi itulah ide dasarnya. Saya meninggalkan beberapa bagian juga (selalu ada empat kasus pemotongan, dan Anda hanya perlu satu) tetapi sedikit pemikiran akan membawa Anda ke solusi akhir :)

kaoD
sumber
Terima kasih. Saya akan mencobanya. EDIT: Hanya karena penasaran, apakah Anda pikir metode ini adalah yang dijelaskan oleh Carrus85 (menggunakan rasio sisi miring)?
Adam Henderson
1
@ AdamHenderson Saya senang membantu :) Ingat Anda dapat menjaga vektor arah Anda sehingga Anda dapat menggambar panah Anda nanti. Anda dapat menormalkannya untuk mendapatkan vektor arah kesatuan, kurangi arrow-lengthwaktu dari vektor pemotongan "et voila", Anda memiliki asal dan tujuan panah Anda.
kaoD
1
@AdamHenderson secara visual itu hal yang sama, karena kalimat Anda adalah sisi miring yang dia bicarakan. Praktis, itu tidak sama, karena sarannya melibatkan sudut (dan karenanya trigonometri) yang saya pikir terlalu banyak untuk ini. Ini tidak melibatkan segitiga sama sekali (meskipun Anda bisa memikirkan vektor Anda sebagai segitiga di mana sisi miring adalah vektor dan kedua belah pihak adalah xdan ykomponen.)
kaoD
Terima kasih lagi! Anda memecahkan masalah saya berikutnya dengan mengarahkan panah ke arah yang benar.
Adam Henderson
1
@ AdamHenderson ya, bawah jika sumbu dibalik. BTW, saya sarankan memposting tautan ke pertanyaan ini di forum Allegro untuk referensi di masa mendatang.
kaoD