Aravid

Tutoriales, Gamer Sense, opinión y más

UDK: Ratón en la interfaz I

Ahora que tenemos el GameInfo que especifica cuál será la clase que gestionará el HUD, vamos a crear un HUD con la particularidad de que dispondremos de un cursor que podemos mover con el ratón, y mostraremos en la esquina superior izquierda información relacionada con él, en este caso la posición 2D dentro de la ventana, la posición 3D en la que se encuentra el cursor la mostraremos en la siguiente parte, porque requiere una pequeña explicación, y creo que vale la pena. Más adelante podremos utilizar esta información para interactuar con el juego, pero vayamos por partes.

Así terminará el tutorial, con un ratón en forma de flecha y la información de posición en la esquina superior izquierda en un gris sospechosamente claro

Creo que es justo nombrar el artículo de la UDN que tanto me ayudo durante el proceso de creación de esta parte en Dungeon Cleaner. Incluso recomendaría su lectura antes de proseguir (puedo entender que es algo largo, en momentos un poco técnico y tiene mucho UDK script) y es el siguiente:

http://udn.epicgames.com/Three/DevelopmentKitGemsCreatingAMouseInterface.html

De hecho, la mayoría de lo que yo voy a explicar se puede extraer de ahí, la diferencia principal es que el artículo ayuda para la creación de una interfaz genérica y hay ciertas cosas que no realiza que son importantes si queremos utilizar el ratón como método principal de juego, que es lo que ocurre en nuestro caso.

Si lo habéis leído (espero que sí) habla de dos maneras para obtener la posición del ratón y trabajar a partir de ahí, mediante Scaleform y mediante UDK script. Voy a hablar un poco de mi experiencia sobre este tema. No puedo decir que haya trabajado Scaleform de forma exhaustiva en el juego, pero sí que ha tenido algunos problemas y eso que no ha sido utilizado mucho, por eso, me decanto por UDK script.

Además me parece mucho más directo que Scaleform, por eso será el que voy a explicar, si queréis atreveros con el otro, allá vosotros. No digo que no sea igual de bueno, pero siempre he leído que hay que tener algo de cuidado con la cantidad de elementos de Scaleform que se introducen en la escena, porque podrían afectar al rendimiento.

Una aclaración más antes de empezar el trabajo duro, en el artículo divide el código en tres clases distintas, cuando todo se podría realizar en dos, personalmente, me gusta ser ordenado en mi código, y si puedo separarlo en distintas clases, lo prefiero así, por ello voy a mantener la misma organización que utiliza el artículo mencionado anteriormente.

Primero tenemos que crear las clases de HUD y de PlayerController especificadas en el GameInfo, haciendo una consulta rápida a dicho artículo, y siempre manteniendo la coherencia de añadir el DC al comienzo de todos los archivos (cosa que realmente es bastante chorra si uno se para a pensar, al final tendrás una veintena de archivos que todos comienzan por DC y no servirá para nada, incluso un punto en la jerga informática habla sobre esto) son DCleanerHUD.uc y DCleanerPlayerController.uc

Ya se ha comentado antes, pero para hacer un repaso rápido, en DCleanerHUD escribiremos todo el código relacionado con el HUD (era obvio, pero no me cuesta nada recordarlo) y en DCleanerPlayerController se especifica qué acciones realizan los controles y cómo se maneja el Pawn. Aprovecho para decir que desde el HUD podemos acceder al PlayerController y viceversa con un simple cast y  que ambas clases son únicas en una instancia del juego, ya sea monojugador o multijugador (en este caso, se refiere al jugador local).

Comenzamos con el DCleanerPC.uc

class DCleanerPC extends PlayerController;

defaultproperties
{   
  InputClass=class'DCleanerMouseInterfacePI'
}

Bien, no es mucho, nuestro PlayerController no tiene que hacer nada por el momento, lo único, especificar que la clase que gestionará la entrada del juego es DCleanerMouseInterfacePI, que es la clase que trabajaremos a continuación.

class DCleanerMouseInterfacePI extends PlayerInput;

var IntPoint MousePosition; 

event PlayerInput(float DeltaTime)
{

  if (myHUD != None) 
  {
    MousePosition.X = Clamp(MousePosition.X + aMouseX, 0, myHUD.SizeX); 
    MousePosition.Y = Clamp(MousePosition.Y - aMouseY, 0, myHUD.SizeY); 
  }

  Super.PlayerInput(DeltaTime);
}

defaultproperties
{
}

En la primera línea, creamos una variable de clase de tipo IntPoint llamada MousePosition (un punto que almacena valores enteros, no os voy a descubrir nada nuevo) que es donde vamos a almacenar la posición en la que se encuentra nuestro cursor en todo momento, y que será accesible desde las clases, esto es importante porque la clase del HUD tiene que conocer el valor de la posición del ratón para calcular la posición 3D (comentado en futuras entregas).

Después definimos nuestro propio PlayerInput que es un método de clase para que realice lo que queremos, en nuestro caso, lo que queremos es actualizar la variable que contiene la posición del ratón. La primera acción del método es asegurarse que existe myHUD, que es el nombre de la variable de la clase PlayerInput que apunta a nuestro HUD.

Es una buena práctica asegurarse de que las variables que no están contenidas en la clase existan, porque si no existen, el juego no va a detenerse e informarte que has accedido a una variable que no está disponible, lo general es un aviso en el log

El problema (para mi no, porque tengo dos monitores) es que no puedas tener el log y la ventana de juego visible a la vez, que solo utilices el UDK editor que no tiene ventana de log o directamente ignores el log (mala práctica, esto nunca, o el día que te de por utilizarlo, veas que salen mil warnings por segundo. Es gracioso porque con una actualización del repositorio me salían tantos warnings por segundo que ralentizaba mi PC).

Aquí hay algo de miga, pero tampoco mucha, primero explicar el método Clamp, que su labor es asegurarse que la primera variable (la coordenada X o la Y) se encuentre entre los otros valores de entrada del método (esto es entre 0 y el tamaño del HUD), esto es importante porque queremos que la posición del ratón no se salga de la ventana, y en caso de que se exceda, lo ajusta al valor mínimo o máximo.

Un detalle sobre la implementación del artículo y que yo también emplée es que utiliza el incremento de la posición del ratón, por eso se observa que el primer parámetro del método es la suma de la posición actual del ratón y aMouseX o aMouseY , que es el incremento en cada uno de los ejes.

Y no hay mucho más que contar, con eso disponemos de la posición del ratón en nuestra ventana de UDK, ahora tenemos que informar al HUD que queremos dibujar un material en la pantalla en la posición que está el ratón para que el usuario pueda conocer su posición, y también escribiremos un pequeño mensaje en la parte superior izquierda con la posición. No es extremadamente útil en este momento, pero es una buena manera de disponer de información adicional durante la ejecución.

Nota: Si os habéis dado cuenta, la posición del ratón se calcula por incrementos, y una variable no inicializada, tiene sus valores a 0, por lo que al iniciar nuestro juego, el ratón siempre estará en la posición (0,0). Se puede inicializar y poner cualquier valor, como por ejemplo, la mitad de la ventana (myHUD.SizeX/2,myHUD.SizeY/2)

