J'ai déjà cherché des réponses mais je n'ai pas pu trouver la meilleure approche pour gérer des fonctions / calculs coûteux.
Dans mon jeu actuel (un bâtiment de ville basé sur des tuiles 2D), l'utilisateur est capable de placer des bâtiments, de construire des routes, etc. Tous les bâtiments ont besoin d'une connexion à une jonction que l'utilisateur doit placer à la frontière de la carte. Si un bâtiment n'est pas connecté à cette jonction, un panneau "Non connecté à la route" apparaîtra au-dessus du bâtiment affecté (sinon il doit être supprimé). La plupart des bâtiments ont un rayon et peuvent également être liés les uns aux autres (par exemple, un service d'incendie peut aider toutes les maisons dans un rayon de 30 carreaux). C'est ce dont j'ai également besoin pour mettre à jour / vérifier lorsque la connexion routière change.
Hier, je suis tombé sur un gros problème de performance. Jetons un œil au scénario suivant: Un utilisateur peut bien sûr également effacer des bâtiments et des routes. Donc, si un utilisateur rompt maintenant la connexion juste après la jonction, je dois mettre à jour de nombreux bâtiments en même temps . Je pense que l'un des premiers conseils serait d'éviter les boucles imbriquées (ce qui est certainement une grande raison dans ce scénario) mais je dois vérifier ...
- si un bâtiment est toujours connecté à la jonction dans le cas où une tuile route a été retirée (je le fais uniquement pour les bâtiments affectés par cette route). (Cela pourrait être un problème plus petit dans ce scénario)
la liste des tuiles de rayon et obtenez les bâtiments dans le rayon (boucles imbriquées - gros problème!) .
// 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. } }
Tout cela fait passer mon FPS de 60 à presque 10 pendant une seconde.
Je pourrais aussi le faire. Mes idées seraient:
- Ne pas utiliser le thread principal (fonction de mise à jour) pour celui-ci mais un autre thread. Je peux rencontrer des problèmes de verrouillage lorsque je commence à utiliser le multithreading.
- Utiliser une file d'attente pour gérer de nombreux calculs (quelle serait la meilleure approche dans ce cas?)
- Conservez plus d'informations dans mes objets (bâtiments) pour éviter plus de calculs (par exemple, les bâtiments dans le rayon).
En utilisant la dernière approche, j'ai pu supprimer une imbrication sous cette forme à la place:
// 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.
}
}
Mais je ne sais pas si cela suffit. Des jeux comme Cities Skylines doivent gérer beaucoup plus de bâtiments si le joueur a une grande carte. Comment gèrent-ils ces choses?! Il peut y avoir une file d'attente de mise à jour car tous les bâtiments ne sont pas mis à jour en même temps.
J'attends vos idées et commentaires avec impatience!
Merci beaucoup!