Ekranın dışında, ekran dışında olan bir nesneyi gösteren bir oku nasıl çizebilirim?


12

Bu konuda açıklananları yapmak istiyorum:

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

Burada bahsedilen çeşitli yöntemleri denedim.

İlk önce Carrus85 tarafından açıklanan yöntemi kullanmaya çalıştım:

Sadece iki üçgen hipontenüs oranını alın (diğeri için hangi üçgeni kullandığınız önemli değil, hesapladığınız mesafe olarak nokta 1 ve nokta 2'yi öneriyorum). Bu, köşedeki üçgenin daha büyük üçgenden en boy oranını verecektir. Ardından, x koordinat ofsetini elde etmek için deltax'ı bu değerle çarpar ve y-koordinat ofsetini elde etmek için deltay'ı bu değerle çarparsınız.

Ancak nesnenin ekranın kenarından ne kadar uzakta olduğunu hesaplamanın bir yolunu bulamadım.

Sonra 23yrold3yrold ​​tarafından önerilen (daha önce hiç yapmadım) ışın döküm kullanarak çalıştı:

Ekranın ortasından ekran nesnesine bir ışın verin. Işının dikdörtgen üzerinde nerede kesiştiğini hesaplayın. İşte koordinatlarınız.

İlk önce iki noktanın x ve y konumlarındaki farkın oluşturduğu üçgenin hipotenüsünü hesapladım. Bunu, bu çizgi boyunca bir birim vektörü oluşturmak için kullandım. X koordinatı veya y koordinatı ekranın dışına çıkıncaya kadar bu vektörde dolaştım. Geçerli iki x ve y değeri, okun x ve y değerlerini oluşturur.

İşte ışın döküm yöntemimin kodu (C ++ ve Allegro 5 ile yazılmış)

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);
}

Bu nispeten başarılıydı. Nesneler ekranın üstünde ve solundayken, okların çizildiği yerlerin yerleri ekranın ortasına 180 derece döndürülmüş gibi oklar ekranın sağ alt bölümünde görüntülenir.

Bunun üçgenin hipotenüsünü hesaplarken, x'deki farkın veya y'deki farkın negatif olup olmadığına bakılmaksızın her zaman pozitif olacağı gerçeğinden kaynaklandığını varsaydım.

Bunu düşünmek, ışın dökümü problemi çözmek için iyi bir yol gibi görünmüyor (sqrt () ve döngü için büyük bir kullanımı içermesi nedeniyle).

Yanıtlar:


6

Yani iki koordinatınız veya vektörünüz var, biri ekranın merkezi (bundan sonra C) ve diğeri nesneniz (bundan sonra P).

Biraz matematik biliyorsanız, bir satırın başlangıç ​​noktası ve yön vektörü olarak ifade edilebileceğini biliyor olabilirsiniz. Orijin ekran merkezinizdir, yön vektörü C'yi P'den çıkarırken bulunabilir. Bu denklem, aynı şekilde parametrik formda da ifade edilebilir, bu aslında aynıdır:

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

Bkz (P.? - C.?)biraz? Bu sizin yön vektörünüzdür (dediğim gibi C'yi P'den çıkarın). Son C.?bit, çizginin kaynağıdır.

tarasında değişebilen bir değişkendir 0için 1, 0vektör kökeni olan (eğer Ameliyatta, xve yhaline woulld C.xve C.y), 1sizin nesne koordinat olmak (yine işletim, bu olacağımızı P.xve P.yya vektör "son", isterseniz) ve segmentinizin her iki ucu arasındaki enterpolasyon arasındaki değerler. Ayrıca dış değerler de atayabilirsiniz: aşağıda 0vektör yönünüzü tersine çevirirsiniz ve üstte 1vektörünüzü aynı yönde "genişletirsiniz".

Bunu aldıktan sonra, oldukça kolay olur. Amacınız, bu vektörün noktasını ( xve yverilen bir değer için t) önce X=WIDTHveya Y=HEIGHTne olursa olsun bulmaktır . Gördüğünüz gibi, tburadaki tek değişkeniniz:

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

Veya tekrar ifade etmek gerekirse:

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

Bu, vektörünüz tarafından tanımlanan çizginin sağ ve üst sınırlarında kesme noktasını alacaktır. Aynısı, ekranınızın sol ve alt kenarlıkları için de geçerlidir, burada 0her iki durum için de kontrol etmeniz gerekir , WIDTHve değil HEIGHT.

Sonunda ekran dışında bile sınırları keseceğinden, en düşük tdeğer ilk temas noktanız olacaktır. İşlemi tersine çevirmek ve bulunan tdeğerinizi (0)(her ikisi için aynı değer!) ' Deki denklemlere (x,y)uygulamak, kesme koordinatlarınız olacak yeni bir getirecektir .

Sorununuz için bazı matematik hataları veya uygulama farklılıkları olabilir, ancak temel fikir budur. Ben de bazı parçaları dışarıda bıraktım (her zaman dört kesme vakası vardır ve sadece bir tane gerekir) ama biraz düşünce sizi nihai bir çözüme götürecektir :)


Teşekkürler. Bi şans tanıcam. DÜZENLEME: Sadece meraktan, sence bu yöntem Carrus85'in tarif ettiği yöntem (hipotenüs oranını kullanarak)?
Adam Henderson

1
@AdamHenderson Yardım etmekten mutluluk duyuyorum :) Daha sonra oku çizebilmeniz için yön vektörünüzü koruyabileceğinizi unutmayın. Üniter yön vektörünüzü almak, arrow-length"et voila" kesme vektöründen süreleri çıkarmak için normalleştirebilirsiniz, okunuz için bir başlangıç ​​noktası ve hedefiniz vardır.
kaoD

1
@AdamHenderson görsel olarak aynı şey, çünkü çizginiz bahsettiği hipotenüs. Pratik olarak, aynı değil, çünkü önerisi, bunun için aşırıya kaçma olduğunu düşündüğüm açıları (ve bu nedenle trigonometri) içeriyor. Bu, hiç üçgen içermez (vektörünüzü hipotenüsün vektör olduğu ve her iki tarafın da xve ybileşenler olduğu bir üçgen olarak düşünebilirsiniz .)
kaoD

Tekrar teşekkürler! Bir sonraki problemimi oku doğru yönde göstererek çözdün.
Adam Henderson

1
@AdamHenderson evet, eksen çevrilirse alt. BTW, ileride başvurmak üzere Allegro'nun forumunda bu soruya bir bağlantı göndermenizi öneririm.
kaoD
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.