Aravid

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

Archivos mensuales: abril 2013

Gamer sense: Wild Arms

Hace no mucho fui recriminado por no haber visto el anime de Great Teacher Onizuka (GTO en adelante). El caso es que un día o dos antes había empezado a jugar al Wild Arms. Lo más gracioso es que tras unos pocos capítulos, descubro que Onizuka estaba jugando al Wild Arms también, lo que me pareció una señal divina de que tenía que seguir jugándolo y terminarlo.

No hace mucho que lo terminé y no me ha costado precisamente poco. Varias son las razones que han hecho que tardara bastante, algunas llegaron acompañadas de una activación de mi Gamer Sense, y otras no. Voy a hacer un breve repaso de las que lo activaron para justificar el nombre de este artículo, y la serie de artículos que se llaman igual que éste.

Correr es horrible. Y es algo habitual en los RPGs, en los que uno no se mueve precisamente poco. Innumerables mazmorras, ciudades, el mapa del mundo, etc. Además de que hay mucho que recorrer, también deberemos de investigar bastante y hablar con mucha gente (detalle que será ampliamente explicado en otro apartado).

Voy a explicar cómo funciona el correr para que se entienda mi frustración. Con la cruceta uno se mueve caminando, como es habitual, y se queda mirando en la dirección en la que hizo el último movimiento. Normal hasta aquí. Para empezar a correr pulsamos X y lo mantenemos presionado, pero en vez de correr directamente, empieza a mover los pies cómicamente mientras está quieto, como en los dibujos animados para unos momentos después, empezar a correr en la dirección en la que estaba encarado.

El hecho de que tarde bastante en empezar a correr ya es bastante malo de por sí, si no fuera porque viene acompañado de más cosas. El personaje corre en la dirección en la que estaba encarado y no puedes cambiar de dirección a menos que sueltes X, con la cruceta selecciones otra dirección y vuelvas a mantener X. El caso es que al soltar X la inercia te lleva un rato más en la dirección, así que si haces un cambio de dirección, tienes que contar con ese deslizamiento a la hora de hacer los giros.

Wild Arms Correr

Aquí podemos ver como corriendo, nos golpeamos contra el caballo y rebotamos.

Por último, pero no por ello menos importante, el remate total a la hora de correr. Si mientras corres te pegas contra un objeto sólido, ¡te estampas! Te detienes en seco, rebotas contra la pared y hay una animación para dramatizar tu fallo a la hora de manejar a tu personaje. Algo que no es difícil porque a la hora de hacer los giros, como he comentado antes, tienes que contar con la inercia que llevas. Por lo menos, no te haces daño, lo que sería el remate total, ¿verdad LBA?

Después de tanto odio por mi parte al asunto de correr, que no me negaréis que tiene su miga, viene algo que no sabría cómo catalogar. Mi Gamer Sense me dijo que había algo, pero no soy capaz de catalogarlo, y es el funcionamiento de la magia.

Explicación de la magia para que cada uno pueda sacar sus conclusiones. La primera división de magia es en blanca y negra. Una vez hemos seleccionado si es blanca o negra, tendremos una tabla de 4×4 en los que se cruzan los distintos elementos que se disponen, por lo que cada hechizo está formado por dos elementos (el orden es importante) por lo que tenemos 16 hechizos blancos y 16 hechizos negros.

WAmagic

Escaneo del manual de instrucciones con la magia de nivel básico

Para almacenar cada hechizo, debemos de disponer de un emblema sin utilizar, que se encuentra a lo largo de la aventura. Una vez disponemos de emblemas (empezamos el juego con dos) debemos ir a una ciudad del gremio de magia, donde un mago nos dice si queremos crear magia, renombrar un hechizo o disolver un hechizo.

Lo que me desconcierta un poco es, que directamente desde el principio, tenemos acceso a 32 hechizos distintos, y en ningún caso son permanentes, porque al disolver un hechizo recuperamos el emblema utilizado y todo esto por coste 0. No nos cuesta nada crear un hechizo o disolverlo.

No sé exactamente qué pensar. Desde el comienzo tenemos acceso a la mitad de todos los conjuros del juego, porque más adelante, se llegan a los gremios avanzados, que usando los mismos emblemas (por lo que nada te impide disolver todos los conjuros que llevas encima para crear magia avanzada) y el mismo sistema de creación de hechizos, tenemos versiones más potentes de los mismos hechizos y otros que cambian.