Ahora es cuando comienza lo más interesante, DCleanerHUD.uc

class DCleanerHUD extends HUD;

var const Texture2D CursorTexture; 

event PostRender()
{
  local DCleanerMouseInterfacePI MouseInterfacePlayerInput;

  if (PlayerOwner != None && CursorTexture != None) 
  {
    MouseInterfacePlayerInput = DCleanerMouseInterfacePI(PlayerOwner.PlayerInput); 

    if (MouseInterfacePlayerInput != None)
    {
      Canvas.SetPos(MouseInterfacePlayerInput.MousePosition.X, MouseInterfacePlayerInput.MousePosition.Y); 
      Canvas.DrawTile(CursorTexture, 64, 64, 0.f, 0.f, CursorTexture.SizeX, CursorTexture.SizeY,, true);
      Canvas.SetPos(50, 50);
      Canvas.DrawText("Posición Ratón ("$MouseInterfacePlayerInput.MousePosition.X$","$MouseInterfacePlayerInput.MousePosition.Y$")");
    }
  }

  Super.PostRender();
}

defaultproperties
{
  CursorTexture=Texture2D'DCleanerAssets.flecha'
}

Bien, empezamos por las variables de clase, que se encargan de almacenar la textura que representará el cursor, en nuestro caso, utilizamos una bonita flecha que amablemente descargamos de opengameart.org, al que le borramos el fondo para que fuera transparente y estuviera colocado en la esquina superior izquierda de la imagen, es importante porque cuando decimos que queremos dibujar una textura en pantalla en una coordenada, la esquina superior izquierda quedará en dichas coordenadas.

Nuestro cursor

Ahora viene lo bueno, el evento PostRender() que se ejecuta cuando promete, aquí es donde escribimos nuestro código relacionado con el HUD y que será ejecutado después del proceso de renderizado. Primero nos declaramos la variable que nos servirá para acceder al PlayerInput y comprobamos que tanto el PlayerController como la textura estén disponibles, si no hay problemas, seguimos.

El HUD tiene una variable llamada PlayerOwner que es de tipo PlayerController, por lo que podemos acceder directamente y pedirle el PlayerInput, pero por cosas de la programación orientada a objetos (en la que no voy a entrar, asumo que si estáis leyendo esto, sabéis cómo funciona), es, exactamente, un PlayerInput y no un DCleanerMouseInterfacePI que es lo que queremos, así que tenemos que hacer un cast y guardamos el resultado del cast. Ahora podemos acceder a las variables y métodos de nuestra clase propia.

Nota: La manera de comprobar si el cast es correcto es comprobar si la variable es distinta de None, en caso de que lo sea, el cast se ha realizado correctamente, y en caso contrario, es que el cast no ha podido realizarse.

Una vez sabemos que se ha podido realizar, colocamos el pincel del Canvas en la posición del ratón, que obtenemos mediante nuestra variable, y ahí, dibujamos el cursor con el método DrawTile al que le hemos especificado el tamaño del cursor a 64×64.

Para terminar, también escribiremos en pantalla la posición del ratón, primero moveremos el pincel a la posición donde vamos a escribir el mensaje, a efectos de posición, la esquina superior izquierda es el origen de coordenadas, el eje X es positivo hacia la derecha y el eje Y es positivo hacia abajo, sabiendo eso, colocamos nuestro pincel y escribimos el mensaje en pantalla.

Nota: Si lo probáis, os daréis cuenta de que al mover el ratón, la cámara también se mueve, eso es porque al heredar de PlayerController, éste tiene una funcionalidad por defecto que es el movimiento de la cámara con el ratón y del Pawn con WASD. Por eso se mueve tanto el cursor como la cámara, más adelante nos encargaremos de anular este comportamiento para que al mover el cursor, no se mueva la cámara.

Ha sido un poco largo, pero ya se ha terminado esta primera parte, en la siguiente entrega calcularemos la posición 3D del cursor, modificaremos la cámara a una tercera persona y haremos que no se mueva al mover el ratón.

Anuncios

Game Testing

Hoy voy a hablar del Game Testing, que es parte de un desarrollo, aunque se pueda pensar que es un proceso que se lleva a cabo después, una vez éste ha terminado. Bueno, no es del todo cierto, no voy a hablar del Game Testing, sino de una pequeña reflexión sobre el Game Testing en un juego concreto.

Y sobre todo, ¿por qué esto? Por el Rainbow Islands de Master System, que volvió a mi mente hace poco, y estuve pensando, ¿cómo era posible que un juego saliera con un Hindenbug y nadie se diera cuenta?

Portada de uno de los traumas de mi infancia. Eso de Rounds 8 no me lo creo…

Antes de nada, creo que hay que hablar de qué es un Hindenbug, y cuál es el de este juego. Hace poco llegué a un artículo en el que se hablaba de jerga creada por desarrolladores llamado New Programming Jargon, y en el punto 17 dice, con ciertas libertades en la traducción, que un Hindenbug es un bug catastrófico que destruye todo lo que se le pase por delante. Exactamente el bug en este juego no destruye datos, pero sí es lo bastante catastrófico como para merecer este calificativo. Y es que el juego no se puede terminar.

No voy a aburrir a nadie hablando del Rainbow Islands, es un juego que todo el mundo debería conocer, y si no lo conoce, ya va siendo hora. El caso es que en cada uno de los 7 mundos que forman el juego, se pueden adquirir 7 diamantes pequeños de colores para que al eliminar el jefe de dicho mundo, se nos entregue un diamante gigante. Al terminar el juego con los 7 diamantes gigantes, accedemos al mundo 8, y si no los tienes, ves el final “malo” por llamarlo de alguna manera. Lo gracioso es cuando eliminas al último jefe con todos los diamantes, con ganas de ver el último mundo, el mundo secreto al que sólo llegan los elegidos y después de una pequeña secuencia de imágenes que nos habla de ese mundo… el juego se reinicia. Sí, habéis leído bien, el juego se reinicia por las buenas. Pulsar cualquier tecla reinicia el juego y el enorme Hindenbug que sobrevuela los mundos estalla en llamas y arrasa con todo.

Ahora es fácil, vas a internet y preguntas al Sr.Google qué pasa con el juego, pero cuando tienes 6 ó 7 años y ocurre eso, no hay nada que hacer. Me acuerdo que hasta llevamos el juego a la tienda a decir que si nos podían dar otro, que ese parecía que estaba estropeado, con la esperanza de que eso cambiaría algo. Pero nada, aún tengo en la memoria los días jugando, haciendo pruebas y buscando posibles caminos ocultos, porque no entendía inglés y no sabía si me decían algo importante. De hecho, durante mucho tiempo estuve convencido de que el sexto diamante gigante era falso, y tenía que encontrarlo en otro lugar, ni me acuerdo de dónde salió eso.

