Más movimientos básicos

En este post continuaremos con las acciones relacionadas con los movimientos básicos dentro de un juego. Empezaremos por explicar como hacer que la cámara siga a nuestro personaje. Será tan simple como arrastrar en Hierarchy nuestra cámara encima del personaje (la cápsula) y ajustarla en la Scene de manera que enfoque a nuestro personaje del modo que deseemos. Si ahora movemos a nuestros personaje la cámara lo seguirá, manteniendo la posición con respecto a él. El problema es que no se girará.

camera

Para girar la cámara necesitamos que nuestro personaje pueda girar. Por eso vamos a añadirle la posibilidad de rotar. Empezaremos creando una variable pública de tipo float a la que llamaremos rotateSpeed que será la que indique la velocidad de giro. Indicará los grados por segundo que queremos que gire nuestro personaje. Le asignaremos un valor igual a 180 de modo que tardara 2 segundos en dar una vuelta completa sobre sí mismo. Para rotar al personaje usaremos la función Rotate de la clase Transform (más información aquí). Los argumentos que le daremos serán los valores de rotación para cada eje (x,y,z). En nuestro caso como queremos que rote de izquierda a derecha nos corresponderá únicamente el eje Y. Esto podemos comprobarlo en Unity cambiando al modo de rotación en la Scene y seleccionando nuestro personaje. Aparecerán tres circunferencias indicando la rotación de cada eje. Por defecto los colores asignados serán rojo para X, verde para Y y azul para Z. Comprobaremos que para girar de izquierda a derecha la cápsula debemos rotar el eje Y.

rotateY

El giro de nuestro personaje vendrá dado por las teclas de movimiento A y S (además de las teclas de dirección izquierda y derecha), por lo que usaremos la función GetAxis de Input con el eje «Horizontal». Escalaremos el resultado con la variable rotateSpeed que regulará la velocidad de giro y con Time.deltaTime para que dependa del tiempo. Quedará por tanto la siguiente línea de código transform.Rotate (0, Input.GetAxis ("Horizontal") * rotateSpeed * Time.deltaTime, 0); . Para evitar conflictos con el movimiento que ya teníamos asignado en el eje X con la misma entrada, lo eliminaremos del vector currentMovement que servía como parámetro para la función Move. De este modo nuestro objeto solo se moverá con respecto al eje Z, es decir, adelante y atrás. Sin embargo, este movimiento adelante-atrás será con respecto a las coordenadas globales, por lo que, si giramos nuestro personaje y pulsamos W, no avanzará hacia adelante con respecto a su nueva posición, sino que avanzará hacia adelante con respecto a las coordenadas globales. Si por ejemplo giramos el personaje 90 grados a la derecha y pulsamos W, avanzará a su izquierda en lugar de adelante. Para solucionar esto multiplicaremos nuestro Vector3 por la rotación de nuestro personaje que vendrá dada por la variable transform.rotation, lo cual es un Quaternion (lo veremos más adelante). Esto permitirá al personaje moverse hacia donde quiere teniendo en cuenta su rotación. Para hacer eso escribiremos el código currentMovement = transform.rotation * currentMovement; . Si variamos el orden de los factores en esta multiplicación nos dará un error, deben tener este orden de colocación. El código final que resulta de todo esto será el siguiente:

using UnityEngine;
using System.Collections;

public class PlayerScript : MonoBehaviour {

public float moveSpeed = 5;
public float rotateSpeed = 180;
CharacterController controller;
Vector3 currentMovement;

void Start () {

controller = GetComponent<CharacterController> ();
}

void Update () {

transform.Rotate (0, Input.GetAxis ("Horizontal") * rotateSpeed * Time.deltaTime, 0);

currentMovement = new Vector3 (0, 0, Input.GetAxis ("Vertical") * moveSpeed);
currentMovement = transform.rotation * currentMovement;

controller.Move (currentMovement * Time.deltaTime);
}
}

coderotate

Para poder distinguir mejor cuando rota nuestro personaje, sin necesidad de fijarnos en los datos de rotación del componente Transform, le añadiremos algunos detalles a nuestra cápsula. Por ejemplo una boca y unos ojos haciendo uso de cubos, o unos brazos. Esos objetos una vez creados y editados los meteremos dentro de nuestro player.

custom player

Movimientos básicos

En este post crearemos una cápsula a la que le añadiremos los movimientos básicos izquierda-derecha y adelante-atrás. Crearemos todo desde cero, por lo que lo que hemos hecho hasta ahora lo guardaremos en una carpeta dentro de Project a la que llamaremos Pregame. Creamos una nueva escena ( File->New Scene ) sobre la que trabajaremos y la guardamos (Ctrl+S) con el nombre Test Level en una carpeta nueva a la que llamaremos Scenes.

testlevel

Empezaremos creando el suelo. Para ello crearemos un cubo al que expandiremos en superficie y reduciremos su altura para formar un plano.

suelo

Añadiremos una Point Light que provea luz a nuestra escena si no disponemos ya de alguna (probablemente tengáis ya una Directional Light por defecto). Podéis ajustar la cámara si lo creéis oportuno. Toca ahora crear nuestra cápsula, a la que dotaremos de movimiento, y la renombraremos como Player. Aseguraros de que no esté colisionando con el suelo. A continuación añadiremos  el componente Character Controller mediante Add Component->Physics->Character Controller y eliminaremos Capsule Collider, ya que Character Controller ya habilita las colisiones. Básicamente Character Controller es un sistema empleado para crear personajes que se muevan y colisionen con el entorno. Las opciones de este componente nos permiten configurar las dimensiones de colisión que tendrá el objeto. Por ejemplo, el Step Offset determinará la altura del escalón que el personaje será capaz de subir simplemente con su desplazamiento normal sin recurrir a saltos o demás.

