Ho già cercato risposte ma non sono riuscito a capire l'approccio migliore per gestire costose funzioni / calcoli.
Nel mio gioco attuale (un edificio di città basato su piastrelle 2d) l'utente è in grado di posizionare edifici, costruire strade, ecc. Tutti gli edifici hanno bisogno di una connessione a un incrocio che l'utente deve posizionare al bordo della mappa. Se un edificio non è collegato a questo incrocio, verrà visualizzato un cartello "Non collegato alla strada" sopra l'edificio interessato (altrimenti deve essere rimosso). La maggior parte degli edifici ha un raggio e potrebbe essere correlata anche tra loro (ad esempio un corpo dei vigili del fuoco può aiutare tutte le case entro un raggio di 30 tessere). Questo è ciò di cui ho bisogno anche per aggiornare / verificare quando cambia la connessione stradale.
Ieri ho riscontrato un grosso problema di prestazioni. Diamo un'occhiata al seguente scenario: Un utente può ovviamente cancellare anche edifici e strade. Quindi, se un utente ora interrompe la connessione subito dopo l'incrocio, devo aggiornare molti edifici contemporaneamente . Penso che uno dei primi consigli sarebbe quello di evitare i cicli nidificati (che sicuramente è una grande ragione in questo scenario) ma devo controllare ...
- se un edificio è ancora collegato all'incrocio nel caso in cui una piastrella stradale sia stata rimossa (lo faccio solo per gli edifici interessati da quella strada). (Potrebbe essere un problema minore in questo scenario)
l'elenco delle tessere raggio e ottieni gli edifici nel raggio (anelli annidati - grosso problema!) .
// Go through all buildings affected by erasing this road tile. foreach(var affectedBuilding in affectedBuildings) { // Get buildings within radius. foreach(var radiusTile in affectedBuilding.RadiusTiles) { // Get all buildings on Map within this radius (which is technially another foreach). var buildingsInRadius = TileMap.Buildings.Where(b => b.TileIndex == radiusTile.TileIndex); // Do stuff. } }
Tutto ciò scompone il mio FPS da 60 a quasi 10 per un secondo.
Quindi potrei fare. Le mie idee sarebbero:
- Non utilizzare il thread principale (funzione di aggiornamento) per questo, ma per un altro thread. Potrei incorrere in problemi di blocco quando inizio a utilizzare il multithreading.
- Usare una coda per gestire molti calcoli (quale sarebbe l'approccio migliore in questo caso?)
- Conservare ulteriori informazioni nei miei oggetti (edifici) per evitare ulteriori calcoli (ad es. Edifici nel raggio).
Usando l'ultimo approccio ho potuto invece rimuovere un annidamento in questo foreach invece:
// Go through all buildings affected by erasing this road tile.
foreach(var affectedBuilding in affectedBuildings) {
// Go through buildings within radius.
foreach(var buildingInRadius in affectedBuilding.BuildingsInRadius) {
// Do stuff.
}
}
Ma non so se sia abbastanza. Giochi come Cities Skylines devono gestire molti più edifici se il giocatore ha una grande mappa. Come gestiscono queste cose ?! Potrebbe esserci una coda di aggiornamento poiché non tutti gli edifici si aggiornano contemporaneamente.
Non vedo l'ora di ricevere idee e commenti!
Molte grazie!