Quizá es que siempre que he jugado a RPGs, me han acostumbrado a obtener los conjuros poco a poco, incitando a probar ese nuevo conjuro, probándolos todos, buscando una utilidad y la mejor manera de aprovecharlos. Eso sin mencionar que al principio, nunca se dispone del conjuro que reanima a un compañero caído en combate, pero aquí lo tienes desde el inicio. ¿Qué será de los mercaderes que viven de las colas / plumas de fénix? Yo os digo, que morirán de hambre. Pero en un RPG ese problema nunca es permanente.

Lo que me lleva a otras preguntas más rocambolescas: con el poco uso que tienen los objetos recuperativos, ¿saldría más barato esperar a morir por inanición y luego utilizar un objeto de éstos? Con el poco mercado que tienen, seguro que sus precios están por los suelos. ¿O quizá los PV que aparecen representan el aguante, y realmente uno no muere, simplemente están exhaustos de forma temporal? En ese caso, los objetos no resucitarían, y la idea anterior carecería de valor. Pero de rebote explicaría por qué Aerith puede recuperarse en combates, pero morir en cutscenes. Cambio de tema que esto se me va de las manos.

Recogida de información aleatoria. Bajo este nombre tan chulo está una premisa de los RPGs de antes. No de todos, pero lo he visto en juegos antiguos principalmente, en casi ninguno moderno. Es el caso de la recogida de información que no se te suministra explícitamente para el avance del juego.

Es una norma no escrita el hecho de que al llegar una ciudad, siempre se de una vuelta completa y se hable con todos los PNJs que en ella habitan para obtener información. El problema es que esto no es obligatorio y podría llevar a ciertos problemas si esta información que nos debe de ser transmitida es vital para continuar.

Wild Arms Gemini

Aquí tenemos las imágenes que ilustran el ejemplo de abajo.

Voy a poner un ejemplo real para intentar explicar mi punto de vista. En un punto del juego, se deben de conseguir dos objetos, por lo que se hacen dos grupos, el del jugador, y uno controlado por PNJs para la recogida de objetos. Cuando volvemos con nuestro objeto, descubrimos que el barco en el que viajaba el otro grupo naufragó y se perdió irremediablemente el objeto. Es ahora cuando la persona que había solicitado los objetos dice que si no están los dos, no puede hacer las modificaciones necesarias en la nave, y que hay que buscar otra manera de avanzar, en ese instante recuperas el control y… nada más. Ahí estás, sin objetivo, sin información, sin ayuda. Nada.

¡Y lo peor es que te dice que hay que encontrar otra manera de avanzar! Desconcierto total.

Entonces es cuando uno se tiene que acordar (si es que hemos hablado con el aldeano que comparte esa información) que la ciudad que se llama Cementerio de barcos se llama así porque todos los restos de los barcos que naufragan en el mar interior, terminan en las costas de esta ciudad.

Wild Arms Yard

Aquí observamos como el aldeano en cuestión nos informa del sobrenombre de la ciudad y el porqué del mismo

Ccomo esta situación, se dan varias a lo largo del juego. Yo entiendo que este juego tiene un tiempo, el diseño de los RPGs ha cambiado y antes se podría llevar ese factor exploración de hablar con todos para obtener pistas para seguir en el juego. Tampoco quiero decir que los juegos que te llevan de la manita a todos los sitios son el camino a seguir, pero seguro que existe un punto intermedio a estos dos extremos.

Y por último, que la cosa se está haciendo larga, la traducción del juego. La traducción tiene bichos, y esas son las palabras más suaves que puedo dedicarle, porque entre frases inconexas y las que no se pueden entender, hacen que sea imposible comprender el juego (yo después de recuperar el arquetípico objeto que lleva la princesa que quiere buscar aventuras por los malos, que quieren utilizarlo para resucitar un mal antiguo no entendí casi nada más). Me fastidia porque no pude conectar con la historia ni con los personajes y, acabar el juego, se convirtió en una obligación, porque no tenía interés al no haber podido conectar como he comentado antes.

Como pequeño detalle, las mayúsculas no tienen tilde y en su lugar aparece un cuadrado blanco donde debería aparecer el carácter con tilde. Varios ejemplos son el reino de ‘Ártica’ o el objeto ‘Ánimo total’. Imperdonable.


Como bonus, pongo el video de introducción del remake del juego para PS2