character collider

Lo siguiente será crear una carpeta para nuestros scripts y crear dentro un script para nuestro Player al que llamaremos PlayerScript. Lo primero que escribiremos en nuestro script será una variable pública de tipo float llamada moveSpeed para determinar la velocidad de movimiento de nuestro personaje, public float moveSpeed = 5; . Ahora para acceder al componente Character Controller usaremos la función GetComponent<type>( ) que devolverá como resultado un componente del tipo indicado por type  (clic aquí para más información) y para aplicarle movimiento al objeto usaremos la función Move de la clase Character Controller que vendrá explicada aquí. Para usar la función Move necesitamos pasarle un Vector3 que indique cómo se moverá el personaje.  Para las coordenadas de dicho vector usaremos las entradas de las teclas que usaremos para el movimiento (WASD). Para el eje X emplearemos «Horizontal»,  que según Edit->Project Settings->Input corresponde con las teclas A y D (además de las flechas de dirección izquierda y derecha), y para el eje Z «Vertical», teclas W y S (además de las flechas de dirección arriba y abajo). De modo que nuestro Vector3 quedaría new Vector3(Input.GetAxis ("Horizontal") * moveSpeed*Time.deltaTime, 0, Input.GetAxis ("Vertical") * moveSpeed*Time.deltaTime) . La función GetAxis de la clase Input es similar a GetButton pero con el uso de ejes en vez de botones (más información aquí). Los valores están escalados por nuestra variable moveSpeed para determinar la velocidad del personaje y por Time.deltaTime para que dependa del tiempo y no del frame rate. Juntándolo todo en una misma línea de código el resultado final es GetComponent ().Move (new Vector3(Input.GetAxis ("Horizontal") * moveSpeed*Time.deltaTime, 0, Input.GetAxis ("Vertical") * moveSpeed*Time.deltaTime)); .

code1char

using UnityEngine;
using System.Collections;

public class PlayerScript : MonoBehaviour {

public float moveSpeed = 5;

void Start () {

}

void Update () {

GetComponent <CharacterController> ().Move (new Vector3(Input.GetAxis ("Horizontal") * moveSpeed*Time.deltaTime, 0, Input.GetAxis ("Vertical") * moveSpeed*Time.deltaTime));
}
}

Para no tener que hacer uso de GetComponent cada vez que queramos acceder a Character Controller podemos crear una variable de tipo CharacterController a la que llamaremos controller y dentro de Start asignarla a GetComponent<CharacterController>( ). De este modo a partir de ahora podemos sustituir GetComponent<CharacterController>( ) haciendo uso únicamente de la variable controller. De igual forma crearemos una variable Vector3 a la que llamaremos currentMovement y dentro de Update la igualaremos a new Vector3(Input.GetAxis ("Horizontal") * moveSpeed, 0, Input.GetAxis ("Vertical") * moveSpeed); . Hemos quitado los deltaTime ya que eso lo multiplicaremos por el Vector3 currentMovement dentro de la función Move. Si multiplicamos un vector por un float el resultado será que cada uno de los componentes x, y, z será multiplicado por él.

El código quedará así:

code2char

using UnityEngine;
using System.Collections;

public class PlayerScript : MonoBehaviour {

public float moveSpeed = 5;
CharacterController controller;
Vector3 currentMovement;

void Start () {

controller = GetComponent <CharacterController> ();
}

void Update () {

currentMovement = new Vector3 (Input.GetAxis («Horizontal») * moveSpeed, 0, Input.GetAxis («Vertical») * moveSpeed);
controller.Move (currentMovement * Time.deltaTime);
}
}

Ya dispondremos de una cápsula capaz de moverse de izquierda a derecha y de adelante hacia atrás.

Cómo pensar en el código

En este post aprenderemos cómo hacer que nuestra esfera salte cada 3 segundos. Si buscásemos una solución en internet a las cosas que queremos hacer podríamos encontrar algo parecido, pero probablemente no exactamente lo mismo. Por ello debemos pensar siempre en cómo hacer lo que pretendemos e ir paso a paso desde el principio, diviendo en partes los problemas.

Empezaremos creando una nueva esfera como ya sabemos, Create->3D Object->Sphere. La llamaremos Sphere 3s. Para evitar confusiones desactivaremos nuestra otra esfera saltarina. Añadiremos el componente Rigidbody a Sphere 3s en Add Component->Physichs->Rigidbody. Crearemos también un nuevo script en Project en la carpeta Scripts mediante Create->C# Script y lo llamaremos Ball3sScript.

sphere3s

Ahora nos centraremos en el código que necesitamos para que nuestra esfera realice la acción de saltar cada 3s. Dividamos el problema en partes mas pequeñas que debemos conseguir para tal fin. Puede ser recomendable usar el bloc de notas para anotar todos los pasos que vayamos a realizar. Necesitaremos un contador de 3 segundos, que la esfera salte al llegar el contador a 0 y reiniciar el contador. Para nuestro contador necesitamos crear una variable que recuerde el tiempo actual en el contador, ajustar el contador para empezar en 3 cuando empezamos el juego, contar hacia atrás a razón de 1 por segundo nuestra variable, si la variable llega a 0 o menos hacer saltar la bola y reiniciar el contador de nuevo en 3 cuando nuestra esfera salte. También necesitamos una variable ajustable, a la que llamaremos jumpHeight, que nos indique cómo de alto va a saltar nuestra esfera. Para que nuestra esfera salte recurriremos a AddForce para añadir una fuerza en el eje y basada en el valor de jumpHeight.

