Esta es la “Regla de oro” de todo programador, y desgraciadamente es la primera regla que se rompe y a la larga termina perjudicando el desarrollo de todo el proyecto, así que por favor antes de escribir una sola línea de código empieza a planear tu juego en una forma estructurada y bien ordenada y cuando ya estés programándolo utiliza nombres coherentes para las variables que manejes y comenta tu código.
He visto gente que nombra a las variables:
int pxj1, pxj2, pye1;
¡esto es terrible!, quizás en un programa simple de 100 o 200 líneas de código no pase nada, pero en un proyecto más avanzado como un vjuego créeme que terminará causándote más problemas que si los hubieras escrito con un nombre lógico que pueda describir qué contienen esas variables, ejm.
int jugador1_pos_x; int jugador2_pos_x; int enemigo1_pos_y;
Si empiezas a ver mala hierba en el camino, detente, y regresa al punto donde todo iba bien y empieza a rehacer el camino, es mejor recodificar unas decenas de líneas de código que tratar de resolverlo con “atajos” y trabajar lo que queda de la programación con código indeseable, si no seguramente llegará el momento en el que te verás trabajando con una telaraña de código que prácticamente ya no puedas arreglarle detalles ni hacerle la más mínima actualización.
A veces puede ser tedioso trabajar ordenadamente y con limpieza, pero te ayudará a hacer tu código más intuitivo al momento de trabajar con él y a la larga puede ahorrarte mucho tiempo en terminar tu juego.
Espera a tener completamente terminado tu juego antes de empezar a optimizar el código, ya cuando tu juego haga todo lo que quieres que haga entonces puedes empezar a optimizarlo, esto te ayudará considerablemente ya que no tendrás que lidiar con código casi criptográfico mientras estas en el desarrollo o tener que optimizar el juego innecesariamente y ahorrarás tiempo considerable.
Seguramente el procesador de tu computadora está hecho con arquitectura RISC (Reduced Instruction Set Computer), esto es, que a tu computadora le gusta ser alimentada con instrucciones simples en lugar de largas y complejas, así que no por escribir algo todo junto así como:
if( mapa[ jugador.x >> 6 + 1 ][ jugador.y >> 6 + 1 ] == '0' ){ ... }
significa que el procesador vaya a ejecutarlo en un solo ciclo, ¡al contrario!, como solo puede recibir instrucciones reducidas al compilador le costará más trabajo simplificarlo para dárselo ya digerido al procesador y terminará creando código binario más lento.
Un algoritmo ineficiente para tus propósitos siempre será ineficiente, y ni aunque quieras programarlo total y absolutamente en lenguaje ensamblador vas a hacer que un algoritmo de orden O(n^2) corra más rápido, así q' mejor ve y busca algo más eficiente que haga lo que buscas; hay muy buenos libros sobre análisis de algoritmos allá afuera.
En mi opinión C++ es un lenguaje de programación muy bueno para programar vjuegos, ya que el paradigma de programar Orientado a Objetos se acopla muy bien a la estructura del juego, pero por favor, si estas haciendo tu juego en C++, esta bien manejar clases y herencia, pero si empiezas a utilizar funciones virtuales y polimorfismo ¡NO EXAGERES!, eso es algo que se realiza en tiempo de ejecución, por lo que sobrecargar demasiado y enloquecer en su uso terminará perjudicando el desempeño, ¡calma!.
Cuando declaras una función inline le estas diciendo al compilador que analice dicha función y si es posible que substituya su contenido en el lugar donde se hizo la llamada, y eso promoverá el buen desempeño del juego; pero esto tampoco significa que declares todas las funciones así, normalmente esta directiva se utiliza cuando se tratan de funciones relativamente pequeñas, además aunque lo hicieras eso no significa que debas de tomar por un hecho que el compilador lo va a hacer, el compilador primero lo va a analizar y solamente va a escoger a las funciones que mejor se acoplen.
Declarar funciones inline hará que el tamaño de tu ejecutable crezca, pero como ya había dicho antes la velocidad es la principal obsesión de un programador de vjuegos.
Seguido en tu juego te verás en la necesidad de usar funciones trigonométricas, pero eso consume una cantidad asquerosa de tiempo, es simplemente ineficiente querer calcular:
x = cos(m)*fuerza;
Así es que un buen truco para evitar esto es al inicio del juego precalcular los valores de las funciones trigonométricas que vayas a utilizar y guardarlos en un arreglo que contenga todos estos valores (si, tiempo = espacio^-1), de este modo te ahorraras muchos ciclos del procesador simplemente calculando:
x = coseno[ m ]*fuerza;
Hacer divisiones y multiplicaciones con los operandos / y * respectivamente también consumen mucho tiempo (aunque en los últimos procesadores ya no tanto), así es que siempre que puedas has recorridos de bits a la derecha e izquierda por medio de las directivas « y » las cuales dividen y multiplican por potencias de 2, es decir:
y = ( y << 3 ); // es lo mismo que y = y*23 o en otras palabras y=y*8 y = ( y >> 3 ); // es lo mismo que y = y/23 o en otras palabras y=y/8
Si te topas con la necesidad de hacer una división o multiplicación por un número que no es exponencial de 2, entonces puedes dividirlo en dos partes y sumarlos, por ejm. si quieres multiplicar por 74:
y = (y << 6) + (y << 3); // osea y = y*26 + y*23 -> y = y*64 + y*8 -> y = y*74
y sí, sigue siendo más eficiente que poner directamente y*=74, interesante ¿no?.
Convertir entre números enteros y números de punto flotante suele ser una práctica muy natural entre los desarrolladores de software, pero para representar el punto flotante en binario se interpreta como una descripción de la forma -25×10^-2 que en binario se ve:
1-1111110-001000000000000000000000000000000000000000000000000000000
Dónde el primer bit es el signo, los siguientes 7 bits son el exponencial, y los restantes 56 bits son el número en sí, ¿cuántos ciclos crees tú que le tomaría al procesador para decodificar eso y transformarlo a un entero?… sí… muchos!…. así que trata de evitar hacer cast entre int y floats lo más posible, si no el desempeño del juego se te va a venir abajo.
Muchas veces dentro del desarrollo de vjuegos se tienen que procesar largos arreglos de algún tipo de estructura (ya sea en la física o sistema de partículas).
Una forma de optimizar su procesamiento es usando apuntadores en lugar de índices, por ejemplo, en un sistema de partículas si tubiéramos:
Particula arreglo[21000];
for( int i=0; i < 21000; i++){
arreglo[i].x = .... //cualquier cosa
arreglo[i].y = ....// cualquier cosa
...
}
se estarían haciendo muchos cálculos para acceder a localidades específicas dentro del arreglo. y eso toma tiempo. Una forma más eficiente sería usando apuntadores así:
Particula arreglo[21000];
Partícula *particula_actual = arreglo;
Particula *fin = & arreglo[21000];
while( particula_actual++ < fin ){
particula_actual->x = ....// cualquier cosa
particula_actual->y = ....// cualquier cosa
....
}