Mi pregunta clave es ¿este juego lo ha probado alguien? Quiero decir, no estamos hablando de algún bug extremadamente extraño o difícil de conseguir. Es un bug que ocurre al jugar el juego una vez. La verdad, es que a día de hoy, aún no salgo de mi asombro ante esto.

Que maravillosa era la época de los cielos azules…

Ahora que conozco algo más el proceso de Game Testing, entiendo que hay que dar una prioridad a los bugs para ser atendidos, porque hay bugs más graves que otros. Pero que un juego se reinicie al llegar a cierto punto es uno de los más graves, y más si no tienes la posibilidad de arreglar errores una vez el juego ha sido vendido, como ocurría en los juegos antes.

En la actualidad, todo este tema es distinto, nuestras consolas están permanentemente conectadas a internet, y en cuanto se encuentra un bug, éste suele ser reparado con rapidez y llega a nuestras consolas casi de forma transparente, y esto es realmente bueno, pero algunas desarrolladoras malvadas se aprovechan de estas facilidades para sacar un juego a medias, o con un tiempo de testeo mínimo porque el plazo se les echa encima, pensando que todo se puede arreglar con un parche. Pero no, la confianza del consumidor no se arregla tan fácilmente, además que eso conlleva un coste, una actualización en una plataforma online se paga.

Antes de lanzarse a insultar a aquellas desarrolladoras que tienen un parche el día de lanzamiento, hay que tener en cuenta que un juego empieza a producirse en masa para su venta casi dos meses antes, si no más, eso da mucho tiempo para seguir trabajando pero todo ese trabajo no puede ser incluido. Entonces todos esos cambios y arreglos se empaquetan en un parche y se distribuye para que llegue a nosotros y nos permita jugar felices el primer día. Tiene su parte mala, como que cuando llegas a tu casa con el juego lo que quieres es jugar y no bajarte una actualización enorme, pero lo hacen por nuestro bien.

Esto no sirve para excusar a nadie, pero creo que era una aclaración que merecía figurar aquí.

Trabajo en grupo – Parte II

Continuando desde el artículo anterior de esta saga de Trabajo en grupo, toca hablar de las ventajas que tiene la realización de un proyecto en grupo. Algunas tiene, de verdad.

Y podría no parecer que las alegrías compensan a las penas de un trabajo así, porque en la primera parte, mi odio interior afloró, pero es que tratar con gente (what a bunch of bastards) no es fácil, y menos si en tu carrera, lo más parecido a un compañero de trabajo es cuadrado, te comunicas con él con teclado y ratón y lo puedes apagar si te molesta en exceso.

Uso de plataformas de trabajo colaborativo: No es una ventaja inherente al trabajo en grupo, porque se puede realizar un proyecto sin ellas, pero está bien que el grupo se obligue a utilizarlas. Muchas son las ventajas de estas herramientas, pero yo destacaría sobre las demás un control de versiones y un gestor de tareas, para saber en todo momento qué tareas tiene cada miembro del grupo asignadas y el tiempo que ha invertido en ellas (aunque en el momento de creación de la misma, se puede introducir una estimación del tiempo que consumirá). Esto servirá para más adelante estimar mejor los tiempos y poder realizar una planificación más exacta.

Reducción de tiempos de desarrollo: A más gente, más personas aporreando teclados, dibujando bocetos, modelando mallas y esas cosas que hacen falta para que un proyecto (un juego en este caso) se complete. Más manos no siempre significa ser más eficientes, porque dos personas no trabajan el doble, recordar que hay unos costes de comunicación asociados, que reducen la eficiencia del grupo, o puede que tu trabajo dependa de un trabajo previo de otra persona, por ejemplo.

Lo que para ti es un marrón irrealizable, para otro puede no serlo: Bajo este nombre tan estrambótico, reside la idea de que en un grupo, los conocimientos disponibles son siempre mayores que si uno trabaja solo, es por eso que si tienes que realizar algo que no sabes hacer, puede que alguien disponga de información útil que te ayude, o realizar un pequeño ajuste en la planificación para que esa tarea pueda realizarse con una inversión de tiempo menor y más eficazmente por otro.

Aprendizaje: Lo bueno de ser varios, es que, casi de forma transparente, se aprende de los otros miembros al igual que los otros miembros pueden aprender de ti. En un grupo, el conocimiento fluye y todos pueden aprovecharse de esto. Hay que tener cuidado porque hay personas que son muy recelosas de sus “descubrimientos” lo que hace que el conocimiento se detenga en seco y ese tiempo que ha dedicado en I+D para la finalización de esa tarea no se difunda al resto de miembros, lo que yo considero que es una pérdida.

Es como se trabaja: Nos guste o no, todos los proyectos del mundo real se hacen así. Esto no es una ventaja, pero sí una advertencia. Hay que cambiar el chip y aceptar que esto es nuestro futuro.

Estas son las ventajas que yo enumeraría sobre el trabajo en grupo. Seguro que hay muchas más, de hecho, si se hace una rápida búsqueda por Google, encontraremos largas listas de ventajas, pero yo hablo desde mi experiencia y punto de vista, y estas son las ventajas que yo he visto. Seguramente con el tiempo y más desarrollos en grupo, encuentre más ventajas, pero aún tengo mucho que aprender.

Seguro que dentro de un tiempo, cuando revise este artículo, me de cuenta de lo equivocado que estaba enumerando tan pocas ventajas y haciendo tanto hincapié en las desventajas de un grupo, aunque estoy intentando cambiar.

UDK: Game Info

El Game Info es una clase cuyo objetivo es definir el juego: las reglas del mismo, la puntuación, los actores que pueden existir y quién puede entrar en el juego. O al menos, eso es lo que dice la wiki sobre el fichero. En mi experiencia creando un juego monojugador, el trabajo que he tenido que realizar con el Game Info ha sido mínimo, ya que la mayoría de las opciones son para servidores multijugador.

Nota: Cuando UDK crea un nivel a partir de un mapa y del Game Info que define las características del juego, crea un servidor al que nosotros nos conectamos. Es importante conocer este detalle porque aunque estemos jugando solo, la creación del servidor se realiza.

Habitualmente especificaremos las clases que se encargarán de controlar nuestro juego y trabajaremos con alguno de los métodos que nos permite, como ejemplo, la función ScoreKill es utilizada en Dungeon Cleaner para el sistema de experiencia.

Para poder crear nuestro Game Info, debemos heredar de GameInfo o de cualquiera de las clases que heredan de ella.

class DCleanerGI extends GameInfo;

El siguiente paso es especificar, como mínimo, el peón del jugador, la clase que lo controla y el HUD.

 defaultproperties
{
	PlayerControllerClass=class'DCleaner.DCleanerPC'
	DefaultPawnClass=class'DCleaner.DCleanerPawn'
	HUDType=class'DCleaner.DCleanerHUD'
}

Con esto en el Game Info, debería de ser suficiente para poder comenzar a trabajar. Ahora si creamos un mapa de UDK y le especificamos que su tipo de juego va a ser este Game Info, ya sabrá cómo jugar el mapa.