Crearemos una variable pública de tipo float llamada jumpHeight y le asignaremos un valor de 500, que ya comprobamos ser un valor suficiente para hacer saltar una esfera de masa 1. Si no le asignásemos ningún valor adquiriría un valor igual a 0 por defecto. Ese será el caso de la variable pública de tipo float llamada timer que crearemos para el contador. Dentro de Start la inicializaremos a 3. Ahora tendremos que hallar algún modo de decrementar la variable timer en 1 cada segundo. Para ello buscaremos en Unity Scripting Refence un modo. Si buscamos dentro de Classes alguna clase llamada Time veremos que existe una con ese mismo nombre. Dentro encontraremos «deltaTime», una variable que nos indica el tiempo en segundos que tardó en completarse el último frame. Si queremos hacer algo en intervalos temporales por segundo usaremos deltaTime.

deltaTime

Para decrementar una vez por segundo nuestra variable timer escribiremos timer -= Time.deltaTime;. Si por ejemplo quisiésemos hacer lo mismo cada 5 segundos sería timer -= Time.deltaTime * 5;. Lo siguiente será hacer que nuestra esfera salte si el contador llega a 0 o menos. Para ello usaremos una sentencia if ( timer <= 0 ). En caso de que se cumpla la condición la esfera saltará usando la línea de código GetComponent<RigidBody>.AddForce ( 0, jumpHeight, 0 );. Sin embargo, para evitar que se añada esta fuerza en cada frame debemos reiniciar el contador , por lo que añadiremos dentro del if el código timer = 3; para reiniciar el contador en 3. Recordad hacer uso de las llaves para introducir más de una acción dentro de una sentencia if.


using UnityEngine;
using System.Collections;

public class Ball3sScript : MonoBehaviour {

public float jumpHeight = 500;
public float timer;

// Use this for initialization
void Start () {

timer = 3;
}

// Update is called once per frame
void Update () {

timer -= Time.deltaTime;

if (timer <= 0) {
GetComponent().AddForce (0, jumpHeight, 0);
timer = 3;
}
}
}

codejump3s

Recordad dividir los problemas grandes en problemas más pequeños y hacer uso de Unity Scripting Reference o Google para buscar la solución a algo cuando os quedéis atascos.

Unity Scripting Reference

En este post aprenderemos como navegar por Unity Scripting Reference, en donde tendremos toda la información necesaria a la hora de realizar nuestros scripts. La encontraremos en http://docs.unity3d.com/ScriptReference/ . Una vez en la página iremos al apartado UnityEngine->Classes, en donde estará toda la documentación que necesitaremos.

classes

Vayamos por ejemplo a la función AddForce que hemos empleado en Rigidbody. Para ello buscaremos la clase Rigidbody dentro de Classes. Ahí encontraremos una descripción de lo que es, sus variables, funciones, etc.

rigidbody

En la parte de Functions buscaremos la función AddForce y clicaremos en ella. Nos enlazará a la página en donde se muestra toda la información relacionada con dicha función. Debemos elegir en la esquina superior derecha el lenguaje de script, para nosotros C#. En el caso de AddForce se nos muestran dos usos de la misma función. En nuestro caso el uso que hemos utilizado en nuestro script es el segundo, en el que añadimos las componentes ( x , y , z ).

addforce

Si hacemos clic en cualquier palabra marcada con un color diferente y un subrayado nos enlazará con la información que haga referencia a ese término en concreto. De modo que si por ejemplo clicamos en Vector3 nos llevará a la página que contiene toda la información de Vector3: variables, funciones, etc. Vector3 puede actuar como variable (indicando una zona en el espacio) o como clase (por ejemplo para calcular la distancia entre dos variables Vector3 con la función Distance).

vector3

Tenemos la posibilidad de acceder desde Unity a Scripting Reference. Para ello debemos ir a Help->Scripting Reference. Sin embargo, esta opción abrirá en nuestro explorador una versión que tendremos en nuestro disco duro de Scripting Reference instalada al mismo tiempo que Unity.

help

Aunque sea una versión local contiene todos los datos como si de la versión online se tratara. Por ejemplo, vayamos a la clase Mathf. Esta clase contiene una colección de funciones y variables matemáticas constantes como puede ser el número PI o una función de redondeo de número decimales a enteros (Round). Haciendo clic en cualquiera de ellas se nos abrirá una página nueva con la información de cada una.

Mathf

A la hora de escribir el código para acceder a una clase, pongamos como ejemplo la clase Vector3, habrá que poner <nombre de la clase>.<función>. Para usar la función Distance de la clase Vector3 quedaría «Vector3.Distance( )» escribiendo los argumentos necesarios para la función entre los paréntesis y devolviendo como resultado un dato tipo float. El tipo de dato que devuelve una función aparece justo antes del nombre de la función en su descripción (float en este caso). Si lo que aparece es Void significará que no devolverá ningún valor.

distance

