Ya he buscado respuestas, pero no pude encontrar el mejor enfoque para manejar costosas funciones / cálculos.
En mi juego actual (un edificio de ciudad basado en fichas 2d) el usuario puede colocar edificios, construir carreteras, etc. Todos los edificios necesitan una conexión a un cruce que el usuario debe colocar en el borde del mapa. Si un edificio no está conectado a este cruce, aparecerá un letrero de "No conectado a la carretera" sobre el edificio afectado (de lo contrario, debe eliminarse). La mayoría de los edificios tienen un radio y pueden estar relacionados entre sí (por ejemplo, un departamento de bomberos puede ayudar a todas las casas dentro de un radio de 30 baldosas). Eso es lo que también necesito actualizar / verificar cuando cambia la conexión de la carretera.
Ayer me encontré con un gran problema de rendimiento. Echemos un vistazo al siguiente escenario: un usuario también puede borrar edificios y carreteras. Entonces, si un usuario ahora rompe la conexión justo después del cruce , necesito actualizar muchos edificios al mismo tiempo . Creo que uno de los primeros consejos sería evitar los bucles anidados (que definitivamente es una gran razón en este escenario), pero tengo que verificar ...
- si un edificio todavía está conectado al cruce en caso de que se haya eliminado una baldosa de la carretera (lo hago solo para los edificios afectados por esa carretera). (Podría ser un problema menor en este escenario)
la lista de mosaicos de radio y obtener edificios dentro del radio (bucles anidados: ¡gran 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. } }
Todo esto descompone mi FPS de 60 a casi 10 por un segundo.
Entonces, ¿podría hacerlo? Mis ideas serían:
- No utiliza el hilo principal (Función de actualización) para este, sino para otro hilo. Podría tener problemas de bloqueo cuando empiezo a usar subprocesos múltiples.
- Usar una cola para manejar muchos cálculos (¿cuál sería el mejor enfoque en este caso?)
- Mantenga más información en mis objetos (edificios) para evitar más cálculos (por ejemplo, edificios en radio).
Usando el último enfoque, podría eliminar una anidación en forma de foreach en su lugar:
// 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.
}
}
Pero no sé si esto es suficiente. Los juegos como Cities Skylines tienen que manejar muchos más edificios si el jugador tiene un mapa grande. ¿Cómo manejan esas cosas? Puede haber una cola de actualización ya que no todos los edificios se actualizan al mismo tiempo.
¡Espero sus ideas y comentarios!
¡Muchas gracias!