Más adelante, cuando se hable del sistema de experiencia que se ha implementado en el juego, volveremos a este fichero para ampliarlo.

Trabajo en grupo – Parte I

Hoy quería hablar un poco sobre el trabajo en grupo, mis experiencias, por qué es importante y lo mal que nos han preparado para esto, y no precisamente en este orden.

Y es que la preparación que he recibido (hablo en mi caso, pero seguro que más de una persona se sentirá identificada) para trabajar en grupo ha sido, en el mejor de los casos, inexistente, digo en el mejor de los casos, porque si ha existido, lo más probable es que haya conseguido un sentimiento de rechazo brutal que te incita a escapar de él a la velocidad de la luz. Yo me incluía en este grupo, porque por experiencias pasadas, mi opinión del trabajo en grupo era tremendamente negativa y me había llevado a que durante la carrera, si se pedía un trabajo de estas características, aunque tuviera que realizar esfuerzos adicionales, intentar siempre realizarlo yo solo.

Aunque trabajar en grupo tiene sus cosas buenas, que comentaré más adelante, voy a comenzar con las cosas que consiguieron que me alejara de esta forma de trabajo durante tanto tiempo, hasta casi la actualidad, en la que he visto que no hay otra manera de conseguir realizar el desarrollo de un videojuego sin hipotecar tu vida. Existen casos de juegos excelentes realizados así, pero la inversión de tiempo ha sido realmente alta. Por poner un ejemplo, el tiempo de desarrollo de Braid fue de tres años.

Antes de desviarnos más, voy a hablar de los problemas que he encontrado en los trabajos en grupo, una vez más, en mi propia experiencia. Sobre todo, hablaré de este último desarrollo que he realizado, que ha sido el más grande y al que más tiempo he dedicado:

Comunicación: La comunicación en un grupo es un aspecto que tiene un coste asociado, de hecho, uno asombrosamente alto y que no te imaginas hasta que te sumerges en un proyecto real. Al igual que en los juegos hay ciertos atributos especiales que el jugador desconoce, pero afectan a todo, en las comunicaciones entre un grupo yo diría que existe un valor oculto que llamaré tasa de sincronía, que afecta a estos costes. Digamos que si entre los miembros del grupo hay una buena tasa de sincronía, puede reducirse ligeramente este coste de comunicación. Si vas a realizar un primer proyecto, lo más recomendable es buscar gente con la que tengas una buena tasa de sincronía. Lo peor es que no hay manera objetiva de manejar esto.

Democracia: Este siempre ha sido un aspecto que no he comprendido, quizá es que nadie quiere hacerse cargo del trabajo y así la responsabilidad se diluye en el grupo, otra razón que se me ocurre es que a nadie le gusta que le den órdenes, entonces, si eres el primero en sugerir lo que viene a continuación, pues remarcas su interés en no ser controlado.

El caso es que se comienza el proyecto y siempre hay una voz que dice “¡Vamos a votarlo TODO!”, una voz que debe de pensar que la democracia es el mejor invento del mundo, y que si todos votan sobre todo eso hará que la gente que votó por la opción que no salió seleccionada se sienta mejor. El principal problema con votar todo es que los costes asociados a la comunicación, que ya son bastante caros en un grupo, son elevados exponencialmente. Otro detalle importante es la coherencia, algo que se destruye si todo se vota y no hay una figura que se encargue de mantenerla a lo largo del desarrollo.

Interés: Este es un factor crítico y que es muy difícil de mantener a lo largo de un desarrollo. Como un miembro se desmotive, te saldrá con excusas, cada vez menos elaboradas (al principio suele ser realmente creativo para la creación de esas excusas) para trabajar menos o nada, porque no le gusta el rumbo que ha tomado el proyecto.

El que un miembro deje de ser productivo puede ser una bomba que destruya toda la planificación y la división de tareas, y en el peor de los casos puede tener salidas estrambóticas, como decir que abandona el grupo y dejar el proyecto temblando.

Posesión de la verdad absoluta: Este es el tipo de personas que más odio en un grupo. Como te caiga un elemento de éstos, estás jodido.

Una vez he mandado el mensaje alarmista, hablemos de ello. Las “estrellas del rock” (como me gusta llamarlos) son un tipo especial de gente que siempre cree estar en posesión de la verdad absoluta y que su opinión siempre es la mejor. Suele venir acompañado de no pegar un palo al agua porque ya te han iluminado con su sabiduría, así que consideran que ya es suficiente. Si realmente eres bueno, puede permitirse esta actitud, pero entonces, creo que no estás hecho para el trabajo en grupo.

Y ahora voy a compartir una pequeña cita de la página ¡Tenía que decirlo!:

Estudiantes, tenía que decir que en cualquier trabajo en grupo, siempre llega un momento en el que deseas asesinar al resto de compañeros, por bien que te caigan. Y si no te ha pasado, eso sólo quiere decir que alguien te quiere matar a ti. TQD

Es totalmente cierto. Aunque conozcas de toda la vida a los compañeros para la realización del proyecto, en algún momento vas a desear verlos muertos. Es normal, así que tranquilos, no estáis solos.

Pero no todo es malo en los grupos, algo bueno tiene que tener, pero viendo la longitud del artículo, voy a dejarlo para la próxima entrega.

Gamer Sense: Ghost Trick

Este verano he limpiado la Nintendo DS que llevaba bastante tiempo criando polvo, y he jugado a este juego llamado Ghost Trick, que yo diría que no es de los más conocidos de la consola, ni de los más publicitados. De hecho, mi conocimiento de este juego se remonta, una vez más, al programa Game Over, en el que Funspot, uno de los miembros del programa, deseaba incluirlo en su lista de los mejores juegos del año pasado.

Debo decir que mi sorpresa al jugarlo fue mayúscula, no me esperaba una aventura táctil (otras personas más aburridas lo llamarían aventura gráfica o novela interactiva) de estas características, tan cuidada en todos los aspectos. Admito que al menos, tenía la certeza de que iba a ser bueno porque tengo fe en la persona que lo recomendaba, pero no me imaginaba cuánto.

Portada del juego Ghost Trick, Detective Fantasma

Y es que el artículo, como Gamer Sense se acaba aquí, en ningún momento he sentido esa sensación que te eriza los pelos de la nuca mientras lo juegas que hace sentir que algo va mal, y como no lo he sentido, no puedo deciros ese aspecto o detalle que, en mi opinión, sería mejorable o que ayudaría al juego a ser mejor.

Quizá, intentando buscarle tres pies al gato, se podría decir que el juego te guía mucho y no se juega con ese concepto de investigar todos los lugares a nuestra disposición para encontrar nuevas pistas u objetos necesarios para continuar.

Para estar en antecedentes, el juego está dividido en una serie de capítulos, donde hay un comienzo y un final claro, que generalmente está asociado a la llegada a una localización y la resolución de la situación que ahí se plantea. Durante dicha resolución uno no puede moverse a otro lugar, menos en momentos concretos en que se nos plantea la posibilidad de ir a una localización B o seguir en la localización A, basta decir que suele ser fácil decidir en qué momento hay que cambiar de localización.