Usaremos de ejemplo ahora la función Normalize de Vector3, que normalizará el vector que se le pase como argumento (ajusta el vector dado a uno igual pero con el módulo igual a la unidad). En las siguientes capturas veremos primero la página de Scripting Reference donde se explica el uso de dicha función. Segundo, nuestro código con una añadido que creará el vector ( 1, 2, 7 ) y lo normalizará para luego mostrarlo por consola mediante Debug.Log, y a continuación con la función Distance calculará la distancia de nuestro vector con respecto al vector ( 10, 20, 10 ). Nótese que a diferencia de la función Normalize, la función Distance devuelve un valor (de tipo float) por lo que habrá que asignarlo a una variable (jumpSpeed en este caso).

Normalize

codeVector3

En resumen, dentro de Unity Scripting Reference tendremos información de todas las clases, sus funciones y sus variables, que podemos emplear en nuestro código para un script de Unity.

Sentencias If en Unity

En este post aprenderemos acerca de las sentencias if y de las sentencias switch, parecido a if pero con múltiples opciones. Básicamente, una sentencia if realizará una acción si se cumple una condición previa.

Crearemos un nuevo script duplicando el ya existente mediante Ctrl+C y Ctrl+D. Le añadiremos «Ifs» en el nombre para diferenciarlos. Debemos acordarnos de modificar también el nombre en la parte del código «public class».

ifscript

Añadiremos este nuevo script arrastrándolo a nuestra esfera y eliminaremos el viejo abriendo el menú desplegable en la parte superior derecha y seleccionando la opción Remove Component.

addremovescript

Limpiaremos un poco el código de nuestro script antes de empezar de manera que quedará como se muestra en la siguiente imagen.

new

Debemos tener en cuenta que después de la sentencia if se ejecutará únicamente la primera acción que venga después hasta el primer punto y coma. Para ejecutar un número mayor de acciones dependiendo de si se cumple o no la condición de la sentencia if, tendremos que emplear llaves («{ }»). Estas llaves se colocarán al principio, justo después de la sentencia if, y al final de las acciones a realizar. Por ejemplo, añadamos un «Debug.Log(«hola»)» para comprobarlo. Al pulsar la barra espaciadora nuestra esfera saltará y nos saldrá el mensaje «hola».

llaves

Mediante el uso de estas llaves también podemos introducir sentencias if dentro de otras sentencias if. Por ejemplo, en la siguiente imagen el código mostrado mostrará un mensaje periódicamente mientras la variable «canJump» sea igual a true y, además, mostrará el mensaje «hola» si pulsamos la barra espaciadora que hace saltar a nuestra esfera.

algo

Los símbolos a utilizar en las condiciones a cumplir dentro de las sentencias if son: == (igual), != (no igual), < (menor que), > (mayor que), <= (menor o igual que), >= (mayor o igual que), && (y), || (o). De este modo si queremos escribir una sentencia if que haga algo si x+y = 10 ó x <= 5 quedaría algo como » if ( x + y == 10 || x <= 5 ) «. Podemos incluso usar paréntesis dentro de la condición. Añadamos al anterior ejemplo que sea necesario que dentro de la condición x <= 5 se deba cumplir además que y >= 0. Nos quedaría entonces » if ( x + y == 10 || ( x <= 5 && y >= 0 ) ) «. «&&» implica que ambas condiciones han de cumplirse, mientras que «||» indica que basta con que se cumpla una de las dos. Por último, significará lo mismo » canJump == false » que » !canJump «.

Si en caso de no cumplirse nuestra condición en la sentencia if deseamos que se realice alguna acción recurriremos a «else». En las sentencias de tipo if-else primero se comprobara si se cumple la condición de if. Si se cumple se realizarán las acciones dentro de la sentencia if, pero de no cumplirse dicha condición se realizarán las acciones dentro de la sentencia else. En nuestro ejemplo haremos que en caso de que canJump no sea true se muestre el mensaje «Necesitas cambiar canJump a true».

else

A continuación aprenderemos como funcionan las sentencias switch, que es básicamente un selector. Emplearemos un switch para seleccionar la velocidad de salto de nuestra esfera, para ello crearemos una variable (tipo int por ejemplo) que servirá de selector. La sentencia switch será «switch(variable)» , poniendo entre los paréntesis la variable según la cual se seleccionará una opción u otra dentro de switch. Crearemos la sentencia switch dentro de «void Start ( )» para que esta selección se realice únicamente al iniciar el juego. A continuación dentro de llaves incluiremos todos los casos que queramos que pueda seleccionar. En cada caso se empezará poniendo «case <valor de la variable>» poniendo en «valor de la variable» el valor para el cual realizaremos las siguientes acciones, puede ser cualquiera que deseemos. A continuación, sin necesidad de usar llaves, escribiremos todas las acciones que se deben realizar en este caso y se finalizará el caso con un «break;». Posteriormente se escribirá el siguiente caso del mismo modo. En nuestro ejemplo si seleccionamos un valor igual a 1 para la variable creada (int number) jumpSpeed adquirirá un valor igual a 1000 al inicio del juego (sin importar qué valor le hayamos puesto previamente), para number = 2 jumpSpeed será 2000 y para number = 10 jumpSpeed será 3000.

swtich

Ejecutar nuestro juego desde Kodi

En este post explicaremos cómo lanzar nuestro juego desde Kodi, un centro multimedia de entretenimiento multiplataforma bajo la licencia GNU/GPL. Podéis descargar Kodi en http://kodi.tv/download/ .