UDK: Jugando con la cámara I

Pensando un poco desde el anterior tutorial (hace algo de tiempo), me he dado cuenta de que intentar manejar un juego con el ratón, sin antes explicar algo sobre la cámara sería problemático, porque aunque existen juegos que hacen uso del ratón en una cámara en primera persona (la que nos provee por defecto UDK), digamos que no es lo más habitual, así que aquí comienza una nueva saga en la que comento un poco el uso de la cámara para conseguir una en tercera persona.

En esta entrega, haremos uso de los siguientes ficheros:

  • Fichero del Pawn, DCleanerPawn.uc
  • Fichero del PlayerController, DCleanerPC.uc
  • Fichero del GameInfo, DCleanerGI.uc
  • Fichero de Inputs, DefaultInput.ini

Ahora que ya tenemos la lista de la compra, explicaré el objetivo de esta primera parte. Crearemos una cámara en tercera persona localizada a una distancia fija del personaje, que se moverá con él, y que con la rueda del ratón, podremos elevar o descender la cámara, pero siempre haciendo que nuestro personaje quede centrado, como detalle, haremos una sencilla interpolación en el eje de altura (eje Z) para que los cambios de cámara sean suaves.

Comenzamos con un paso previo en caso de que sea necesario, en el fichero del GameInfo, tenemos que hacer que nuestro juego herede de UDKBase.SimpleGame o tendremos problemas más adelante, como que por ejemplo nada de lo que hagamos funcione, este es el aspecto de mi DCleanerGI.uc después de esta actualización.

class DCleanerGI extends UDKBase.SimpleGame;

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

Ya estamos en condiciones de comenzar, antes de entrar al trapo, voy a comentar un poco cómo funciona el fichero DefaultInput.ini y qué hace.

En este fichero hay dos tipos de línea, las que definen una GBA o Game Bindable Action, y las que asocian una tecla o botón de un mando, a una GBA. Esto nos provee una capa intermedia entre asociar un botón a un trozo de nuestro código, lo que podría crear algún problema o inconveniente a la hora de intercambiar la función de los botones dentro del juego o similar, por lo que creamos una GBA que consiste en un nombre, y un pequeño trozo de código que invocará un método que hayamos creado, y luego asignaremos un botón a una GBA.

No quiero entrar mucho en detalle, pero con esto es suficiente para nuestros propósitos, así que abrimos el fichero DefaultInput.ini, y en cualquier punto del mismo, podemos añadir estas líneas

.Bindings=(Name="GBA_AlejaCamara",Command="alejaCamara")
.Bindings=(Name="GBA_AcercaCamara",Command="acercaCamara")

y tenemos que hacer un cambio más, que es modificar unas líneas (las dos primeras líneas del siguiente bloque ya están en el fichero), yo suelo comentar y volver a escribir, pero sois libres de modificarlas

; .Bindings=(Name="MouseScrollUp",Command="GBA_PrevWeapon")
; .Bindings=(Name="MouseScrollDown",Command="GBA_NextWeapon")
.Bindings=(Name="MouseScrollUp",Command="GBA_AcercaCamara")
.Bindings=(Name="MouseScrollDown",Command="GBA_AlejaCamara")

Las primeras dos líneas definen dos nuevas GBAs, les asignamos el nombre y lo que realizarán, que es ejecutar el comando de consola alejaCamara y acercaCamara, esto ya nos dice que esos métodos deben de definirse de manera que podamos ejecutarlos en consola.

El segundo bloque asigna a la rueda del ratón nuestras GBAs, el problema es que ya está asignada a otra GBA, así que rápidamente comentamos las líneas con el símbolo del punto y coma  y decimos que invoque a nuestras GBAs.

Ahora abrimos el fichero del PlayerController, DCleanerPC.uc en mi caso y añadimos los métodos exec que serán ejecutados cuando utilicemos la rueda del ratón.

exec function alejaCamara()
{
	local DCleanerPawn p;
	p = DCleanerPawn(Pawn);
	if(p.cameraOffset.Z < 570)
		p.cameraOffset.Z += 30;
}

exec function acercaCamara()
{
	local DCleanerPawn p;
	p = DCleanerPawn(Pawn);
	if(p.cameraOffset.Z > 330)
		p.cameraOffset.Z -= 30;
}