Y no me gustaría irme sin recomendar este juego. En serio, probarlo si tenéis la oportunidad. Sé que no he recomendado ninguno de los juegos que han pasado por esta sección, la mayoría de los juegos sobre los que he hablado han tenido su publicidad o al menos, han conseguido llegar al gran público por una u otra razón,  pero con este juego no he tenido esa sensación y no me gustaría que se quedase en el olvido siendo uno de los mejores juegos que he jugado en la Nintendo DS.

Los protagonistas de Ghost Trick, con sus peinados imposibles

Voy a permitirme el lujo de hablar de los dos detalles que más me han marcado mientras jugaba el juego, pero sin la intención de realizar un análisis. Ya hay mucha gente que analiza juegos.

El primero ha sido el diseño de personajes, cada uno con un carisma y una personalidad propia muy trabajada que lo diferencia de los demás, que hace que sea uno de los pilares principales del juego. Tampoco debería sorprenderme, porque en una novela (interactiva o no), sus personajes son casi tan importantes o más que la historia que se cuenta, pero es que parece que en los últimos juegos esto se ha olvidado, introduciendo personajes sin carisma (en el peor caso, clónicos de alguno que en su momento despuntó) que no despiertan interés alguno ni nos sentimos reflejados en ellos.

Y el otro es la historia, los acontecimientos que se cuentan en el juego y del que seremos parte activa. Realmente atractiva y consigue atraparte y tener ganas de más, yo diría que es lo mismo que ocurre con el punto anterior, es el otro punto fuerte de una novela, y aquí ha sido pensada con bastante detenimiento y ejecutada correctamente. Puede ser que algún detalle del final del juego no haya sido tan excelente como el resto, pero dicen que lo más importante del viaje no es el llegar, sino la aventura del viaje.

No quiero que penséis que estoy encumbrando el juego porque ha sido de los últimos que he jugado que ha realizado las cosas correctamente, es que en su género, lo que hace, lo hace realmente bien.

Reorientación del blog

Ahora que dispongo del tiempo y las ganas para seguir con el blog como se merece, hay unas cosas que quiero aclarar porque la concepción del blog, en parte, fue para hablar del desarrollo del juego que realizamos en el curso que estaba realizando sobre diseño y creación de videojuegos, y realmente, menos de eso, he hablado de muchas cosas.

Mirándolo ahora, creo que lo que quería hacer era otra cosa. Quería hablar de mi experiencia con UDK, lo que he aprendido e intentar compartirlo con el resto de la gente para que puedan dar rienda suelta a su imaginación y crear el juego que desean. Así que lo que voy a hacer a partir de ahora es utilizar el juego como referencia para los tutoriales que voy a seguir realizando.

Todos los tutoriales hablarán de aspectos que he desarrollado, más o menos como he venido realizando hasta ahora, pero sin la idea en mente de hablar directamente del juego, aunque me reservo el derecho de un postmorten del mismo.

Además, dentro de poco tendremos la presentación de los proyectos en sociedad en un acto del curso, para entonces deberíamos de tener una versión jugable y más o menos depurada, que también me gustaría compartir con el resto de la gente, para que puedan ver lo que he realizado en el juego.

En resumen, quiero que durante verano, el blog avance bastante. También estoy seguro de que más de uno se alegrará de que ésta última actualización no sea un ladrillo como viene siendo habitual.

Gamer Sense: The Legend of Mana

Se está convirtiendo en una costumbre hacer un artículo de estas características cuando termino un juego. Debo admitir que cuando lo empecé, aunque sabía que iba a redactar este artículo, no pensé que fuera a ser tan extenso porque recibí muchos comentarios positivos del juego. Creo que algunos de los puntos pueden ser suavizados por el momento en que se creó el juego y el momento actual, ya que este mundo está en constante evolución y algunas prácticas han cambiado a lo largo del tiempo.

Antes de hablar de cada uno de los puntos, voy a listarlos todos para que no pierda ninguno y si es necesario enlazar alguno, poder hacerlo:

  • Carencia de historia global
  • Falta de interés por el protagonista
  • Mapeados confusos
  • Innumerables sistemas a tener en cuenta (¡Incluso para un RPG!)
  • Desaprovecharlos todos
  • Truco sucio del golpe

Mi Gamer Sense comenzó a avisarme de que algo ocurría cuando al comenzar el juego, no se me explicaba nada ni ocurría nada. Elegía el nombre de mi personaje, al que yo bauticé como YOU (En la pantalla de selección de nombre, aparecía YOU escrito, inocente de mí, pensé que si presionaba Start directamente, se pondría el nombre por defecto. El caso es que sí se puso el nombre por defecto, pero yo no sabía que sería YOU), su sexo y su arma (un detalle eso de poder seleccionar con qué arma comienzas, lástima que luego no tenga mucha más repercusión que ser con el arma que comienzas) y se me lanzaba a la aventura. No sabía qué tenía que realizar ni qué se esperaba de mí, ahí estaba yo a la espera de que algo ocurriera. Lo esperé durante todo el transcurso del juego.

Aquí está toda la historia del juego. TODA

Quizá es que no he sabido entender la magia del título. Hay algo que he descubierto a lo largo del tiempo que he dedicado y es que cada lugar ofrecía una pequeña historia autoconclusiva en la que no formas parte en absoluto, más que como mero observador y a veces te ves introducido de una manera tan forzada que hasta me produjo rechazo. Mi Gamer Sense zumbó especialmente con la historia de Drakonis, una historia en la que te ves arrastrado a matar a una serie de dragones para recuperar unas piedras para resucitar a Drakonis para luego volver a mandarlo al infierno, te guste o no, pienses que es una buena idea o no, forzado y cruel porque los dragones molaban mucho.

Otro de los aspectos que muy cerca del comienzo me llamó la atención es la falta de un minimapa. Esa pequeña ayuda que sirve para que uno se oriente en un lugar. El caso es que el juego está formado por 26 lugares independientes, y cada uno de ellos, contiene una buena cantidad de pantallas conectadas. Si bien es cierto que algunos lugares son más extensos que otros, esta ayuda habría venido realmente bien porque las pantallas suelen tener varias salidas y se hace confuso. En más de una ocasión miré a la esquina superior derecha en busca del mismo, porque es donde suele estar, y no lo encontré.

Mapa de las Ulkan Mines. Ejemplo de mapa laberíntico

Una vez hablado del mínimo interés en YOU o de su inexistente historia, quería hablar de la ingente cantidad de sistemas que acompañan al título y que alargan la vida útil del título si hubiera alguna razón para usarlos, que no la hay, aunque de eso hablaré más adelante. Ahora voy a hablar de todos los que hay, once en total si los desmenuzamos al máximo.

  1. Forja de armas
  2. Temple de armas
  3. Forja de armaduras
  4. Temple de armaduras
  5. Creación de instrumentos
  6. Creación de golems
  7. Creación de bloques lógicos para golems
  8. Obtención de mascotas
  9. Mascotas
  10. Semillas
  11. Obtención de monedas elementales