También necesitaremos un add-on para Kodi llamado Advanced Launcher que podréis descargar en https://github.com/Angelscry/plugin.program.advanced.launcher . Para instalarlo dentro de Kodi iremos a System->Settings.

settings

Seleccionamos Add-ons y dentro de Add-ons le damos a «Install from zip file».

add-ons

fromzip

Buscamos el directorio en donde tenemos el archivo .zip de Advanced Launcher y lo seleccionamos. Hecho esto esperamos un momento mientras lo instala.

install

Para ejecutar nuestro juego desde Kodi iremos a Programs y seleccionamos Advanced Launcher.

programs

Hacemos clic derecho en «Default» y elegimos «Create New Category» para crear una categoría donde guardaremos el launcher de nuestro juego.

newcategory

Escribimos el nombre que deseemos darle a esta categoría y le damos a «Done».

nombrecateg

Hacemos clic izquierdo en la nueva categoría y nos saltará una ventana de creador de launcher. Seleccionamos «Standalone launcher (normal executable)», buscamos el ejecutable de nuestro juego y lo seleccionamos.

launcher

A continuación nos saldrá una ventana donde podremos poner los argumentos de la aplicación que queramos añadirle al launcher, luego una ventana donde le daremos un nombre, otra para seleccionar la plataforma en la que se ejecutará (en este caso será Linux). Por último tendremos que elegir los directorios donde tendremos las imágenes Thumbnail y Fanart para nuestro juego (si no tenéis da igual qué directorios elegir).

Ya solo queda ejecutar nuestro launcher y Kodi hará una llamada al sistema para iniciar nuestro juego. Cuando lo cerremos volveremos a Kodi.

Para una mayor comodidad y fluidez usando Kodi y Advanced Launcher, sería recomendable poder cerrar nuestro juego dandole a un botón sin tener que recurrir a Alt+F4 y que se ejecutase en la resolución nativa a pantalla completa sin necesidad de que apareciese la pantalla de configuración de resolución de nuestro juego.

Para cerrar el juego existe «Application.Quit();». En este ejemplo lo añadiremos de manera rápida y sencilla dentro del script de nuestra bola «saltarina» (véasen posts Introducción al código del juego y Variables en Unity3D). Para ello añadiremos otra sentencia if que ejecute la orden de cerrar el juego si presionamos el botón «Cancel» al que está asignada la tecla Escape. El código de la sentecia if sería «if(Input.GetButtonDown(«Cancel»))» y a continuación ponemos la orden «Application.Quit();» para que cierre el juego si pulsamos Escape.

MONODEVELOP

Para saltar la pantalla de configuración del juego deberemos darle al botón «Player Settings…» en la ventana de Build Settings a la hora de exportar nuestro juego. Nos aparecerán las opciones de Player Settings en la pestaña de Inspector. En el apartado «Resolution and Presentation»->»Standalone Player Options» cambiaremos la opción «Display Resolution Dialog» de «Enabled» a «Hidden By Default». Con este cambio ya no nos aparecerá la ventana de configuración de resolución de pantalla antes de que se inicie nuestro juego. Se iniciará automáticamente en la resolución nativa y a pantalla completa.

DISPLAY CONFIG

Variables en Unity3D

En este post aprenderemos acerca de las variables en Unity3D. Las variables pueden ser de varios tipos que contienen distintos tipos de datos (números, caracteres, true/false, etc). Por ejemplo, una variable tipo float es un número real.

Todo lo que escribamos en nuestro script dentro de «void Start( )» se ejecutará una única vez cuando el objeto sea creado dentro del juego. Si el objeto está previamente creado dentro del juego, se ejecutará una vez se ejecute el juego. Podemos asignarle a una variable un valor inicial introducción una asignación a un valor determinado dentro de «void Start( )». Por ejemplo, podemos asignar poniendo a la variable «jumpSpeed» un valor de 200 poniendo «jumpSpeed = 200;» , por lo que al iniciar el objeto el valor de la variable será 200.

jS200

Ahora borraremos esto último y estableceremos que cuando hagamos clic izquierdo durante el juego la variable jumpSpeed adquiera un valor de 200. Clic izquierdo esta asignado a Fire1 en el InputManager y clic derecho a Fire2 (cómo acceder a InputManager en este post). Se puede añadir, quitar o modificar cualquier cosa en InputManager. En la siguiente imagen veremos el código que cambia el valor de «jumpSpeed» a 200 si pulsamos clic izquierdo en nuestro juego.

set200

Modificaremos a continución el código de manera que, en vez de igualar la variable a 200, incremente su valor en +100. También añadiremos que cuando pulsemos clic derecho se reduzca su valor en -100. Existen dos modos de hacer estas modificaciones. Uno sería «jumpSpeed = jumpSpeed + 100» y el otro «jumpSpeed += 100». Ambos realizan la misma acción, sumar 100 a la variable.

incr

Si el número que necesitamos almacenar es un número entero usaremos una variable tipo int (integer) para guardarlo. Antes de cambiar el tipo de nuestra variable float a int es necesario explicar que si deseamos igualar la variable a un número decimal debemos poner una f al final como se muestra en el siguiente ejemplo: «public float jumpSpeed = 10.5f;» . Cambiemos ahora nuestro tipo float por int. Ya no podremos introducir un número decimal como valor de nuestra variable jumpSpeed en Inspector. Si modificamos el incremento de clic derecho y lo cambiamos por 100,5 nos saldrá un error diciendo que no puede ser convertido a «int».

