Çarpışma algılamanın çözünürlükten bağımsız olarak çalışması için ekrandaki fare konumunu “haritalamak” kötü bir fikir midir?


16

Varsayılan çözünürlüğü 800x600 olan bir oyun düşünün. Çarpışma maskeli nesneler 800x600 boyutunda bir oyun dünyasına yerleştirilir. Çarpışma maskeleri, farenin ne zaman çarpıştığını algılayabilir.

Şimdi oyunu 1024x768 boyutuna kadar ölçeklendirdiğimizi düşünün (her şeyi bir katmana dönüştürüp ardından tüm katmanı aynı anda ölçekleyerek grafikleri ölçeklendirdiğimizi varsayalım). Bu yeni çözünürlükte fare ile çarpışmaların düzgün çalışmasını sağlamak için iki seçeneğimiz var:

A.) Dünyayı 1024x768'e kadar ölçeklendirin ve her nesnenin çarpışma maskesini buna göre ölçeklendirin.

B.) Fare konumunu orijinal dünyaya "eşleyin" (800x600).

"Harita" ile fare konumunu orijinal 800x600 dünyasına ölçeklemek istedim. Örneğin, ekrandaki fare konumu (1024, 768) ise, dünyadaki fare konumu (800, 600) olur.

Şimdi belli ki, B seçeneği gerektirir yolu daha az hesaplama ve muhtemelen geometrik hataları daha az olmakla birlikte, daha sonra düzeltmek için cehennem olacak bu yöntemle gitmeyi öngörülemeyen sonuçları var gibi o da, bana nazik "hackish" nin hisseder.

Hangi yöntemle gitmeliyim: A, B veya başka bir şey?


2
Klasik Thunder'ın işaret ettiği gibi, ekran koordinatları dünya koordinatları veya nesne koordinatları ile aynı olmamalıdır. Genellikle dönüşümler yapmak istersiniz (temel olarak, eşlemeler dediğiniz gibi , ancak genellikle matris matematiği ile yapılır).
Dan

Yanıtlar:


38

Tipik olarak (2d oyunlar için bile) oyun için çözünürlükten bağımsız ayrı bir koordinat sistemi vardır, bu genellikle dünya alanı olarak adlandırılır. Bu, keyfi bir çözünürlüğe ölçeklendirmenizi sağlar.

Bunu başarmanın en kolay yolu, aslında dünya uzayından (keyfi ünitelerinizden) ekran uzayına (ekrandaki pikseller) geçişi tanımlayan bir matris olan bir 2D Kamera kullanmaktır. Bu matematikle uğraşmayı önemsiz kılar.

XNA 2d Kamera Kaydırma'nın aşağıdaki bölümüne bir göz atın - neden matris dönüşümü kullanıyorsunuz?

Koordinat sistemi tanımları arasında dönüştürmeyi gerçekten kolaylaştırır

Ekrandan dünya alanına gitmek için Vector2.Transform'u kullanın. Bu genel olarak nesne toplama için farenin dünyadaki yerini almak için kullanılır.

Vector2.Transform(mouseLocation, Matrix.Invert(Camera.TransformMatrix));

Dünyadan ekran alanına geçmek için tam tersini yapmanız yeterlidir.

Vector2.Transform(mouseLocation, Camera.TransformMatrix);

Matris kullanmanın biraz öğrenmekten başka bir dezavantajı yoktur.


... ve aslında, genel olarak konuşursak, modern donanım, SSE, NEON, vb. gibi vektörizasyon mimarileri aracılığıyla matris işlemleri için tasarlanmıştır.
Mühendis

1
Hafif sorumluluk reddi: XNA, microsoft tarafından kullanımdan kaldırılmıştır, ancak Monogame aynı API'yı kullanmaktadır.
Pharap

1
Elbette, iki koordinat sistemi arasında çeviri yapmak için matrisler kullanmak akıllıdır. Peki bu soruya nasıl cevap veriyor? Yine de, A sisteminden B sistemine veya B'den A'ya eşlemek isteyip istemediğinize ve varsa sonuçlarının ne olduğuna karar vermelisiniz.
mastov

"Çarpışma algılamanın çözünürlükten bağımsız olarak çalışması için ekrandaki fare konumunu" haritalamak "kötü bir fikir mi?" "İki koordinat sistemi arasında çeviri yapmak için matris kullanmak akıllıca" tarafından yanıtlandı ...
ClassicThunder

Ayrıca, "Sistem A'dan sistem B'ye veya B'den A'ya eşleşmek isteyip istemediğinize ve varsa sonuçlarının ne olduğuna karar vermelisiniz." çözünürlük ve ölçeğe bağlı olmayan keyfi bir yöntem kullanmanız gerektiğini söyleyerek. Bu nedenle, A veya B'nin çözünürlük olup olmadığına bağlı olarak C -> A veya C -> B. Tabii ki C, sizin için tasarladığınız bir temel çözünürlüğe eşit olabilir ve oradan ölçeklendirebilirsiniz. Nokta tüm matematik aynı koordinat sisteminde olur ve sadece render için ölçek.
Mayıs 16:45