La forja de armas y armaduras es bastante explicativa. Con objetos que recoges durante tu aventura, puedes crear armas y armaduras para tu uso (los NPCs que te acompañan, al igual que el golem o la mascota no pueden usar objetos, así que todo lo que hagas, es para tu uso personal). El temple lo que permite es sobre un objeto ya creado (via forja o comprado) mejorarlo mediante el uso de un objeto. Realmente es interesante esta libertad a la hora de crear tu equipamiento pero se pierde cuando no es necesario conseguir un equipamiento mejor del que compras en tienda.

En la forja creas tu nuevo equipamiento y puedes templarlo para mejorarlo

Las magias en este juego se adquieren creando un instrumento. Para crear uno hay que unir un objeto que crea el cuerpo del instrumento y una moneda elemental que especifica de qué elemento será el conjuro que contendrá, pero exactamente el área, la potencia y el conjuro concreto dentro del elemento lo especifica la unión del tipo de moneda y del objeto empleado, permitiendo una gran cantidad de combinaciones. Al no necesitar magia en ningún momento, no profundicé más, hice un instrumento de cada y ahí se quedó.

Aquí podemos hacer nuestros instrumentos encantados para tener acceso a la magia

En este párrafo voy a unificar la creación de golems con la lógica de los mismos. Primero debes crear un golem usando armas y armaduras que tengas por el inventario, eso determina los atributos del golem, la matriz lógica y el tipo de bloques que pueden usar. Una vez creado el golem hay que rellenar la matriz lógica con bloques lógicos que se crean con objetos. Los objetos que se utilicen determinan el tamaño del bloque lógico, y qué acción representan (pensar en los bloques como piezas del tetris y la matriz lógica como un tablero de 3×3, 4×4 o 5×5 dependiendo de la calidad de los materiales) donde debes colocar esas piezas para determinar el comportamiento del golem. Complejo e incluso atractivo, pero innecesario porque nunca necesitas tanta ayuda. Una lástima.

En el laboratorio, creas los cuerpos de los golems y los bloques lógicos de los mismos

Las mascotas y la obtención de los huevos, interesante pero que entra en conflicto con el sistema de los golems, porque no puedes llevar a un golem y una mascota, estás obligado a elegir uno de los dos, por lo que el otro va a ser desechado, y en mi humilde opinión, la complicación del sistema de los golems y la relativamente ineficiencia de los mismos, hace que uno se decante por las mascotas, y aún así, tampoco son excesivamente útiles. El caso es que durante el juego, te puedes encontrar con un huevo de mascota, que debes capturar dejando comida por la zona hasta que el huevo (¿?) se la coma y puedas capturarlo. Al capturarlo es llevado a tu rancho, donde puedes hacer que te acompañen, alimentarlos o dejarlos corretear por el corral donde van subiendo poco a poco de nivel. El problema es que la IA de las mascotas es bastante floja. Me atrevería a decir que la única utilidad de llevar a una mascota es para recibir menos ataques de los enemigos.

El granero, donde los huevos eclosionan. Luego puedes elegir sacarlos al corral a darse unos paseos al aire libre

Llegado a un punto en el juego, un enorme árbol imbuido con la energía Maná al que puedes entregar una combinación de dos semillas, para que un par de días después, las frutas ya estén maduras y puedas recogerlas. El problema que hay es que la utilidad de las frutas solo es en algunas forjas y para alimentar a las mascotas, porque no pueden ser consumidas para recuperar vida durante el juego. Al no utilizar casi nada los sistemas de forja o mascotas, este de las frutas quedó relegado al olvido muy rápido.

El árbol que imbuye las semillas con Mana para que maduren rápido, algo similar a lo que hizo Homer con el tomaco

El último sistema que tiene el juego es el de las monedas elementales, y la única razón por el que utilicé durante unos cinco minutos el de instrumentos musicales. En algunos puntos del juego, aparece un espíritu de maná que debes atrapar si quieres conseguir monedas elementales para los instrumentos. Para conseguirlo debes de tocar música para atraerlo y así capturarlo. Puedes colocar hasta ocho instrumentos, puedes elegir entre cuatro tipos de música y si un instrumento toca melodía o armonía, con todo esto, si al espíritu le gusta, se acercará y podrás capturarlo.

Si al espíritu en cuestión le gusta lo que interpretas, se acercará y podrás tocarlo, con lo que recibirás monedas afines al elemento del espíritu

El problema de que existan tantísimos sistemas en un juego es que te abruman, al final tienes que sacrificar algunos. ¡Los más grave es que incluso algunos se solapan! Como he dicho antes, no puedes llevar a un golem y a una mascota, así que no tiene mucho sentido utilizar ambos, a menos que tengas un interés especial por completar el juego. Mi problema con los sistemas es la total falta de necesidad de utilizar cualquiera de ellos.

Y aquí la última razón que activó mi Gamer Sense, el truco sucio del combate. Voy a intentar no extenderme en este punto, pero es que en un Action RPG, que exista un problema tan grave con el combate puede destrozar el título completamente. El caso es que tienes el ataque ligero y el ataque poderoso. El ataque ligero se puede encadenar  para hacer un combo de tres o cuatro golpes dependiendo del arma, y al terminar el combo, hay un tiempo hasta poder volver a atacar. Lo mismo ocurre con el ataque poderoso, al utilizarlo, tienes un tiempo que no puedes atacar. Imagino que la utilidad de esto es que los enemigos puedan moverse, huir de tí, o reaccionar para poder atacarte. Y llegó el desastre.

Si realizas un ataque ligero, el enemigo realiza una animación de recibir daño, lo que no le permite realizar ninguna acción, y si estaba haciendo alguna, deja de realizarla. Aquí está el asunto, no sé si voy a saber explicarlo bien, si esperas el suficiente tiempo entre ataque ligero y ataque ligero, en vez de seguir el combo, comienzas uno nuevo, realizando siempre el primer ataque del combo, el caso es que el tiempo que está el enemigo con la animación de recibir daño es superior al tiempo para realizar dos veces el primer ataque del combo, inutilizando totalmente al enemigo contra el que estás combatiendo. Si consigues enganchar el primer golpe y tienes un poco de ritmo, ese enemigo estará siempre reproduciendo la animación de recibir daño y tu atacándole sin descanso. ¡Funciona incluso con enemigos finales! En cuanto descubrí esto, y no tardé mucho en hacerlo, el juego dejó de suponer un reto y mi interés por él, decayó.

Y yo creo que ya está, he hablado de todos los aspectos que despertaron mi Gamer Sense, y no han sido pocos precisamente. La falta total de historia del protagonista, que hace que no sientas ninguna simpatía por él, la abrumadora cantidad de sistemas para el juego, desaprovecharlos todos porque no tuve que utilizar ninguno y que el combate tuviera un error tan evidente, pero que destroza completamente la experiencia de juego.

Agradezco a http://legendofmana.info/ y a http://lparchive.org/Legend-of-Mana/ las imágenes y algunos detalles del juego.

