Mam straszny czas wymyślić dobre pytanie Tytuł ... przepraszam/edytuj jeśli twój mózg jest mniej strzał niż mój.strategia dzielenia mapy, rechunk lag issue
Mam pewne problemy z obsługą strony map mojej gry. Moja gra jest oparta na kaflach z użyciem płytek 32x32 pikseli. Moja pierwsza mapa gry miała wymiary 1750 x 1750. Miałem grupę warstw po stronie klienta, ale udało mi się ją zredukować do 2 (ziemia i budynki). Poprzednio ładowałem całe warstwy mapy do pamięci (krótkie tablice). Kiedy przeskoczyłem do 2200 x 2200 płytek, zauważyłem, że starszy komputer ma problemy z brakującą pamięcią (1 GB +). Chciałbym, żeby był typ danych między bajtem i krótkim (zamierzam na ~ 1000 różnych płytek). Moja gra obsługuje wiele rozdzielczości, więc widzowie mogą wyświetlać 23,17 kafli dla rozdzielczości 800x600, aż do 45,29 klocków dla rozdzielczości 1440x1024 (plus). Używam Kafelki do rysowania moich map i wysyłania 2 warstw do oddzielnych plików tekstowych przy użyciu formatu podobnego do następującego (0, 0, 2, 0, 3, 6, 0, 74, 2 ...) w jednym wierszu.
Za pomocą wielu pytań dotyczących SO i niektórych badań wymyśliłem strategię mapowania kawałków. Używając aktualnych współrzędnych gracza, jako punktu centralnego, ładuję wystarczającą ilość kafli na 5-krotność wielkości mapy wizualnej (największa to 45 * 5,29 * 5 = 225,145 płytek). Gracz zawsze znajduje się w środku, a ziemia porusza się pod nim (kiedy idziesz na wschód, ziemia porusza się na zachód). Minimapa jest rysowana, pokazując jeden ekran we wszystkich kierunkach, aby była trzy razy większa od widocznej mapy. Zobacz poniższą (bardzo pomniejszoną) reprezentację wizualną, aby wyjaśnić lepiej niż prawdopodobnie wyjaśniłem.
Mój problem jest taki: Gdy gracz porusza „1/5th płytki wielkości kawałek away” z oryginalnego punktu środkowego (chunkX/Y) koordynuje, wzywam do gry ponownie przeskanować plik . Nowy skan użyje bieżących współrzędnych gracza, ponieważ jest to punkt środkowy. Obecnie ten problem, który mam, polega na tym, że rechunking trwa jak .5s na moim komputerze (co jest dość wysokim spec). Mapa nie aktualizuje się tak jak 1-2 ruchy płytek.
Aby rozwiązać powyższy problem, spróbowałem uruchomić skanowanie pliku w nowym wątku (przed trafieniem w 1/5 punkt) w tymczasowego arachibra. Następnie, po zakończeniu skanowania, skopiowałbym bufor do prawdziwej tablicy i wywołał repaint(). Losowo widziałem kilka pomijanie problemów z tym, co było nic wielkiego. Co gorsza, zobaczyłem, jak losuje część mapy na 1-2 klatki. Przykładowy kod poniżej:
private void checkIfWithinAndPossiblyReloadChunkMap(){
if (Math.abs(MyClient.characterX - MyClient.chunkX) + 10 > (MyClient.chunkWidth/5)){ //arbitrary number away (10)
Runnable myRunnable = new Runnable(){
public void run(){
logger.info("FillMapChunkBuffer started.");
short chunkXBuffer = MyClient.characterX;
short chunkYBuffer = MyClient.characterY;
int topLeftChunkIndex = MyClient.characterX - (MyClient.chunkWidth/2) + ((MyClient.characterY - (MyClient.chunkHeight/2)) * MyClient.mapWidth); //get top left coordinate of chunk
int topRightChunkIndex = topLeftChunkIndex + MyClient.chunkWidth - 1; //top right coordinate of chunk
int[] leftChunkSides = new int[MyClient.chunkHeight];
int[] rightChunkSides = new int[MyClient.chunkHeight];
for (int i = 0; i < MyClient.chunkHeight; i++){ //figure out the left and right index points for the chunk
leftChunkSides[i] = topLeftChunkIndex + (MyClient.mapWidth * i);
rightChunkSides[i] = topRightChunkIndex + (MyClient.mapWidth * i);
}
MyClient.groundLayerBuffer = MyClient.FillGroundBuffer(leftChunkSides, rightChunkSides);
MyClient.buildingLayerBuffer = MyClient.FillBuildingBuffer(leftChunkSides, rightChunkSides);
MyClient.groundLayer = MyClient.groundLayerBuffer;
MyClient.buildingLayer = MyClient.buildingLayerBuffer;
MyClient.chunkX = chunkXBuffer;
MyClient.chunkY = chunkYBuffer;
MyClient.gamePanel.repaint();
logger.info("FillMapChunkBuffer done.");
}
};
Thread thread = new Thread(myRunnable);
thread.start();
} else if (Math.abs(MyClient.characterY - MyClient.chunkY) + 10 > (MyClient.chunkHeight/5)){ //arbitrary number away (10)
//same code as above for Y
}
}
public static short[] FillGroundBuffer(int[] leftChunkSides, int[] rightChunkSides){
try {
return scanMapFile("res/images/tiles/MyFirstMap-ground-p.json", leftChunkSides, rightChunkSides);
} catch (FileNotFoundException e) {
logger.fatal("ReadMapFile(ground)", e);
JOptionPane.showMessageDialog(theDesktop, getStringChecked("message_file_locks") + "\n\n" + e.getMessage(), getStringChecked("message_error"), JOptionPane.ERROR_MESSAGE);
System.exit(1);
}
return null;
}
private static short[] scanMapFile(String path, int[] leftChunkSides, int[] rightChunkSides) throws FileNotFoundException {
Scanner scanner = new Scanner(new File(path));
scanner.useDelimiter(", ");
int topLeftChunkIndex = leftChunkSides[0];
int bottomRightChunkIndex = rightChunkSides[rightChunkSides.length - 1];
short[] tmpMap = new short[chunkWidth * chunkHeight];
int count = 0;
int arrayIndex = 0;
while(scanner.hasNext()){
if (count >= topLeftChunkIndex && count <= bottomRightChunkIndex){ //within or outside (east and west) of map chunk
if (count == bottomRightChunkIndex){ //last entry
tmpMap[arrayIndex] = scanner.nextShort();
break;
} else { //not last entry
if (isInsideMapChunk(count, leftChunkSides, rightChunkSides)){
tmpMap[arrayIndex] = scanner.nextShort();
arrayIndex++;
} else {
scanner.nextShort();
}
}
} else {
scanner.nextShort();
}
count++;
}
scanner.close();
return tmpMap;
}
Naprawdę jestem na tym wyczerpany. Chcę być w stanie przejść dalej poza tym gównem GUI i pracować nad mechaniką prawdziwej gry. Każda pomoc zostanie ogromnie doceniona. Przepraszam za długi post, ale zaufaj mi, że wiele myśli/nieprzespanych nocy weszło w to. Potrzebuję pomysłów ekspertów SO. Dzięki wielkie!!
p.s. Wpadłem niektórych potencjalnych pomysłów optymalizacyjnych (ale nie jestem pewien, to mogłoby rozwiązać niektóre z kwestii):
podzielić pliki map na wielu liniach, więc mogę zadzwonić scanner.nextLine() 1 raz, zamiast skanera .next() 2200 razy
wymyślić formułę, która, biorąc pod uwagę 4 rogi kawałka mapy, będzie wiedzieć, czy dana współrzędna jest w nim zawarta. to pozwoliłoby mi wywołać metodę scanner.nextLine(), gdy znajduje się w najdalszym punkcie fragmentu dla danej linii. wymagałoby to powyższego podejścia do plików map wielowierszowych.
- rzut zaledwie 1/5th na fragmencie, przesunąć tablicę i załadować następny 1/5th z kawałkiem
OMG nadszedł dzień (pracował nad tym przez kilka tygodni) ... to działa jak czar. Byłem więc bardzo blisko, co mnie uszczęśliwia - po prostu spamowanie jest jak szalone. Dziękuję bardzo za pomoc. Przyznaje nagrodę, kiedy mi pozwala. Jeśli jesteś ciekawy, pomogłeś "Kisnard Online" :). Mam nadzieję, że przyjdziesz zagrać jeden dzień i doświadczysz buforowania po stronie klienta w akcji !! Mam zamiar wspomnieć o Tobie (lub Twojej stronie) w moich informacjach o wersji - daj mi znać, jeśli z jakiegoś powodu nie chcesz, abym nie zrobił tego. – KisnardOnline
@KisnardOnline Dzięki, byłbym szczęśliwy, gdybym został uznany za "Lukasa Beyeler'a" i sprawdzi twoją grę, gdy tylko dostanę trochę czasu :) – BeyelerStudios
Nagroda przyznana za Bounty. Będą w notatkach do wydania następnej łatki: D Jeszcze raz dziękuję Lukas. Teraz, gdy mam tę poprawkę do sfinalizowania, będę reklamować więcej. Mam nadzieję, że po dołączeniu do gry są jacyś gracze :) – KisnardOnline