Los métodos no son excesivamente complicados, explicaré el primero, que el segundo es igual cambiando un signo y el límite. Primero creamos una variable para almacenar nuestro Pawn personalizado, y hacemos un cast de la variable Pawn que tiene el PlayerController para poder acceder a las variables que hemos declarado en nuestro Pawn personalizado.

A continuación comprobamos que la Z (el eje de las alturas) del vector cameraOffset (hablo de este vector en el siguiente párrafo) que almacena el desplazamiento de la cámara respecto al personaje no haya excedido el valor determinado por nosotros, si no lo ha hecho, lo aumentamos y terminamos. Aclarar que los valores son totalmente arbitrarios y no hay ninguna razón para utilizar estos, se pueden utilizar cualquiera.

Ahora a modificar la cámara en el fichero del Pawn, pero en el código de antes hemos hablado de un vector que no está en nuestro DCleanerPawn.uc, así debemos de añadir una variable de tipo Vector que almacene los valores que debemos sumar a la posición del personaje para situar la cámara, con esto conseguiremos que la cámara siempre esté centrada respecto a nuestro personaje.

var Vector cameraOffset;

Ya tenemos nuestra variable, ahora tenemos que sobreescribir el método CalcCamera que se encarga de calcular la cámara, para ello, nos pasa como parámetro la posición de la cámara y la rotación de la misma para que los modifiquemos, así que los calculamos y los almacenamos en los vectores que no pasan como parámetro.

simulated function bool CalcCamera(float dt, out vector CamPos, out rotator CamRot, out float FOV)
{
	// FOV Para consola: 65
	FOV = 85;

	CamPos.X = Location.X + cameraOffset.X;
	CamPos.Y = Location.Y + cameraOffset.Y;
	CamPos.Z = FInterpto(CamPos.Z, Location.Z + CameraOffset.Z, 0.2, 1);
	CamRot = Rotator(Location-CamPos);

	return true;
}

Empieza la explicación del código, que no es muy complejo. Al vector camPos que recibimos como parámetro, sumamos a la componente X y a la componente Y los valores X e Y de cameraOffset directamente. Para la componente Z hacemos uso de un método interesante que nos puede ser más adelante, que es el FInterpTo que lo que hace es interpolar un float de un valor inicial a uno final especificando una velocidad y un tiempo de interpolación, con esto conseguimos que la actualización del eje Z de la cámara se haga de forma suave, más rápido al comienzo de la interpolación y más suave conforme llega al final.

Nota: Existen más funciones del tipo de FInterpTo, dependiendo del tipo de variable que interpole, como IInterpTo que interpola enteros o VInterpTo que interpola vectores.

Para finalizar, debemos de especificar unos valores iniciales para el vector cameraOffset, en mi caso, yo utilizo (0,600,450), que han sido fruto de la experimentación. La componente Z está en función de los números que hay en los métodos de acercaCamera y alejaCamara, así que si los modificáis, acordaros de también cambiar los números de esos métodos.

Aquí añado el bloque de defaultproperties de la clase Pawn, en el que especificamos los valores iniciales del vector cameraOffset y también un modelo para nuestro Pawn de los que nos provee UDK.

defaultproperties
{
	cameraOffset=(X=0,Y=600,Z=450)

	Begin Object Name=SKMesh class=SkeletalMeshComponent
		SkeletalMesh = SkeletalMesh'CH_LIAM_Cathode.Mesh.SK_CH_LIAM_Cathode'
		AnimSets(0)=AnimSet'CH_AnimHuman.Anims.K_AnimHuman_BaseMale'
		bOwnerNoSee = false
	End Object

	Mesh = SKMesh
	Components.Add(SKMesh)
}

Y con esto, ya está completa la cámara. Es una cámara bastante rudimentaria, pero es un comienzo. De hecho, es más avanzada que la cámara de la versión entregada de Dungeon Cleaner, que era fija y no se podía modificar ningún parámetro.

Nota: Si lo habéis probado, o quizá con el código os hayáis dado cuenta, solo modificamos el eje de las alturas, dejando la distancia en los otros dos ejes sin alterar, con esto conseguimos aumentar o reducir la verticalidad de la cámara respecto al personaje y como consecuencia la distancia, pero no podemos alejarla sin elevar la cámara. En el próximo tutorial, hablaré de cómo hacer una cámara que tiene la capacidad de orbitar a nuestro alrededor, cambiando el ángulo desde el que vemos al personaje, y la distancia de la cámara sin modificar la verticalidad de la cámara.