Documentos de diseño

Aunque en la etapa de preproducción se realizan muchos documentos de diseño, voy a hablar de los tres que son más relevantes en esta fase y que sirven para describir la evolución de la idea del juego, por llamarlo de alguna manera.

Si alguien tiene dudas sobre el proceso de creación de un videojuego, les remito a Game Over, el primer programa satírico sobre videojuegos, programa de radio y podcast en el que fanatiko tiene una sección llamada “Destripando la industria” donde habló sobre Las fases de desarrollo de un videojuego.

Su artículo es especialmente interesante porque la mejor visión posible es la de alguien que trabaja ya en la industria, porque aunque yo intentara hablar sobre ello, no sería más que un enfoque teórico, porque aún no he participado en ningún desarrollo.

Comenzando con el meollo, los tres documentos a tratar son el

  1. Game Design Overview o One-sheet
  2. Ten-Pager
  3. Game Design Document o GDD
Todos tienen una serie de características comunes y es bueno tenerlas en cuenta a la hora de redactarlos:
  • Concreción. Sobre todo en las versiones “técnicas” de los mismos, es decir, los que van orientados a tu grupo de trabajo.
  • Precisión. Los documentos serán la información base con la que la gente trabajará y creará los contenidos. Cuanto más exacto mejor porque evitarás interpretaciones erróneas y eso ahorrará tiempo.
  • Ameno. Mucha gente va a leer el documento, y si es un ladrillo, será pesado para los que lo tienen que consultar. Intenta organizarlo lo mejor posible y utiliza las herramientas disponibles, como índices, enlaces y listas.
  • Bien escrito. Al igual que por la razón que el punto anterior, mucha gente terminará consultando tus documentos, y los fallos gramaticales o tipográficos pueden dar una sensación de dejadez o de falta de interés a la hora de redactar los documentos, así que revísalos.

One-Sheet

Como su nombre indica, es un documento que idealmente debe de ocupar una cara y tener la capacidad de ser atractivo, porque va a ser la carta de presentación de tu idea. ¡Y vas a tener solo una cara para expresar lo maravilloso que va a ser! Siempre va a ser insuficiente y hay una serie de datos que es más que recomendable que aparezcan, reduciendo aún más tu espacio. Tampoco es obligatorio hablar sobre los datos que comentaré a continuación, pero es una plantilla bastante buena.

  • Título del juego
  • Plataformas en las que estará disponible
  • Edad objetivo
  • Calificación por edades (PEGI y ESRB)
  • Resumen de la historia
  • Jugabilidad
  • Unique Selling Points o USP. Es decir, qué hace especial a tu juego
  • Competencia

Otra cosa importante sobre este documento es que, por lo general, no va a estar dirigido a una persona que juega habitualmente. Este documento, con el que pretender vender tu idea, estará leído por gente que tiene que invertir o por jefazos, así que intentar hacerlo lo más ameno posible será buena idea.

Ten-Pager

El Ten-Pager es la evolución del One-Sheet, si la cosa funciona como es debido, la idea debe de desarrollarse, en este caso, hasta que ocupe unas diez páginas, pero al igual que el documento anterior, si es posible que sea más escueto, es incluso beneficioso.

Como detalle y para posibles contingencias, no está de más que este documento tenga forma de presentación de diapositivas, porque si la idea gustó, probablemente la siguiente fase sea enseñar, en forma de pequeña presentación, por qué tu juego es el mejor en este momento prematuro y deben de invertir su dinero a lo loco en tí.

Pero un Ten-Pager más técnico para que tu grupo pueda comenzar a trabajar tampoco está de más, por lo que mi recomendación es hacer dos documentos (por suerte no son extensos) siendo uno más centrado a la venta de tu producto y otro más centrado a las características del juego.

Los apartados recomendados para este documento, y con una longitud de aproximadamente una página por cada uno son:

  • Página del título
  • Resumen del juego
  • Personajes
  • Jugabilidad
  • Mundo
  • Experiencia de juego
  • Mecánicas
  • Enemigos
  • Cutscenes
  • Material extra
Una regla que se aplica en este documento y en el siguiente es la regla de los tres ejemplos, porque los ejemplos son un gran aliado. Permiten explicar situaciones con todo lujo de detalles y la resolución de las mismas, permitiéndonos aclarar posibles puntos oscuros. Siguiendo con la regla de los ejemplos:
  • El primer ejemplo da una idea al lector sobre la situación, pero puede que no quede claro.
  • El segundo ejemplo nos permite comparar con el primer ejemplo.
  • El tercero anula el efecto binario, y complementa los ejemplos anteriores.

¿Quiere esto decir que cada vez que hay que poner un ejemplo, debemos de invertir el espacio y la capacidad de atención del lector con tres? Evidentemente no, hay que saber cuándo utilizar esta técnica.

Game Design Document

Este ladrillo de innumerables páginas será vuestra peor pesadilla por varias razones, pero para desarrollos grandes, mi opinión es que hace falta, ya que en él TODO debe de estar especificado, explicado y detallado para que cualquier desarrollador, en un momento dado, si tiene que consultarlo para saber cómo realizar algo, lo encuentre y no tenga que molestar a las personas que han dedicado su tiempo a la creación de este documento.

Por desgracia todos conocemos a la gente y lo vaga que es, y en más de una ocasión pasarán de buscar en el documento y preguntarán directamente. Esto es inevitable a menos que dispongas de un elemento disuasorio en una posición privilegiada y visible (como por ejemplo, un trofeo de caza con la cabeza del último desarrollador que preguntó demasiado), pero se puede mitigar siendo un documento ordenado, fácil de entender y ameno (cosa imposible para este documento).

Otro de los grandes problemas que traerá este documento, es que el proceso de desarrollo de un juego es un proceso vivo, y a lo largo del tiempo, ciertas cosas ya especificadas serán modificadas por alguna razón, y todos esos cambios deben de figurar en este documento, así que mantenerlo al día debería ser imperativo.

Nota: Si os habéis dado cuenta, estos documentos están enfocados a la entrega a un publisher y un desarrollo para un grupo grande. Esto no quiere decir que no os pueda servir para un desarrollo individual o para grupos pequeños. Mi experiencia es que estos documentos habrían sido de gran ayuda en el caso de haberlos realizado correctamente y habernos ceñido a ellos.

Aprovecho para agradecer a Victor Cerezo por la clase sobre Documentación, sin la que éste artículo no habría sido posible.

Scaleform: Integración en UDK

Después de los dos tutoriales anteriores, ya tenemos una película de Flash preparada para que pueda ser importada en UDK. Para ello, debemos de hacer una clase que se encargue de la película en sí y de implementar los métodos que llamamos desde Actionscript.

El primer paso es importar a nuestro paquete de assets la película siguiendo los pasos a continuación:

  1. Lanzamos el Unreal Editor y nos vamos al Content Browser.
  2. Seleccionamos nuestro paquete de assets (en mi caso, DCleanerAssets) y pulsamos el botón Import.
  3. Seleccionamos la película que se encuentra en UDK\UDKGame\Flash\DCleanerAssets (Recordar que no podemos especificar a qué paquete de assets se añadirá la película. Lo hará en uno con el nombre de la carpeta, por eso mi carpeta se llama igual que el paquete de assets).
