Ogarniam właśnie kwestię automatycznego skalowania elementów przez sdl. Jest tam taka możliwość więc chce z niej skorzystać.
Z tego co póki co zrozumiałem to wygląda to tak, że ustawiasz "oryginalną" rozdzielczość, renderujesz wszystkie elementy a kiedy rozdzielczość się zmienia to na podstawie oryginalnego obrazu sdl wszystko automatycznie skaluje.
Tak, skalowanie jest ”w standardzie”, ale problemem nie jest to jak skalować, a czy jest to zasadne. Bo o ile ja pisząc NES-owego klona Tetrisa, mogę sobie wszystko renderować na buforze o stałym rozmiarze (nie tyle mogę, co muszę) i wyrzucić na ekran zachowując proporcje 4:3
(i zostawić czarne pasy po bokach ekranu), o tyle Ty robić tego nie powinieneś.
Powód jest prosty — różne proporcje i rozdzielczości ekranów. Jeśli stworzysz interfejs typowo pod proporcje 16:9
, a użytkownik ma monitor pionowy (np. 9:16
), to po zeskalowaniu tylnego bufora do rozdzielczości docelowej, obraz będzie tak rozciągnięty, że kompletnie nieczytelny. Ale tu nie trzeba przypadków brzegowych, bo wystarczy odpalić grę na monitorze z proporcjami 4:3
i już dostaniesz takie zniekształcenie obrazu, że obraz będzie wyglądał bardzo źle.
Dlatego dostosowywanie rozmiaru i proporcji tylnego bufora musi istnieć w Twojej grze, tak jak istnieje w każdej innej, poważnej produkcji. Jest masa gier, które mają okienka, i które bez względu na rozdzielczość i proporcje obrazu, zachowują prawidłowe proporcje okien (proporcje są stałe, wymiary są dopasowane do rozdzielczości ekranu lub tylnego bufora, jeśli ten jest mniejszy niż wybrana rozdzielczość ekranu). To pozwala wyświetlać różny obszar mapy bez zniekształceń (im wyższy współczynnik proporcji, tym kamera obejmuje większy obszar mapy), a także dopasować rozmiar okien do rozdzielczości, zachowując prawidłowe proporcje tych okien.
Tak więc masz trzy rozwiązania:
-
Stałe proporcje tylnego bufora — przy ustalaniu rozmiaru wewnętrznego bufora, respektujesz wymyślone jego proporcje (np. 16:9
) i obraz renderujesz z zachowaniem tych proporcji. To powoduje, że docelowy obraz klatki (na ekranie) jest zgodny z 16:9
, a pozostały obszar wypełniasz na czarno, tworząc pasy po bokach obrazu lub na górze i dole. Okna mają stałe proporcje, także ustalone z góry, a podczas renderowania skaluje się je zgodnie z rozdzielczością bufora (bez zniekształceń). Dodatkowo, w ustawieniach dajesz możliwość wyboru, czy obraz ma zachowywać proporcje i mają być renderowane na ekranie czarne pasy wypełnienia, czy ma być rozciągnięty na pełen ekran (a więc zniekształcony).
-
Zmienne proporcje tylnego bufora — tylny bufor zawsze ma proporcje zgodne z proporcjami rozdzielczości ekranu. To powoduje, że na różnych rozdzielczościach kamera obejmuje różny, szerszy lub węższy (oraz wyższy lub niższy) obszar mapy. Okna zachowują z góry ustalone proporcje, ich rozmiar jest dopasowywany do aktualnej rozdzielczości, ale na różnych rozdzielczościach zajmują różną powierzchnię ekranu (zakładając, że okno jest kwadratowe, to na rozdzielczości 16:9
zajmują połowę szerokości ekranu, a na 4:3
zajmują — na oko — 3/4 powierzchni ekranu). W tym przypadku zawsze renderujesz obraz rozciągnięty na pełen ekran, bez wypełniania czarnymi pasami po bokach lub u góry i na dole.
-
Stały rozmiar bufora i rozciąganie na pełen ekran — to jest to co obecnie masz w planach, czyli rozciąganie bufora na cały ekran przy hardkodowanych jego proporcjach. Jest to opcja najgorsza, bo obraz będzie zniekształcony na wszystkich rozdzielczościach, które współczynnikiem proporcji odbiegają od tych z góry ustalonych.
Nie wiem czy będzie mi to potrzebne bo w sumie w grach nie spotkałem się raczej z możliwością przesuwania okienek. Chyba, że dorobić taką możliwość na potrzeby np animacji rozwijania itp.
Animacje rozwijania okien możesz zrobić bez wsparcia ich przeciągania za pomocą myszy. Tutaj wystarczy po prostu zmieniać współrzędne i/lub rozmiar okna, mysz nie jest do tego potrzebna. Ale jeśli chcesz na przyszłość zostawić sobie taką możliwość, to każde okno też powinieneś renderować na osobnym, tylnym buforze, a podczas renderowania całej klatki, namalować tylny bufor okna na tylnym buforze klatki ze skalowaniem.
Czyli zakładając, że okno ma natywne wymiary 200×200
pikseli, to renderujesz je na osobnym buforze o rozmiarach 200×200
. Następnie z danych o animacji wychodzi, że okno ma być namalowane we współrzędnych 10,10
i rozmiarze 200×50
(spłaszczone), to kopiujesz obszar okna z 0,0,200,200
do obszaru klatki 10,10,210,60
— i dostajesz całe okno ściśnięte pionowo. To tylko przykład, gdy okno ma się pojawiać w sposób animowany, z niewidocznego, poprzez coraz mniej spłaszczone pionowo, aż do kwadratowego (200×200
). Mam nadzieję, że rozumiesz tę analogię.
Muszę się zastanowić jak to zbudować. Teraz mam po prostu procedure z klasy manadzera, ktora rysuje tlo i buttony.
To co powinieneś mieć to bazową klasę, która będzie reprezentować okno oraz kontrolki. Klasa ta powinna zawierać listę kontrolek osadzonych, być w stanie odbierać komunikaty myszy i klawiatury, obsługiwać je a także przekazywać stan myszy i klawiatury do wszystkich kontrolek osadzonych. Z takiej klasy powinny dziedziczyć klasy różnych kontrolek i w odpowiedni sposób implementować obsługę myszy i klawiatury — inaczej tekst, inaczej przycisk, a jeszcze inaczej pole edycyjne. Klasa okna powinna dodatkowo obsługiwać możliwość przeciągania siebie po ekranie, czyli zmianę swojego położenia i/lub rozmiaru.
Ogólnie chodzi o to, aby stworzyć sobie drzewko dziedziczenia, tak aby każdy element interfejsu przejmował funkcjonalność swojej bazowej. I o to, aby okno było korzeniem, a wszystko co w nim się znajduje, tworzyło drzewko kontrolek, gdzie komunikaty sterujące i aktualizujące stan kontrolek płynęłyby z góry (okna) do dołu (np. przycisku).
Wydaje się to dość trudne do osiągnięcia, ale wbrew pozorom jest to dosyć proste do zrobienia. Szczególnie, jeśli zależy Ci jedynie na obsłudze odpowiedników zdarzeń OnMouseEnter
, OnMouseLeave
, OnMouseMove
, OnMouseDown
, OnMouseUp
, OnMouseScroll
, OnKeyDown
i OnKeyUp
, czyli na reagowanie na ruch i wciskanie przycisków myszy, a także na wciskanie klawiszy klawiatury.