Aravid

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

Archivos por Etiqueta: Game Info

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.

Anuncios

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.