error int

Existe un tipo de variable llamada bool cuyo valor únicamente es true o false (verdadero o falso) que podría traducirse como 1 ó 0. Crearemos una variable public tipo bool llamada canJump que inicializaremos con un valor false ( 0 ). En Inspector será modificable mediante una casilla marcable. Esta variable servirá para activar o desactivar la posibilidad de saltar de nuestra esfera.  Para lograr esto variaremos nuestra segunda sentencia if de modo que asignaremos esta función a clic derecho, de modo que si pulsamos clic derecho cambiaremos el valor false por true.  Añadiremos una sentencia «if (canJump)» antes de la sentencia de Jump para realizar esta acción sólo si el valor de canJump es igual a true. De este modo si no hacemos clic derecho no podremos saltar.

canJump

Otra manera de lograr esto es añadiendo en la sentencia «if( Input.GetButtonDown («Jump»))» otra condición que debe cumplir además de la ya existente mediante el uso de «&&» ( Shift+7 ) , que indicará que debe cumplirse una condición y ( «&&» ) la otra. Quedará tal que así: «if( Input.GetButtonDown («Jump») && canJump )» , de modo que la esfera saltará cuando pulsemos la barra espaciadora y el valor de canJump sea true.

and

Se explicará ahora la variable tipo string. Este tipo de variable string almacena una cadena de caracteres. Para igualarla a algo habrá que poner entre comillas ( » ) el texto que queramos almacenar en ella. Por ejemplo, public string myString = «cualquier cosa» almacenará en la variable myString el texto «cualquier cosa» (sin las comillas). Aparecerá en Inspector y podremos modificarla debido a que es pública.

string

Por último, veremos como funciona Debug.Log ( ) . La función Log dentro de la clase Debug es una herramienta para el desarrollador que básicamente mostrará por pantalla lo que pongamos entre los paréntesis. Este mensaje aparecerá en la esquina inferior izquierda de Unity y también en la Console.

string2

Introducción al código del juego

En este post aprenderemos cómo crear nuestro primer script. Consistirá en una esfera que se desplazará arriba y abajo cuando pulsemos la barra espaciadora. Para ello empezaremos creando la esfera en Hierarchy con Create->3D Object->Sphere. Para distinguirla la llamaremos «Ball» y aumentaremos su tamaño. También debemos eliminar/desactivar nuestro controlador de primera persona y añadir una cámara (Create->Camera) que colocaremos enfocando a nuestra esfera. Para colocar la cámara de modo que enfoque lo mismo que  se está mostrando en la vista de nuestra Scene iremos a GameObject->Align With View con nuestra cámara seleccionada.

camera

A continuación añadiremos las físicas a nuestra esfera. Para ello, con la esfera seleccionada, en Inspector le daremos a Add Component->Physics->Rigidbody (como ya hemos visto en un post anterior). Por defecto este objeto colisionará sin problema con el resto, no necesitaremos buscar y marcar la opción Convex.

Ahora vayamos con la creación de nuestro script. Primeramente por temas de organización crearemos en Project una carpeta llamada Scripts donde guardaremos nuestros Scripts. Para crear un Script iremos a la carpeta Scripts de Project y seleccionaremos Create->C# Script . Hay otras opciones pero en este tutorial trabajaremos con scripts C# Script.

C script

Llamaremos «BallScript» a nuestro script. Podremos observar el contenido del script en Inspector. Lo abriremos haciendo doble click y se lanzara la aplicación MonoDevelop, que es independiente de Unity pero que se instalará con el mismo. Esta será la aplicación en donde escribiremos el código de nuestros scripts. Habrá varias cosas de las que haremos que probablemente no se entiendan ahora mismo, pero serán explicadas en post posteriores a este. Se verán simplemente para que resulten familiares en un futuro.

monodevelop

En el código inicial leeremos algo como «public class BallScript». En donde pone BallScript será donde aparecerá el nombre de nuestro script. Dentro de «void Start()» se escribirá el código de todo aquello que se ejecutará cuando el objeto sea creado dentro del juego. En nuestro ejemplo esta parte quedará vacía, incluso podríamos borrarlo si quisiésemos. Dentro de «void Update()» se escribirá el código de todo aquello que se ejecuta en cada frame (cada una de las imágenes que se suceden en la reproducción de un juego, película, etc) , aquello que se va a ejecutar una y otra vez a lo largo del videojuego. A continuación se mostrará la imagen final de nuestro código y se explicará debajo todo lo relacionado con ella.

script code

Una variable es un contenedor que guardará información y el tipo de variable indicará qué tipo de información almacenará. En este caso la variable «public float jumpSpeed = 10;» indicará que se puede acceder a ella desde cualquier sitio, incluyendo el Inspector, («public») la variable será de tipo «float»(un número que puede ser decimal), su nombre será «jumpSpeed» (Unity tendrá en cuenta mayúsculas y minúsculas) y su valor sera 10. Esta variable nos indicará cómo de alto llegará nuestra esfera. Debemos recordar que al final de cada línea de código deberemos finalizar con punto y coma («;»).

La sentencia «if()» realizará una acción si se cumple la condición incluída entre los paréntesis o si esta es igual a verdadero («true»).

