Opanuj optymalizacj臋 gier dzi臋ki sprawdzonym technikom wydajno艣ci. Zwi臋ksz klatka偶, zredukuj lagi i popraw wra偶enia graczy na wielu platformach globalnie.
Optymalizacja Gier: Techniki Wydajno艣ci dla Globalnego Sukcesu
W konkurencyjnym 艣wiecie tworzenia gier, wydajno艣膰 ma kluczowe znaczenie. S艂abo zoptymalizowana gra, niezale偶nie od jej walor贸w artystycznych czy innowacyjnej rozgrywki, ryzykuje zra偶enie graczy z powodu lag贸w, niskiej liczby klatek na sekund臋 i nadmiernego zu偶ycia zasob贸w. Jest to szczeg贸lnie wa偶ne na rynku globalnym, gdzie gracze uzyskuj膮 dost臋p do gier na r贸偶norodnych urz膮dzeniach, od wysokiej klasy komputer贸w gamingowych po niedrogie telefony kom贸rkowe. Ten obszerny przewodnik przedstawia podstawowe techniki optymalizacji gier, maj膮ce zastosowanie na r贸偶nych platformach, maj膮c na celu zapewnienie p艂ynnych i przyjemnych wra偶e艅 dla graczy na ca艂ym 艣wiecie.
Zrozumienie W膮skich Garde艂 Wydajno艣ci
Zanim zag艂臋bisz si臋 w konkretne techniki optymalizacji, kluczowe jest zidentyfikowanie w膮skich garde艂 wp艂ywaj膮cych na wydajno艣膰 Twojej gry. Cz臋ste przyczyny to:
- CPU (Central Processing Unit): Obs艂uguje logik臋 gry, AI, fizyk臋 i inne podstawowe obliczenia.
- GPU (Graphics Processing Unit): Odpowiedzialne za renderowanie grafiki, w tym tekstur, shader贸w i efekt贸w wizualnych.
- Pami臋膰 (RAM): Przechowuje zasoby gry, dane i instrukcje programu dla szybkiego dost臋pu.
- Operacje I/O dysku: Wp艂ywaj膮 na czasy 艂adowania i strumieniowanie zasob贸w.
- Sie膰: Wp艂ywa na gry wieloosobowe online z powodu op贸藕nie艅 i ogranicze艅 przepustowo艣ci.
Zidentyfikowanie g艂贸wnego w膮skiego gard艂a to pierwszy krok do skutecznej optymalizacji. Cz臋sto wymaga to u偶ycia narz臋dzi profiluj膮cych do analizy wykorzystania CPU i GPU, alokacji pami臋ci i ruchu sieciowego.
Narz臋dzia Profiluj膮ce: Tw贸j Arsena艂 Optymalizacji
Narz臋dzia profiluj膮ce dostarczaj膮 bezcennych informacji na temat wydajno艣ci Twojej gry. Popularne opcje to:
- Unity Profiler: Wbudowany profiler dla projekt贸w Unity, oferuj膮cy szczeg贸艂owe informacje na temat wydajno艣ci CPU, GPU, pami臋ci i renderowania.
- Unreal Engine Profiler: Podobny do profilera Unity, zapewniaj膮cy kompleksow膮 analiz臋 wydajno艣ci dla gier Unreal Engine.
- RenderDoc: Pot臋偶ny, otwarty debugger grafiki, kt贸ry pozwala na inspekcj臋 poszczeg贸lnych wywo艂a艅 rysowania i wykonywania shader贸w.
- Perfetto: Zestaw do 艣ledzenia i analizy wydajno艣ci klasy produkcyjnej dla Androida, Linuksa i Chrome.
- Xcode Instruments (iOS): Zbi贸r narz臋dzi profiluj膮cych do rozwoju iOS, w tym pr贸bnik CPU, alokator pami臋ci i analizator OpenGL ES.
- Android Studio Profiler (Android): Oferuje profilowanie CPU, pami臋ci, sieci i energii dla aplikacji Android.
Opanowanie tych narz臋dzi umo偶liwi Ci precyzyjne okre艣lenie w膮skich garde艂 wydajno艣ci i pokierowanie Twoimi wysi艂kami optymalizacyjnymi.
Techniki Optymalizacji CPU
Optymalizacja wydajno艣ci CPU jest kluczowa dla zapewnienia p艂ynnej rozgrywki, zw艂aszcza w grach z z艂o偶on膮 sztuczn膮 inteligencj膮, fizyk膮 lub symulacjami.
Optymalizacja Kodu
Pisanie wydajnego kodu jest fundamentalne dla wydajno艣ci CPU. Rozwa偶 nast臋puj膮ce kwestie:
- Optymalizacja Algorytm贸w: Wybierz najbardziej wydajne algorytmy dla swoich konkretnych zada艅. Na przyk艂ad, u偶ycie tablicy haszuj膮cej zamiast wyszukiwania liniowego dla zapyta艅 mo偶e znacz膮co poprawi膰 wydajno艣膰.
- Struktury Danych: Wybierz odpowiednie struktury danych, aby zminimalizowa膰 zu偶ycie pami臋ci i czasy dost臋pu.
- Buforowanie (Caching): Przechowuj cz臋sto u偶ywane dane w zmiennych lokalnych, aby zmniejszy膰 narzut zwi膮zany z dost臋pem do pami臋ci.
- Unikanie Niepotrzebnych Alokacji: Minimalizuj tworzenie i niszczenie obiekt贸w, poniewa偶 alokacja pami臋ci mo偶e by膰 kosztown膮 operacj膮. U偶yj puli obiekt贸w (object pooling), aby ponownie wykorzystywa膰 istniej膮ce obiekty zamiast tworzy膰 nowe.
- 艁膮czenie 艁a艅cuch贸w (String Concatenation): Unikaj wielokrotnego 艂膮czenia 艂a艅cuch贸w znak贸w w p臋tlach, poniewa偶 mo偶e to tworzy膰 liczne tymczasowe obiekty 艂a艅cuchowe. U偶yj StringBuilder (C#) lub podobnych technik do wydajnej manipulacji 艂a艅cuchami.
- Logika Warunkowa: Zoptymalizuj instrukcje warunkowe, umieszczaj膮c najbardziej prawdopodobne warunki na pierwszym miejscu.
- Minimalizacja Wywo艂a艅 Funkcji Wirtualnych: Wywo艂ania funkcji wirtualnych wprowadzaj膮 narzut z powodu dynamicznego wysy艂ania. Zredukuj ich u偶ycie, gdzie to mo偶liwe, zw艂aszcza w krytycznych dla wydajno艣ci sekcjach kodu.
Przyk艂ad (C# - Unity): Zamiast wielokrotnie oblicza膰 pierwiastek kwadratowy liczby, buforuj wynik:
float CachedSqrt(float number)
{
static Dictionary<float, float> sqrtCache = new Dictionary<float, float>();
if (sqrtCache.ContainsKey(number))
{
return sqrtCache[number];
}
else
{
float result = Mathf.Sqrt(number);
sqrtCache[number] = result;
return result;
}
}
Wielow膮tkowo艣膰 (Multithreading)
Wykorzystaj wiele rdzeni CPU, rozdzielaj膮c zadania na r贸偶ne w膮tki. Mo偶e to znacz膮co poprawi膰 wydajno艣膰, zw艂aszcza w przypadku zada艅 intensywnie obliczeniowych, takich jak symulacje fizyki lub obliczenia AI.
- R贸wnoleg艂o艣膰 oparta na zadaniach: Podziel du偶e zadania na mniejsze, niezale偶ne zadania, kt贸re mo偶na wykonywa膰 r贸wnolegle.
- R贸wnoleg艂o艣膰 danych: Zastosuj t臋 sam膮 operacj臋 do wielu element贸w danych jednocze艣nie, u偶ywaj膮c wielu w膮tk贸w.
- Synchronizacja: Zapewnij odpowiedni膮 synchronizacj臋 mi臋dzy w膮tkami, aby unikn膮膰 warunk贸w wy艣cigu (race conditions) i uszkodzenia danych. U偶yj blokad, muteks贸w lub innych prymityw贸w synchronizacji do ochrony wsp贸艂dzielonych zasob贸w.
Przyk艂ad (C++): U偶ycie std::thread do wykonania zadania w osobnym w膮tku:
#include <iostream>
#include <thread>
void task(int id)
{
std::cout << "Thread " << id << " is running.\n";
}
int main()
{
std::thread t1(task, 1);
std::thread t2(task, 2);
t1.join(); // Wait for t1 to finish
t2.join(); // Wait for t2 to finish
std::cout << "All threads finished.\n";
return 0;
}
Pulowanie Obiekt贸w (Object Pooling)
Pulowanie obiekt贸w to technika ponownego wykorzystywania istniej膮cych obiekt贸w zamiast tworzenia nowych. Mo偶e to znacz膮co zmniejszy膰 narzut zwi膮zany z alokacj膮 pami臋ci i od艣miecaniem pami臋ci (garbage collection).
- Wst臋pna alokacja obiekt贸w: Utw贸rz pul臋 obiekt贸w na pocz膮tku gry lub poziomu.
- Ponowne wykorzystanie obiekt贸w: Gdy obiekt jest potrzebny, pobierz go z puli zamiast tworzy膰 nowy.
- Zwracanie obiekt贸w do puli: Gdy obiekt nie jest ju偶 potrzebny, zwr贸膰 go do puli w celu p贸藕niejszego ponownego wykorzystania.
Jest to szczeg贸lnie skuteczne w przypadku cz臋sto tworzonych i niszczonych obiekt贸w, takich jak pociski, cz膮steczki lub wrogowie.
Optymalizacja Fizyki
Symulacje fizyki mog膮 by膰 kosztowne obliczeniowo. Zoptymalizuj ustawienia fizyki, aby zmniejszy膰 obci膮偶enie CPU:
- Wykrywanie Kolizji: U偶ywaj uproszczonych kszta艂t贸w kolizyjnych (np. obwiedni, sfer) zamiast z艂o偶onych siatek do wykrywania kolizji.
- Iteracje Fizyki: Zmniejsz liczb臋 iteracji fizyki na klatk臋. Mo偶e to poprawi膰 wydajno艣膰, ale mo偶e r贸wnie偶 zmniejszy膰 dok艂adno艣膰 symulacji.
- Pr贸g U艣pienia (Sleep Threshold): Ustaw pr贸g u艣pienia dla cia艂 sztywnych, aby zatrzyma膰 symulacj臋 obiekt贸w, kt贸re s膮 w spoczynku.
- Wy艂膮czanie Kolider贸w: Wy艂膮cz kolidery dla obiekt贸w, kt贸re nie wchodz膮 w interakcje z otoczeniem.
Techniki Optymalizacji GPU
Optymalizacja wydajno艣ci GPU jest kluczowa dla osi膮gni臋cia wysokich klatek na sekund臋 i atrakcyjnej wizualnie grafiki. GPU odpowiada za renderowanie tekstur, shader贸w i efekt贸w post-processingowych, co czyni je g艂贸wnym celem optymalizacji.
Poziom Szczeg贸艂owo艣ci (LOD)
Poziom Szczeg贸艂owo艣ci (LOD) to technika redukcji z艂o偶ono艣ci modeli w zale偶no艣ci od ich odleg艂o艣ci od kamery. Zmniejsza to liczb臋 poligon贸w, kt贸re musz膮 zosta膰 wyrenderowane, poprawiaj膮c wydajno艣膰 GPU.
- Tworzenie Wieloziarnistych LOD-贸w: Generuj r贸偶ne wersje modelu o r贸偶nym poziomie szczeg贸艂owo艣ci.
- Prze艂膮czanie LOD-贸w na podstawie odleg艂o艣ci: Prze艂膮czaj na modele o ni偶szej szczeg贸艂owo艣ci wraz ze wzrostem odleg艂o艣ci od kamery.
- Automatyczne generowanie LOD: U偶ywaj narz臋dzi lub skrypt贸w do automatycznego generowania LOD-贸w z modeli o wysokiej rozdzielczo艣ci.
Przyk艂ad: Model drzewa mo偶e mie膰 wersj臋 o wysokiej szczeg贸艂owo艣ci z tysi膮cami poligon贸w dla widok贸w z bliska oraz wersj臋 o niskiej szczeg贸艂owo艣ci z kilkoma setkami poligon贸w dla widok贸w z daleka.
Culling Okluzji (Occlusion Culling)
Culling okluzji to technika zapobiegania renderowaniu obiekt贸w, kt贸re s膮 ukryte za innymi obiektami. Mo偶e to znacz膮co zmniejszy膰 liczb臋 wywo艂a艅 rysowania (draw calls) i poprawi膰 wydajno艣膰 GPU.
- U偶ywaj Wolumin贸w Okluzji: Zdefiniuj woluminy okluzji, aby okre艣li膰 obszary, kt贸re mog膮 zas艂ania膰 inne obiekty.
- Dynamiczny Culling Okluzji: Zaimplementuj dynamiczny culling okluzji do obs艂ugi ruchomych obiekt贸w i pozycji kamery.
- Wypiekany Culling Okluzji (Baked Occlusion Culling): Wst臋pnie oblicz dane okluzji podczas projektowania poziomu, aby dodatkowo zoptymalizowa膰 wydajno艣膰.
Optymalizacja Shader贸w
Shadery to programy dzia艂aj膮ce na GPU, kt贸re okre艣laj膮 spos贸b renderowania obiekt贸w. Optymalizacja shader贸w mo偶e znacz膮co poprawi膰 wydajno艣膰 GPU.
- Zmniejsz Z艂o偶ono艣膰 Shader贸w: Upro艣膰 kod shadera, usuwaj膮c niepotrzebne obliczenia i instrukcje.
- U偶ywaj Typ贸w Danych o Ni偶szej Precyzji: U偶ywaj typ贸w danych o ni偶szej precyzji (np. zmiennoprzecinkowe p贸艂precyzji) tam, gdzie to mo偶liwe, aby zmniejszy膰 zu偶ycie przepustowo艣ci pami臋ci.
- Optymalizuj Pr贸bkowanie Tekstur: Zminimalizuj liczb臋 pr贸bek tekstur i u偶ywaj mipmapowania, aby zmniejszy膰 aliasing.
- 艁膮czenie Wywo艂a艅 Rysowania (Batch Draw Calls): Po艂膮cz wiele wywo艂a艅 rysowania w jedno wywo艂anie, aby zmniejszy膰 narzut CPU.
- Unikaj Przezroczystych Obiekt贸w: Przezroczysto艣膰 mo偶e by膰 kosztowna w renderowaniu ze wzgl臋du na nadrysowanie (overdraw). Zminimalizuj u偶ycie przezroczystych obiekt贸w lub u偶yj alternatywnych technik, takich jak przezroczysto艣膰 ditheringowa.
Optymalizacja Tekstur
Tekstury to obrazy u偶ywane do dodawania szczeg贸艂贸w do modeli 3D. Optymalizacja tekstur mo偶e zmniejszy膰 zu偶ycie pami臋ci i poprawi膰 wydajno艣膰 GPU.
- Kompresuj Tekstury: U偶ywaj skompresowanych format贸w tekstur (np. DXT, ETC, ASTC), aby zmniejszy膰 zu偶ycie pami臋ci.
- Mipmapping: U偶ywaj mipmappingu do tworzenia wersji tekstur o ni偶szej rozdzielczo艣ci dla odleg艂ych obiekt贸w.
- Atlasy Tekstur: Po艂膮cz wiele ma艂ych tekstur w jeden du偶y atlas tekstur, aby zmniejszy膰 liczb臋 prze艂膮cze艅 tekstur.
- Rozmiar Tekstury: U偶ywaj najmniejszego rozmiaru tekstury, kt贸ry jest wizualnie akceptowalny. Unikaj u偶ywania niepotrzebnie du偶ych tekstur.
Zmniejsz Liczb臋 Wywo艂a艅 Rysowania (Draw Calls)
Ka偶dy obiekt renderowany w Twojej scenie wymaga "wywo艂ania rysowania". Zmniejszenie liczby wywo艂a艅 rysowania jest kluczow膮 technik膮 optymalizacji.
- Statyczne Batchowanie (Static Batching): Po艂膮cz statyczne obiekty z tym samym materia艂em w jedn膮 siatk臋.
- Dynamiczne Batchowanie (Dynamic Batching): Po艂膮cz dynamiczne obiekty z tym samym materia艂em w okre艣lonych granicach blisko艣ci. (Cz臋sto obs艂ugiwane automatycznie przez silniki gier)
- Instancjonowanie GPU (GPU Instancing): Renderuj wiele instancji tej samej siatki z r贸偶nymi transformacjami za pomoc膮 jednego wywo艂ania rysowania.
Efekty Post-Processingowe
Efekty post-processingowe (np. bloom, ambient occlusion, color grading) mog膮 znacz膮co poprawi膰 jako艣膰 wizualn膮 Twojej gry, ale mog膮 by膰 r贸wnie偶 kosztowne obliczeniowo. U偶ywaj efekt贸w post-processingowych oszcz臋dnie i optymalizuj ich ustawienia.
- Zmniejsz Jako艣膰 Efekt贸w: Obni偶 ustawienia jako艣ci efekt贸w post-processingowych, aby poprawi膰 wydajno艣膰.
- U偶ywaj Zoptymalizowanych Shader贸w: U偶ywaj zoptymalizowanych shader贸w dla efekt贸w post-processingowych, aby zmniejszy膰 obci膮偶enie GPU.
- Wy艂膮cz Niepotrzebne Efekty: Wy艂膮cz efekty post-processingowe na urz膮dzeniach ni偶szej klasy.
Techniki Optymalizacji Pami臋ci
Efektywne zarz膮dzanie pami臋ci膮 jest kluczowe dla zapobiegania awariom i zapewnienia p艂ynnej wydajno艣ci, zw艂aszcza na urz膮dzeniach mobilnych z ograniczonymi zasobami pami臋ci.
Zarz膮dzanie Zasobami (Asset Management)
W艂a艣ciwe zarz膮dzanie zasobami jest niezb臋dne do minimalizowania zu偶ycia pami臋ci.
- Zwalnianie Niewykorzystanych Zasob贸w: Zwalniaj zasoby, kt贸re nie s膮 ju偶 potrzebne, aby zwolni膰 pami臋膰.
- Addressable Asset System (Unity): Wykorzystaj system adresowalnych zasob贸w do 艂adowania i zwalniania zasob贸w na 偶膮danie, poprawiaj膮c zarz膮dzanie pami臋ci膮.
- Strumieniowanie Zasob贸w: Strumieniuj du偶e zasoby (np. tekstury, audio) z dysku zamiast 艂adowa膰 je w ca艂o艣ci do pami臋ci.
Optymalizacja Struktur Danych
Wybieraj odpowiednie struktury danych, aby zminimalizowa膰 zu偶ycie pami臋ci.
- U偶ywaj Prymitywnych Typ贸w Danych: U偶ywaj prymitywnych typ贸w danych (np. int, float) zamiast typ贸w obiektowych, gdzie to mo偶liwe.
- Unikaj Niepotrzebnych Kopii: Unikaj tworzenia niepotrzebnych kopii danych. Zamiast tego u偶ywaj referencji lub wska藕nik贸w.
- U偶ywaj Kompresji Danych: Kompresuj dane, aby zmniejszy膰 ich 艣lad w pami臋ci.
Profilowanie Pami臋ci
U偶ywaj narz臋dzi do profilowania pami臋ci, aby identyfikowa膰 wycieki pami臋ci i nadmierne zu偶ycie pami臋ci.
- Identyfikacja Wyciek贸w Pami臋ci: Wykrywaj i naprawiaj wycieki pami臋ci, aby zapobiec wyczerpaniu pami臋ci.
- Analiza Zu偶ycia Pami臋ci: Analizuj wzorce zu偶ycia pami臋ci, aby zidentyfikowa膰 obszary, w kt贸rych pami臋膰 mo偶na zoptymalizowa膰.
Optymalizacja Specyficzna dla Platformy
Strategie optymalizacji cz臋sto wymagaj膮 dostosowania do konkretnych platform ze wzgl臋du na r贸偶nice w sprz臋cie i warianty API.
Optymalizacja Mobilna
Urz膮dzenia mobilne maj膮 ograniczon膮 moc obliczeniow膮 i pami臋膰 w por贸wnaniu do komputer贸w PC i konsol. Skoncentruj si臋 na nast臋puj膮cych technikach optymalizacji dla gier mobilnych:
- Zmniejsz Liczb臋 Poligon贸w: U偶ywaj modeli o niskiej liczbie poligon贸w i optymalizuj siatki.
- Optymalizuj Tekstury: U偶ywaj skompresowanych tekstur i mipmapowania.
- Wy艂膮cz Cienie: Wy艂膮cz cienie lub u偶yj uproszczonych technik cieniowania.
- Zmniejsz Efekty Cz膮steczkowe: Ogranicz liczb臋 cz膮steczek i optymalizuj shadery cz膮steczkowe.
- 艁膮czenie Wywo艂a艅 Rysowania (Batch Draw Calls): Zminimalizuj liczb臋 wywo艂a艅 rysowania.
- Zarz膮dzanie Energi膮: Zoptymalizuj gr臋, aby zminimalizowa膰 zu偶ycie baterii.
Optymalizacja Konsolowa
Konsole oferuj膮 bardziej kontrolowane 艣rodowisko sprz臋towe, ale optymalizacja jest nadal wa偶na dla osi膮gni臋cia sta艂ej liczby klatek na sekund臋 i maksymalizacji jako艣ci wizualnej.
- Wykorzystaj API Specyficzne dla Platformy: Wykorzystaj API specyficzne dla platformy do renderowania, zarz膮dzania pami臋ci膮 i wielow膮tkowo艣ci.
- Optymalizuj dla Docelowej Rozdzielczo艣ci: Zoptymalizuj gr臋 dla docelowej rozdzielczo艣ci konsoli (np. 1080p, 4K).
- Zarz膮dzanie Pami臋ci膮: Starannie zarz膮dzaj pami臋ci膮, aby unikn膮膰 jej wyczerpania.
Optymalizacja dla Sieci (Web Optimization)
Gry internetowe musz膮 by膰 zoptymalizowane pod k膮tem szybkich czas贸w 艂adowania i p艂ynnej wydajno艣ci w przegl膮darkach internetowych.
- Optymalizuj Rozmiary Zasob贸w: Zmniejsz rozmiar zasob贸w (np. tekstur, audio, modeli), aby zminimalizowa膰 czasy pobierania.
- U偶ywaj Kompresji: U偶ywaj technik kompresji (np. gzip, Brotli) do kompresowania plik贸w gry.
- Optymalizacja Kodu: Zoptymalizuj kod JavaScript pod k膮tem szybkiego wykonania.
- Buforowanie (Caching): Wykorzystaj buforowanie przegl膮darki, aby skr贸ci膰 czasy 艂adowania cz臋sto u偶ywanych zasob贸w.
Globalne Rozwa偶ania
Tworz膮c gry dla globalnej publiczno艣ci, we藕 pod uwag臋 nast臋puj膮ce czynniki:
- R贸偶norodno艣膰 Urz膮dze艅: Zoptymalizuj gr臋 dla szerokiej gamy urz膮dze艅, od wysokiej klasy komputer贸w PC po niedrogie telefony kom贸rkowe.
- Warunki Sieciowe: Zaprojektuj gr臋 tak, aby by艂a odporna na zmienne warunki sieciowe.
- Lokalizacja: Zlokalizuj tekst, d藕wi臋k i grafik臋 swojej gry dla r贸偶nych j臋zyk贸w i kultur.
- Dost臋pno艣膰: Spraw, aby Twoja gra by艂a dost臋pna dla graczy z niepe艂nosprawno艣ciami.
Wniosek
Optymalizacja gier to ci膮g艂y proces, kt贸ry wymaga starannego planowania, analizy i eksperymentowania. Rozumiej膮c w膮skie gard艂a wydajno艣ci w swojej grze i stosuj膮c techniki opisane w tym przewodniku, mo偶esz stworzy膰 p艂ynne, przyjemne i dost臋pne do艣wiadczenie dla graczy na ca艂ym 艣wiecie. Pami臋taj, aby regularnie profilowa膰 swoj膮 gr臋, iterowa膰 strategie optymalizacji i adaptowa膰 si臋 do stale zmieniaj膮cego si臋 krajobrazu sprz臋tu i oprogramowania. Priorytetyzuj膮c wydajno艣膰, mo偶esz zapewni膰, 偶e Twoja gra osi膮gnie sw贸j pe艂ny potencja艂 i zachwyci graczy na ca艂ym 艣wiecie.
Ci膮g艂e uczenie si臋 i bycie na bie偶膮co z najnowszymi technikami optymalizacji jest kluczem do sukcesu w konkurencyjnej bran偶y gier. Podejmij wyzwanie, eksperymentuj z r贸偶nymi podej艣ciami i d膮偶 do zapewnienia najlepszych mo偶liwych wra偶e艅 z gry dla swoich graczy.