Rozważ grę, której domyślna rozdzielczość to 800 x 600. Obiekty z maskami kolizyjnymi są umieszczane w świecie gry o wymiarach 800 x 600. Maski kolizyjne mogą wykryć zderzenie myszy z nimi.
Rozważmy teraz skalowanie gry do 1024 x 768 (załóżmy, że skalujemy grafikę, po prostu renderując wszystko na warstwę, a następnie skalując całą warstwę jednocześnie). Mamy dwie opcje prawidłowego działania kolizji z myszą w nowej rozdzielczości:
A.) Powiększ świat do 1024 x 768 i odpowiednio skaluj maskę kolizji każdego obiektu.
B.) „Mapuj” pozycję myszy na oryginalnym świecie (800 x 600).
Przez „mapę” rozumiem po prostu przeskaluj pozycję myszy do oryginalnego świata 800x600. Na przykład, jeśli pozycja myszy na ekranie to (1024, 768), to pozycja myszy na świecie to (800, 600).
Teraz, oczywiście, opcja B wymaga znacznie mniej obliczeń i prawdopodobnie jest mniej podatna na błędy geometryczne, ale wydaje mi się to również trochę „hacking”, podobnie jak istnieją nieprzewidziane konsekwencje korzystania z tej metody, którą będzie piekło naprawić później.
Którą metodą powinienem stosować: A, B lub coś innego?
źródło
Odpowiedzi:
Zazwyczaj (nawet w przypadku gier 2d) istnieje osobny układ współrzędnych dla gry, który jest niezależny od rozdzielczości, co zwykle określa się mianem przestrzeni świata. Umożliwia to skalowanie do dowolnej rozdzielczości.
Najłatwiejszym sposobem na osiągnięcie tego jest użycie kamery 2D, która jest zasadniczo matrycą, która określa przejście z przestrzeni świata (twoich dowolnych jednostek) do przestrzeni ekranu (pikseli na ekranie). To sprawia, że radzenie sobie z matematyką jest banalne.
Spójrz na poniższy rozdział przewijania kamery XNA 2d - po co używać transformacji macierzowej?
Ułatwia to konwersję między definicjami układu współrzędnych
Aby przejść z ekranu do przestrzeni kosmicznej, wystarczy użyć Vector2.Transform. Jest to powszechnie używane do uzyskiwania położenia myszy na świecie do wybierania obiektów.
Aby przejść ze świata do miejsca na ekranie, po prostu postępuj odwrotnie.
Korzystanie z matrycy nie ma żadnych wad, ale wymaga trochę nauki.
źródło
Inną opcją byłoby: Przy każdym wejściowym zdarzeniu ruchu myszy przesuń kursor myszy w grze o liczbę pikseli gry odpowiadającą liczbie pikseli w zdarzeniu myszy. Dzieje się tak naturalnie w przypadku gier 3D, które blokują prawdziwy wskaźnik myszy na środku i obracają kierunek celowania o wartość odpowiadającą ruchowi myszy na wejściu, ale można to zrobić w ten sam sposób, przesuwając duszka reprezentującego kursor myszy w grze.
Oczywiście musisz zignorować wszelkie zdarzenia ruchu myszy wejściowej spowodowane przez wypaczenie go do środka, a jeśli gra ma jakieś opóźnienie wejściowe w ogóle, brak reakcji kursora będzie najbardziej niepokojącym i zauważalnym aspektem.
Częściowo, jakie rozwiązanie zastosujesz, zależy od tego, jak ważna jest pozycja myszy w grze. Jeśli jest to RTS, a gracz po prostu klika, aby wybrać jednostki, prawdopodobnie możesz po prostu wybrać jedną z A lub B, która jest łatwiejsza. Jeśli jest to strzelanka odgórna, a mysz bezpośrednio kontroluje ruchy postaci, prawdopodobnie będziesz potrzebować bardziej dogłębnego rozwiązania, które ogranicza zakres zmienności sposobu poruszania się postaci na podstawie nie tylko rozdzielczości, ale także rzeczy takich jak ruch myszy prędkość. Jeśli zamiast tego mysz steruje kierowaniem, będziesz potrzebować innego rozwiązania itp.
źródło
Odpowiedź ClassicThundera jest poprawna, ale chciałbym podać przykład alternatywnego / prostszego sposobu osiągnięcia pożądanego efektu. Jest to prostsze rozwiązanie do szybkiego prototypowania, przypadków, w których nie masz dostępu do w pełni funkcjonalnej biblioteki, lub w przypadkach, gdy nie masz dostępu do GPU (np. W systemach wbudowanych).
Aby wykonać wspomniane mapowanie, możesz użyć następującej funkcji (zakładając, że zostanie zdefiniowana w klasie statycznej
Helper
):(Nie określiłeś języka, ale widzę, że znasz trochę C #, więc mój przykład jest w C #).
Następnie możesz użyć tej funkcji w następujący sposób:
Gdzie
camera.Bounds
jest prostokąt reprezentujący obszar świata, który może zobaczyć kamera (tj. Obszar rzutowany na ekran).Jeśli masz klasę
Vector
lubPoint
, możesz jeszcze bardziej uprościć ten proces, tworząc 2D odpowiednik funkcji mapy, na przykład:Co sprawiłoby, że Twój kod mapowania byłby prostą linią:
źródło
Opcja (C): zmień rozdzielczość ekranu z powrotem na 800x600.
Nawet jeśli tego nie zrobisz, rozważ to jako eksperyment myślowy. W takim przypadku to do wyświetlacza należy zmiana rozmiaru grafiki w celu dopasowania do jego fizycznego rozmiaru, a następnie do odpowiedzialności systemu operacyjnego za dostarczenie zdarzeń wskaźnika w rozdzielczości 800x600.
Myślę, że wszystko zależy od tego, czy twoja grafika to bitmapa czy wektor. Jeśli są to mapy bitowe, a ty renderujesz do bufora 800 x 600, to tak, znacznie łatwiej jest zmienić mapowanie myszy w przestrzeń ekranu i zignorować rzeczywistą rozdzielczość ekranu. Jednak dużym minusem tego jest to, że skalowanie może wyglądać brzydko, szczególnie jeśli robisz blokową grafikę w stylu „8-bit”.
źródło