Input.GetButtonDown(«jump») devuelve true cuando pulsamos el botón que indicamos en los paréntesis (en este caso el botón asignado a «jump»). Si queremos asignar una tecla de entrada en nuestro juego vamos a Edit->Project Settings->Input y nos aparecerá en Inspector el InputManager. Entre los menús desplegables buscamos Jump y veremos que ya está asignada a la barra espaciadora.

input

GetComponent<Rigidbody>().AddForce (0, jumpSpeed, 0) indica que al componente rigidbody se le realizará lo que indica la función AddForce(). La función AddForce añadirá una fuerza cuyo vector vendrá determinado por los valores entre los paréntesis distribuidos según la forma (x,y,z) respecto a las coordenadas. De modo que en este caso la fuerza únicamente será vertical (eje y) y vendrá dada en función de la variable jumpSpeed.

En general, si escribimos «GetComponent<nombre_de_componente>().función» accederemos a ese componente y realizaremos dicha función en él.

Para añadir el script a nuestra esfera simplemente tendremos que arrastrarlo a Add Component en Inspector con nuestra esfera seleccionada. También se puede añadir haciendo click en Add Component->Scripts y seleccionando el script de nuestro proyecto que deseemos añadir al objeto. El script será un componente más de nuestro objeto. Podremos modificar la variable jumpSpeed debido a que la hemos hecho pública. Y de hecho deberemos modificarla, ya que la esfera resultará demasiado pesada para ser desplazada aplicando solo una fuerza igual a 10. Una fuerza de 500 bastará, con lo que simplemente deberemos cambiar el parámetro de 10 a 500 en Inspector. Otra opción sería disminuir la masa del objeto en Rigidbody en Mass.

jumpSpeed

Por último, si tenemos algún error en nuestro código nos aparecerá en Unity un mensaje en la esquina inferior izquierda indicándonos dicho error. Si vamos a la pestaña Console tendremos una lista de todos los avisos y errores que Unity pudo detectar. Realicemos un pequeño ejemplo eliminando uno de los «;» de nuestro código. Si hacemos esto nos saldrá un mensaje de error en Unity que nos indicará el error y dónde se encuentra este error. Haciendo doble clic en el error abrirá MonoDevelop en el punto exacto en el que detectó el fallo.

error

Más sobre los objetos del juego

En este post vamos a aprender cómo agrupar objetos del juego, cómo guardar objetos y como reusar objetos.

Si queremos modificar varios objetos simultáneamente deberemos seleccionar aquellos objetos que deseemos modificar. Para ellos mientras mantenemos pulsado Shift seleccionaremos con clic todos los objetos que deseemos modificar en Scene. El mismo procedimiento se aplica con Hierarchy pero manteniendo pulsada la tecla Ctrl en vez de Shift, con Shift seleccionará todos los objetos desde el primer objeto que hayamos marcado hasta el último que marquemos. Una vez seleccionados los objetos podremos observar que modificando un parámetro en Inspector modificaremos ese parámetro en todos los objetos que lo compartan. Si alguno de los parámetro no tiene el mismo valor entre los objetos aparecerá en blanco con puntos suspensivos, no obstante si lo modificamos se aplicará y sobreescribirá en todos los objetos que tengan dicho parámetro.

multiple selection

Aprendamos ahora cómo agrupar objetos. Empecemos por crear una especie de estructura con cubos. Para ello crearemos un cubo, lo reproduciremos mediante Ctrl+C y Ctrl+D (visto anteriormente cómo hacerlo aquí), seleccionamos ambos cubos y repetimos el proceso, volvemos a seleccionar los cuatro cubos y repetimos una última vez colocándolos encima. Crearemos ahora un objeto vacío (no tendría necesariamente que ser este tipo de objeto), pero previamente seleccionaremos los cubos y pulsaremos F para fijar nuestro punto focal entre ellos y así crear nuestro objeto vacío en esa posición. A continuación seleccionaremos todos los cubos en Hierarchy y los arrastraremos encima del nombre de nuestro objeto vacío. Ahora tendremos un menú desplegable en nuestro objeto vacío en el que aparecerán los cubos. Estos cubos serán cada uno un «child» (hijo) del objeto vacío que será «parent» (padre). Si movemos, rotamos o escalamos el objeto padre, los objetos hijos se verán afectados del mismo modo. Si desmarcamos la casilla del objeto padre en Inspector todos los objetos serán desactivados. Del mismo modo si cambiamos el Layer nos dará la opción de cambiar también la de sus objetos hijos. Además, los datos de posición de los cubos vendrán dados con respecto a su objeto padre (posición local) y no con respecto al nivel en el que están (posición global).

parent child

Podremos también crear objetos hijos dentro de otros objetos hijos. Pongamos por ejemplo un escenario en el que tenemos un cubo, una cápsula y una esfera. Si metemos la esfera dentro de la cápsula en Hierarchy y luego el cubo dentro de la esfera, tendremos que el cubo es un objeto hijo de la esfera que a su vez es un objeto hijo de la cápsula. Si por ejemplo desplazamos la cápsula, se moverán también el cubo y la esfera. Sin embargo, si solo movemos la esfera también se moverá el cubo por ser un objeto hijo de la esfera.

capsulespherecube

