Ho un momento orribile in arrivo con una buona domanda Titolo ... mi spiace, per favore modifica se il tuo cervello è meno sparato del mio.strategia di chunking della mappa, problema di ritardo di Rientro
Sto riscontrando alcuni problemi nella gestione del lato client delle mappe del mio gioco. Il mio gioco è basato su tile con tessere di 32x32 pixel. La mia prima mappa di gioco era di 1750 x 1750 tessere. Avevo un mucchio di strati di client side, ma sono riuscito a ridurlo a 2 (terreno e edifici). Stavo caricando in precedenza gli strati dell'intera mappa in memoria (array corti). Quando ho saltato a 2200 x 2200 piastrelle ho notato un vecchio pc con alcuni problemi con memoria insufficiente (1 GB +). Vorrei che ci fosse un tipo di dati tra byte e short (sto mirando a ~ 1000 piastrelle diverse). Il mio gioco supporta più risoluzioni in modo che lo spazio visibile dei giocatori possa mostrare 23,17 tessere per una risoluzione di 800x600 fino a 45,29 tessere per risoluzioni 1440x1024 (più). Uso Tiled per disegnare le mie mappe e generare i 2 livelli in file di testo separati usando un formato simile al seguente (0, 0, 2, 0, 3, 6, 0, 74, 2 ...) tutti su una riga.
Con l'aiuto di molte domande SO e alcune ricerche ho trovato una strategia di chunking della mappa. Usando le coordinate attuali del giocatore, come punto centrale, carico abbastanza tessere per 5 volte la dimensione della mappa visiva (il più grande sarebbe 45 * 5,29 * 5 = 225,145 tessere). Il giocatore è sempre disegnato al centro e il terreno si muove sotto di lui/lei (quando cammini ad est il terreno si muove verso ovest). La minimappa viene disegnata mostrando una schermata in tutte le direzioni, per essere tre volte la dimensione della mappa visibile. Si prega di vedere la seguente rappresentazione visiva (molto ridotta) per spiegare meglio di quanto probabilmente l'ho spiegato.
Il mio problema è questo: quando il giocatore muove "1/5 ° le piastrelle di dimensioni pezzo di distanza" dal punto centrale originale (chunkX/Y) coordinate, che io chiamo per il gioco di ri scansione del file . La nuova scansione utilizzerà le coordinate correnti del lettore come punto centrale. Attualmente il problema che sto riscontrando è che il rechunking prende come .5s sul mio pc (che è una specifica piuttosto alta). La mappa non si aggiorna per 1-2 spostamenti di tessere uguali.
Per risolvere il problema precedente, ho provato a eseguire la scansione dei file in un nuovo thread (prima di toccare il 1/5 punto) in un buffer di array temporaneo. Quindi, una volta eseguita la scansione, avrei copiato il buffer nell'array reale e chiamato repaint(). Casualmente ho visto alcuni problemi saltati con questo che non era un grosso problema. Peggio ancora, l'ho visto disegnare una parte casuale della mappa per 1-2 fotogrammi. Esempio di codice riportato di seguito:
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;
}
Sono davvero alle mie spalle. Voglio essere in grado di andare oltre questa schifezza della GUI e lavorare su vere meccaniche di gioco. Qualsiasi aiuto sarebbe enormemente apprezzato. Scusate per il post lungo, ma credetemi un sacco di pensieri/notti insonni è andato in questo. Ho bisogno delle idee degli esperti di SO. Grazie mille!!
p.s. Sono venuto con alcuni potenziali idee di ottimizzazione (ma non è sicuro queste sarebbero risolvere alcuni della questione):
dividere i file delle mappe in più righe in modo da poter chiamare scanner.nextLine() 1 volta, piuttosto che lo scanner .next() 2200 volte
trovare una formula che dati i 4 angoli del blocco della mappa saprà se una determinata coordinata si trova all'interno di essa. questo mi permetterebbe di chiamare scanner.nextLine() quando si trova nel punto più lontano del blocco per una determinata linea. questo richiederebbe l'approccio di file di mappe multilinea sopra.
- buttare via solo 1/5 del pezzo, spostare l'array, e caricare il prossimo 1/5 del pezzo
OMG è arrivato il giorno (ci hanno lavorato per settimane) ... questo funziona come un fascino. Quindi ero molto vicino e questo mi rende felice: spammare i soccorritori come un matto. Grazie mille per l'aiuto. Assegnerà la taglia quando me lo consente. Se sei curioso, hai aiutato "Kisnard Online" :). Spero che tu venga un giorno a giocare e che tu possa sperimentare il tuo fantasioso caching sul lato client in azione !! Ho intenzione di menzionare te (o il tuo sito) nelle mie note di rilascio - fammi sapere se desideri che non lo faccia per qualche motivo. – KisnardOnline
@KisnardOnline Grazie Sarei felice di essere accreditato come "Lukas Beyeler" e controllerò il tuo gioco non appena avrò un po 'di tempo :) – BeyelerStudios
Bounty assegnato e lo farà. Sarà nelle note di rilascio per la prossima patch: D Grazie ancora Lukas. Ora che ho questa correzione per finalizzare pubblicizzerò di più. Spero che ci siano alcuni giocatori quando ti unisci :) – KisnardOnline