Buenas prácticas en C# (Parte 3)
Hola y bienvenidos a un nuevo artículo del blog. Seguimos con las buenas prácticas en C# para Unity, este será el tercer y último artículo sobre este tema. Hoy veremos desde el punto 1 al 5 (de Unity), si quieres refrescar la memoria aquí tienes el primer y el segundo artículo.
Buenas prácticas en C#
- Usa nombres descriptivos en tus variables (y funciones)
- Usa clases de utilidad para tareas comunes
- Almacena la información en objetos en lugar de arrays
- No abuses de las variables estáticas
- Alinea el código con las llaves en vertical
- Crea las variables como privadas si no planeas compartirlas
- Evita los comentarios innecesarios (si usas bien el punto 1).
- Usa Enums
- Evita funciones con muchos parámetros. Si es necesario usa un struct.
- No silencies los errores (Exception)
BONUS: ESPECÍFICAS PARA UNITY
- Guarda las referencias necesarias en el Start()
- Usa print() en todas partes
- No todo son GameObjects
- Usa «RequireComponent»
- Update vs FixedUpdate
Buenas prácticas en C# 1: Guarda las referencias necesarias en el Start()
Échale un vistazo a este código:
Aparentemente es muy inocente, estamos accediendo al script del personaje en el Update y comprobando un valor. ¿Cuál es el problema?
Estamos obligando a Unity a “buscar” en cada fotograma el gameObject Player, y luego dentro del player, el componente ScriptPersonaje. Algo así como leer un libro en casa, y a cada página cerrarlo, guardarlo en la estantería, volver a cogerlo, buscar la página y leer la siguiente.
Hay una forma más eficiente:
Como ves, el código es muy similar, solo que guardamos el script una sola vez en el Start, y luego en Update lo reutilizamos las veces que haga falta. Suele llamarse “cachear” un objeto, aunque suene raro porque es un anglicismo.
Esto no son Buenas prácticas en C#… Imagen cortesía de humoranimal.com
Buenas prácticas en C# 2: Usa print() en todas partes
La consola es tu amiga. Puedes mostrar todos los mensajes que necesites, desde volcar el contenido de variables que usas en el código hasta el típico “paso por aquí” que se usa para comprobar si entramos en una función. Por ejemplo:
Si ejecutamos este código, la consola nos irá informando cada vez que el usuario pulse “Esc”.
Otro ejemplo:
La consola nos avisará cuando nuestro gameObject (el que contiene este script) choque con otro, y nos dirá cómo se llama ese otro.
Incluso este ejemplo es válido:
Buenas prácticas en C#
No es lo recomendado por lo poco que se explica, pero nos serviría para asegurarnos que nuestro programa pasa por ahí.
Buenas prácticas en C# 3: No todo son GameObjects
Cuando queremos pasar un objeto desde el editor, es común este código:
o su versión más refinada:
Los 2 nos permiten asignar ese valor (en el editor) para que el script lo utilice. ¿Entonces cuál es el problema?
El problema es que GameObject son todos, o casi. Podría pasar aquí un enemigo, el suelo, un gameObject vacío o cualquier cosa, y el editor diría “OK programmer”. El error saldría más adelante al intentar acceder a algo específico del player, como las vidas. Un ejemplo aquí:
La línea 5 funcionaría bien si hemos pasado al player desde el editor, pero si es otro objeto ¡fallará en tiempo de ejecución! El programa no tiene forma de saberlo hasta que intenta acceder al script y se encuentra… Que no lo encuentra.
Una forma de corregir esto sería declarar la variable así:
con este cambio tan breve, nos aseguramos que el gameObject que pasamos desde el editor contiene sí o sí el script que necesitamos, y lo más importante, no nos dejará asignar un gameObject que no lo contenga.
Buenas prácticas en C# 4: Usa «requiredcomponent»
Aquí debería añadir “…para reutilizar scripts y garantizar que funcionan”.
Imagina que creamos un script que necesita un RigidBody para funcionar, éste:
Si lo añadimos a un objeto cualquiera, funcionará si éste tiene un RigidBody. PERO fallará si no lo tiene, porque damos por hecho que está y en tiempo de ejecución (en el Start) Unity verá que no existe. Recibimos un desagradable mensaje de error:
“MissingComponentException: There is no ‘Rigidbody’ attached to the «Cube» game object, but a script is trying to access it.”
Si queremos evitar esto, podemos garantizar que el componente se creará automáticamente cuando añadamos nuestro script, así:
Es decir, añadimos la línea 1 justo antes de la declaración de clase. El resultado será que el propio editor creará el RigidBody por nosotros, y problema resuelto.
Buenas prácticas en C# 5: Update vs FixedUpdate
Por último, más que una recomendación es una duda muy común. ¿Para qué tenemos Update y FixedUpdate? Parecen la misma cosa, pero tienen sus diferencias:
Update se ejecuta en cada fotograma, es decir que su frecuencia no podemos saberla. En un ordenador potente pueden ser 60 veces por segundo, en uno más lento quizás 20. La cuestión es que se ejecuta tanto como es posible, y por eso aquí suele ir
- La recogida del input del usuario (Input.getKey y demás)
- Movimiento “manual” de los objetos, con .position o .translate
Nota: No olvides usar Time.deltaTime en tus cálculos para que el movimiento sea constante.
FixedUpdate (como su nombre indica) se ejecuta x veces por segundo. Siempre a esa velocidad, no importa el ordenador en el que esté funcionando. Esta estabilidad es necesaria para las físicas, no es lo mismo aplicar una fuerza a un objeto 20 veces por segundo que 60, en el primer caso el objeto se moverá y en el 2o… ¡Saldrá disparado!
En cambio, no nos interesa recoger aquí el “input” del usuario, porque al ser menos frecuente podemos perder pulsaciones de teclas y estropear la jugabilidad.
Recuerda que en este caso, deltatime no es necesario porque la frecuencia es constante.
¡Y hasta aquí el artículo sobre Buenas prácticas en C#! Hasta la próxima.