Ahora en nuestro paquete de assets tendremos un SwfMovie que es la película que hemos importado y una Texture2D que es el puntero del ratón.
Nota: Lo que importamos no es el fichero .fla, lo que importamos en el fichero .fla una vez publicado, que su extensión es .swf

A continuación, nos vamos a nuestra carpeta donde se encuentran todos los ficheros de UnrealScript, en mi caso y siguiendo las convenciones habituales, se encuentra en Development\Src\DCleaner\Classes siendo DCleaner vuestra carpeta para código propio. Como recordatorio, esta carpeta se definió en el primer artículo de UDK: Estructura de carpetas, y en dicha carpeta creamos un nuevo fichero que yo llamaré DCleanerPauseMenu.uc

Recomendación: Ya dije en el artículo de UDK: Herramientas que lo mejor para trabajar con UnrealScript es tener nFringe instalado, y para crear un fichero desde nFringe, nos vamos a la carpeta donde debería de estar el fichero, y con botón derecho -> Add -> New Item y seleccionando un fichero de UnrealScript, nFringe ya se encarga de crearlo y además el autocompletado de código funcionará mejor que si importamos el fichero.

Ya tenemos el fichero, y debemos especificar el nombre de la clase y de qué clase vamos a heredar. Yo llamaré a la clase igual que al fichero, es decir DCleanerPauseMenu y toda película de Flash debe de heredar de GFxMoviePlayer, así que sabiendo esto, podemos poner la primera línea:

class DCleanerPauseMenu extends GFxMoviePlayer;

A continuación, rellenamos el bloque de defaultProperties con el nombre de la película que vamos a reproducir, y activamos el boolean bPauseGameWhileActive que se encargará de pausar el juego mientras mostramos la película, que es exactamente lo que queremos para nuestro menú de pausa. También necesitamos capturar la entrada del juego, así que también activamos el boolean bCaptureInput. El bloque quedará así:

defaultProperties
{
	MovieInfo = SwfMovie'DCleanerAssets.PauseMenu'
	bCaptureInput=true
	bPauseGameWhileActive=true
}

Nota: Para obtener el nombre completo de la película, nos vamos al Content Browser y con botón derecho sobre el item del que queremos obtener el nombre completo, seleccionamos la opción de Copy fullname to clipboard.

Ahora tenemos que implementar el método Init(), que lo llamaremos para inicializar la película.

function Init(optional LocalPlayer LocPlay)
{
	super.Init(LocPlay); // Llamamos al método de la clase padre
	Start(); // Inicializamos la película

	/* Los siguientes métodos especifican el escalado de la película, al igual 
	que su alineación en la pantalla, los posibles valores de cada uno están 
	definidos en GFxMoviePlayer.uc pero como no me cuesta nada, os los copio 
	aquí para que conozcáis las posibilidades de cada método

	enum GFxScaleMode
	{
		SM_NoScale,
		SM_ShowAll,
		SM_ExactFit,
		SM_NoBorder
	};

	enum GFxAlign
	{
		Align_Center,
		Align_TopCenter,
		Align_BottomCenter,
		Align_CenterLeft,
		Align_CenterRight,
		Align_TopLeft,
		Align_TopRight,
		Align_BottomLeft,
		Align_BottomRight
	}; */

	SetViewScaleMode(SM_NoScale);
	SetAlignment(Align_Center);
	Advance(0.f); // Especificamos que vaya al frame 0 de la película
}

Solo nos falta implementar los métodos que son llamados desde ActionScript, los nombres que le dimos a estos métodos eran ExitMenu() y ExitGame(), así que los declaramos y los rellenamos.

function ExitMenu()
{
	ConsoleCommand("TogglePauseMenu");
}

function ExitGame()
{
	ConsoleCommand("exit");
}

Nota: El método ConsoleCommand lo que invoca es el método que se le pasa por parámetro como si lo hubieramos introducido en la consola.

El comando de consola exit ya existe, por lo que no tenemos que hacer nada con él, pero TogglePauseMenu no existe, y debemos de declararlo de forma que pueda ser invocado por consola para que todo funcione correctamente. El lugar más adecuado para este método es la clase personalizada para mostrar el HUD que ya debería de existir. Yo abro mi fichero DCleanerHUD.uc y al final, declaramos el método TogglePauseMenu que abrirá la película si está abierta, y en el caso de estar abierta, la cerrará.

/* Al comienzo del fichero, declaramos una variable de tipo DCleanerPauseMenu */
var DCleanerPauseMenu PauseMenu;

exec function TogglePauseMenu()
{
	/* Si el fichero no es igual a none y el flag de que la película está 
	abierta es true, lo que hacemos es cerrar la película. */
	if(PauseMenu != None && PauseMenu.bMovieIsOpen)
	{
		/* Cerramos la película. El parámetro de la función es si deseamos 
		eliminar de la memoria la película. En nuestro caso, como es un
		menú de pausa que será invocado en más de una ocasión, mejor no 
		eliminarlo porque la siguiente vez que fuera invocado, tendría que
		copiarlo a memoria de nuevo. */
		PauseMenu.Close(false);
	}
	/* Si por otro lado, la película no es igual a None o no se encuentra 
	abierta */
	else
	{
		/* Comprobamos si la película es igual a none, para inicializar la 
		variable. Lo realizamos así, porque al no descargar la película, 
		podría ocurrir que la película estuviera cerrada, pero que PauseMenu 
		no fuera none */
		if(PauseMenu == None)
		{
			/* Sabiendo que la película no está inicializada, la 
			inicializamos haciendo un new en nuestra variable */
			PauseMenu = new class'DCleanerPauseMenu';
		}
		/* Llegados a este punto, estando ya la película creada, o recién 
		creada, debemos llamar a este método para que muestre la película. 
		Recuerdo que este método lo hemos escrito en nuestra clase*/
		PauseMenu.Init();
	}
}

Nota: la palabra reservada exec se utiliza para especificar que un método puede ser invocado por consola. Lo que nos permite invocarlo con el método ConsoleCommand.

Ya hemos terminado con la integración de un fichero de Flash en UDK. Como habéis podido ver, es realmente fácil y una vez realizado uno, todos son iguales. Un pequeño resumen de los pasos es:

  1. Realizamos la película con los widgets específicos de Scaleform.
  2. Importamos la película a nuestro paquete de assets.
  3. Declaramos el fichero que hereda de GFxMoviePlayer.
  4. En el bloque de defaultProperties, especificamos la película y todos los parámetros por defecto, como bCaptureInput o bPauseGameWhileActive.
  5. Reescribimos el método Init() y modificamos la alineación o escalado al gusto.
  6. Y Voilá. Tenemos que buscar un sitio en nuestro código donde llamaremos a la película para mostrarla, y acordarnos de disponer de una manera de cerrar la película, o no podremos volver al juego.