Expliquemos ahora qué es un prefab. Un prefab es un objeto prefabricado (como su nombre indica). Estará localizado en nuestra carpeta de Assets en Project. Si tenemos varios objetos de este tipo en nuestro juego y queremos modificarlos, para ello modificaremos el prefab y estos cambios afectarán a todos los objetos de este tipo. Procederemos ahora con la creación de un prefab. Para ello crearemos un objeto, un cilindro por ejemplo. Lo personalizaremos añadiéndole un material y una luz para hacerlo único. Por motivos de organización crearemos una carpeta para nuestros prefabs en Assets. Entramos en la carpeta y creamos un prefab (Create->Prefab). Para convertir nuestro cilindro personalizado en un prefab tan solo debemos arrastrarlo de Hierarchy a Project y soltarlo encima del prefab que acabamos de crear.

prefab creation

Si seleccionamos el prefab veremos sus características en Inspector. Para añadir un objeto de este tipo bastará con arrastrar el prefab y soltarlo en Hierarchy o en Scene. El nuevo objeto tendrá el mismo nombre que el prefab del que procede. Estos objetos pueden ser modificados de manera individual e independiente, pero si modificamos el prefab afectará a todos los objetos creados a partir de él. En estos objetos habrá una opción en Inspector con el nombre Prefab que dispondrá de tres botones: Select, Revert, Apply. Select seleccionará el prefab en la pestaña Project. Si modificamos uno de los objetos y le damos a Revert, retomará los valores del prefab. Si por el contrario le damos a Apply, estos cambios se aplicarán al prefab y, por tanto, a todos los objetos de este prefab. Cuando modificamos algún parámetro de uno de estos objetos las letras de este parámetro se pondrán en negrita. Si le damos a Apply, estos cambios se aplicarán al prefab y ya no estarán en negrita.

prefabs

Componentes en Unity

En este post hablaremos de los componentes en Unity. Los componentes son las partes que componen los objetos del juego. Cada uno de los apartados que aparecen de un objeto en Inspector se trata de un componente.

components

Crearemos ahora un objeto vacío. Para ello iremos al a pestaña GameObject->Create Empty (acceso directo Ctrl+Shift+N). El único componente que tendrá este objeto será Transform (datos de posición, rotación y escala). Una opción útil para los objetos no explicada anteriormente es Tag, en Inspector, que permitirá etiquetar al objeto para así indicar la funcionalidad del mismo para una mejor organización en nuestro proyecto. Podemos elegir entre las etiquetas ya existentes o crear una nueva.

empty object

Otra opción muy interesante es Layer. En Inspector podremos asignar el objeto a una de las capas existentes o crear una nueva. A continuación en la opción general de Layer podemos escoger que capas deseamos visualizar, de modo que, si tenemos un objeto o serie de objetos asignados a una capa y desactivamos la misma, esos objetos no serán visibles en nuestra Scene.

layer

Una opción con un efecto parecido es marcar/desmarcar la casilla del objeto al lado de su nombre en Inspector. Esto hará desaparecer el objeto de nuestra Scene y también de nuestro juego, manteniéndose en Hierarchy con el nombre en gris. Se podría decir que esta opción desactiva el objeto dentro de nuestro proyecto. Para recuperar el objeto simplemente debemos marcar de nuevo la casilla. Algunos componentes pueden ser desactivados del mismo modo marcando su casilla correspondiente.

desactived object

De vuelta a nuestro objeto vacío, podemos añadir nuevos componentes desde Inspector dándole a Add Component o en el menú desplegable de la pestaña Component.

add component

Añadiremos un componente Mesh->Mesh Filter, que será lo que indicará la forma 3D de nuestro objeto. Solo dispondra de una opción llamada Mesh que será donde seleccionaremos que Mesh tendremos. Si tenemos un archivo Mesh en nuestro proyecto podemos arrastralo y ya tendremos una Mesh en el objeto. Si no tenemos ninguno haremos click en el botón que tiene al lado el recuadro que pone «None (Mesh)», esto nos mostrará en una ventana todos los Meshes de que disponemos.

mesh filter

Esto solo será un indicador de que Mesh le dará forma al objeto. Para dar esa forma al objeto debemos añadir ahora el componente Mesh->Mesh Renderer en Add Component. Nos aparecerá en color rosa el objeto para indicarnos que debemos añadirle un material.

Mesh renderer

Para añadir el material debemos arrastrar desde Project el material de nuestro proyecto que deseemos añadir a nuestro objeto como vimos en un post anterior. Por ejemplo, arrastrando a Add Component en Inspector. Recordad poner en Shader la opción Legacy Shaders->Diffuse.

material component

En estos momentos nuestro objeto aún no es un cuerpo sólido. Si previsualizamos el juego podremos ver que somos capaces de atravesar este objeto sin problemas. Para que este objeto sea un cuerpo sólido añadiremos el componente Physics->Mesh Collider en Add Component. En general, se asignará automáticamente a nuestro Mesh Filter. Con este componente el objeto se comportará como un cuerpo sólido, no pudiendo así ser atravesado en la previsualización. Podemos añadir más componentes para hacer que nuestro objeto haga lo que sea. Por ejemplo, hacer que el objeto emita una luz con Rendering->Light y configurarlo según lo que queramos. En nuestro ejemplo le hemos añadido al cubo rojo una luz rosa a modo de linterna.

Mesh collider

En Add Component->Physics->Rigidbody añadiremos un complemento para dotar de físicas al objeto. Esto hará, por ejemplo, que simule tener gravedad, por lo que no flotara en el aire. Para que pueda colisionar con otros objetos habrá que marcar la opción convex en Mesh Collider.

gravity

Hay multitud de componentes que puedes añadir por lo que es recomendable experimentar para ver que uso pueden tener cada uno de ellos.