Esto es mas bien una nota para mi, pero pueden usarla si creen que los saca de un apuro. Estas consideraciones me ayudan a decidir donde poner tal o cual código en un juego.
Por ejemplo, hace poco me surgió la siguiente duda mientras programaba un juego multiplayer de disparos:
Es la bala la que debe darse cuenta si le dió a un elemento que puede ser destruido a balazos(e informarlo al servidor), cada objeto destruible debe darse cuenta que fué impactado por una bala o debe haber una entidad(porción de código) que realice estas comprobaciones y lo informe al servidor?
El problema es que cada uno de los objetos propuestos debe tener referencias a los objetos con los que interactúa, pero ninguna opción es necesariamente mala. Uno puede pensar que el código que realiza todas estas comprobaciones debe estar en la clase principal, que iniclializa todos los objetos y, por ende, tiene la referencia a todos ellos, evitando crear singletons o pasando por referencia las colecciones de objetos durante al creación, complicando la interface de los constructores. Pero también puede querer que cada elemento (como las balas, las granadas y los objetos destructibles) sean autonomos y que ellos encapsulen las complejidades de su comportamiento y que cada objeto se de cuenta que si debe enviar o no datos por la red(si la posición de un jugador no cambia, no debería transmitirse).
Estas consideraciones pueden quitarnos gran cantidad de tiempo si no queremos arrepentirnos mas adelante si tenemos que tocar el código o pasárselo a alguien para que lo modifique.
Estos tips no son en absoluto sustituto de la experiencia, pero al menos nos ayudará a encontrar "la punta del ovillo".
1. Fundamentar las decisiones de diseño.
Si decimos "la bala debe darse cuenta si impacta contra un elemento que puede ser destruido o dañado" documentemos en el código por que tomamos esta decisión. Esto nos ayudará a no tentarnos a cambiar mas adelante el modelo por otro que nos guste mas.
2. Que todas las operaciones similares sean llevadas a cabo de la misma manera en todos lados.
Si tenemos una bala que se da cuenta cuando impacta a un jugador (con lo cual debe actualizar las propiedades como la energía del mismo o su velocidad) y luego tenemos que agregar la capacidad de lanzar granadas, que la granada se de cuenta también si explotó lo suficientemente cerca de un jugador como para dañarlo.
3. Si debemos cambiar un comportamiento, asegurarnos que es totalmente necesario y cambiar todos los comportamientos similares.
Este punto tiene como objetivo evitar cambios innecesarios y mantener la homogeneidad del diseño. Supongamos que el hecho de que bala se de cuenta de que impactó contra algo es antiperformante y nos tira abajo los frames por segundo. Por lo tanto, debemos crear una matriz de colisiones, manejada desde una entidad que contenga todas las referencias a las balas que hay volando en el escenario. Deberemos extraer el comportamiento de comprobación de colisiones no solo de la bala, sino también de la granada aunque esta ultima operación no afecte la performance del juego. De esta manera, la bala y la granada(proyectiles) se comportarán de la misma manera, lo cual allanará el camino para tomar futuras decisiones sobre proyectiles(como un misil), recordemos que puede ser que no seamos nosotros los que en un futuro tengamos que modificar o ampliar el código.
Por ahora eso es todo lo que tenía necesidad de bloguear. Ampliaremos.