2

Başka bir seçenek: Her bir giriş fare hareketi olayında, oyun içi fare imlecini fare olayındaki piksel sayısına karşılık gelen oyun piksellerinin sayısına göre hareket ettirin. Bu, gerçek fare işaretçisini merkeze kilitleyen ve hedef yönünü, giriş faresi hareketine karşılık gelen bir miktarda döndüren 3D oyunlar için doğal olarak gelir, ancak oyun içi fare imlecini temsil eden bir hareketli grafiği hareket ettirerek de aynı şekilde yapabilirsiniz.

Belli bir şekilde, merkeze çarpık hale getirilmesinden kaynaklanan herhangi bir giriş fare hareketi olayını görmezden gelmelisiniz ve oyununuzda herhangi bir giriş gecikmesi varsa, imlecin tepkisizliği en sarsıcı ve göze çarpan özellik olacaktır.

Kısmen, hangi çözümü kullandığınız, fare konumunun oynanışta ne kadar önemli olduğuna bağlıdır. Bu bir RTS ise ve oyuncu sadece birimleri seçmek için tıklıyorsa, muhtemelen A veya B'nizden hangisi daha kolaysa gidebilirsiniz. Yukarıdan aşağıya bir nişancıysa ve fare karakterin hareketlerini doğrudan kontrol ederse, muhtemelen karakterin sadece çözünürlüğe değil, aynı zamanda fare hareketi gibi şeylere göre nasıl hareket edebileceğindeki değişkenlik miktarını sınırlayan daha derinlemesine bir çözüm isteyeceksiniz. hız. Fare bunun yerine hedefleme yönünü kontrol ederse, farklı bir çözüm vb.


0

ClassicThunder'ın cevabı doğrudur, ancak istenen efekti elde etmek için alternatif / daha basit bir yol örneği sunmak istiyorum. Bu, hızlı prototipleme, tam özellikli bir kütüphaneye erişiminiz olmadığı durumlar veya GPU'ya erişiminiz olmayan durumlar (örneğin gömülü sistemlerde) için daha basit bir çözümdür.

Bahsedilen eşlemeyi gerçekleştirmek için aşağıdaki işlevi kullanabilirsiniz (statik sınıfta tanımlandığını varsayın Helper):

static float Map(float value, float fromLow, float fromHigh, float toLow, float toHigh)
{
    return ((value - fromLow) / (fromHigh - fromLow) * (toHigh - toLow)) + toLow;
}

(Bir dil belirtmediniz, ancak C # hakkında biraz bilginiz olduğunu görüyorum, bu yüzden örneğim C # 'da.)

Daha sonra bu işlevi şu şekilde kullanabilirsiniz:

float mouseXInWorld = Helper.Map(Mouse.X, 0, Screen.Width - 1, camera.Bounds.X, camera.Bounds.X + camera.Bounds.Width - 1);
float mouseYInWorld = Helper.Map(Mouse.Y, 0, Screen.Height - 1, camera.Bounds.Y, camera.Bounds.Y + camera.Bounds.Height - 1);

camera.BoundsDünyadaki alanı temsil eden bir dikdörtgen nerede fotoğraf makinesinin görebileceği (yani ekrana yansıtılan alan).

Bir Vectorveya Pointsınıfınız varsa, aşağıdaki gibi harita işlevinin 2D eşdeğerini oluşturarak bu işlemi daha da basitleştirebilirsiniz:

static Vector Map(Vector value, Rectangle fromArea, Rectangle toArea)
{
    Vector result = new Vector();
    result.X = Map(value.X, fromArea.X, fromArea.X + fromArea.Width - 1, toArea.X, toArea.X + toArea.Width - 1);
    result.Y = Map(value.Y, fromArea.Y, fromArea.Y + fromArea.Height - 1, toArea.Y, toArea.Y + toArea.Height - 1);
    return result;
}

Bu, eşleme kodunuzu basit bir astar haline getirir:

Vector mousePosInWorld = Map(Mouse.Pos, Screen.Bounds, camera.Bounds);

-1

Seçenek (C): ekran çözünürlüğünü tekrar 800x600 olarak değiştirmenizi sağlar.

Bunu yapmasanız bile, bunu bir düşünce deneyi olarak düşünün. Bu durumda, grafikleri fiziksel boyutuna uyacak şekilde yeniden boyutlandırmak ekranın ve ardından 800x600 çözünürlükte işaretçi olayları vermek için işletim sisteminin sorumluluğundadır.

Her şeyin grafiklerinizin bitmap veya vektör olmasına bağlı olduğunu düşünüyorum. Bitmap'lerse ve 800x600'lük bir arabellek oluşturuyorsanız, evet, fareyi ekran alanına yeniden yerleştirmek ve gerçek ekran çözünürlüğünü yok saymak çok daha kolaydır. Bununla birlikte, bunun en büyük dezavantajı, özellikle bloklu "8 bit" tarzı grafikler yapıyorsanız, yükseltmenin çirkin görünebilmesidir.

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.