shooter en unity 3d

36
Tutorial de Gameplay: Shooter 2D Por jonay Rosales Gonzalez “Don Barks Gheist” Este documento está bajo licencia Creative Commons:

description

modelo de shooter en unity 3d

Transcript of shooter en unity 3d

Page 1: shooter en unity 3d

Tutorial de Gameplay: Shooter 2DPor jonay Rosales Gonzalez “Don Barks Gheist”

Este documento está bajo licencia Creative Commons:

Page 2: shooter en unity 3d

INTRODUCCÓN:Bienvenidos al que va a ser el primero de muchos tutoriales sobre diseño y desarrollo de gameplay

de video juegos. En este he empezado con algo sencillo y que a muchos les gustarían hacer: Un shooter 2D.

Tras mirar referencias, creo que la mas famosa es la del juego pang. Así que primero empezaremos por el diseño del gameplay y después empezaremos a crearlo.

Page 3: shooter en unity 3d

Diseñando nuestro Shooter:Antes de empezar a hacer el juego, siempre tenemos que hacer un documento para tener las cosas claras sobre lo que hay que hacer. ESTO ES LO PRIMERO QUE HA DE HACERSE

ANTES DE EMPEZAR UN PROYECTO.

Historia:Para ser sinceros, desconozco la historia de Pang. Un juego casi siempre tendrá un pequeño trasfondo histórico. Pero siempre hay excepciones que confirmen la regla y, si mal no recuerdo, Pang es uno de éstos.

Objetivo:el objetivo del juego es “disparar” las bolas hasta hacerlas desaparecer del escenario. He remarc ado en negrita disparar porque, en muchas ocasiones, los objetivos de un juego definen su género.

Personajes:Nuestro personaje es un cazador de bolas. Dependiendo de muchos factores, nuestro “héroe” también puede determinar varios parámetros de nuestro juego: la ambientación, elementos interactivos, enemigos y, SOBRE TODO Y ANTE TODO, la jugabilidad. El personaje que encarnará el jugador debe ser acorde con el mundo que hemos imaginado para él (hay excepciones que confirman la regla, así que ojo).

Enemigos:Las bolas antes mencionadas, serán nuestro enemigo en este juego, saltarán y rebotarán entre si para hacerlas más impredecibles (un añadido respecto al juego original). si nos toca, perderemos una oportunidad.

Gameplay:Cada juego se juega de una manera única, por muy parecido que sea a otro juego (o por muy remake que sea). Aquí expondremos los elementos que tengan que ver con la jugabilidad. Entre ellos los Items, Power Ups, niveles, nº de vidas, continuaciones, puntuación y un largo etcétera de elementos de juego.

Control:¿Cómo y de que manera interactuará el personaje con el entorno? Cuando hablamos de entorno, es el Mundo en su totalidad que hemos creado para que el personaje campe a sus anchas y logre sus objetivos. En nuestro juego, nuestro héroe se moverá de izquierda a derecha y disparar, posiblemente tenga que subir escaleras (Cosa que no voy a hacer yo, pero sí vosotros si queréis).

Page 4: shooter en unity 3d

Escenarios/Niveles/Fases y demás nombres:¿Cuantos niveles tendrá que pasar nuestro personaje para terminar con su objetivo?, esto es “cosa vostra”. Pero deberían ser suficientes para satisfacer al jugador; ni muy pocos, ni muchos. Cada nivel, por regla de ORO, debe ser mas desafiante que el anterior.

Diseño Artístico:Será un remake, y en el juego de referencia me pasé casi por el forro el diseño artístico (mas bien porque es un proyecto de “entrenamiento”). Pero vosotros NI DE COÑA lo hagáis. La gente come por los ojos, y si ve un juego cuya presentación visual no le llame la atención, pasará de él. En esta generación de la industria se valorá muchísimo el aspecto visual (y la historia) que en anteriores. Así que tened mucho cuidado con este aspecto.

Page 5: shooter en unity 3d

¡Manos a la obra (Primeros pasos)!

Tras terminar vuestro documento de diseño, es hora de abrir Unity 3D y crear un nuevo proyecto, llamadlo como os de la real gana. Ahora cogemos la cámara y, en su propiedad “transform”, la ponemos a X=0,Y=0, Z=-10. En sus propiedades de cámara, marcamos la de Ortographic.

NOTA: La cámara ortográfica no detecta distancia pese a que estemos haciendo una escena 3D, por consecuencia, todos los objetos tendrán el mismo tamaño sin importar la lejanía. Aprovechad esto para poner capas de imágenes o planos en vuestros escenarios o para hacer menús.

NOTA: para hacer efectos de Zoom en una cámara Ortográfica, simplemente bajaremos el Ortographic size(por defecto está a 100).

Ahora cread un Light Source, para ello vais a GameObject>>Create>>Directional Light (haced esto si el material que usáis le afecta la iluminación) y dejáis las propiedades tal cual están.

NOTA: hay 3 tipos de luces en Unity 3D, la directional Light emula la dirección de los rayos del sol. El SpotLight emularía un foco de luz y el Point Light emularía iluminación ambiental, como la provocada por el fuego o una explosión.

Page 6: shooter en unity 3d

Creando un menú principal simple:

Una vez hecho el paso de la página anterior (lo deberéis de hacer cada vez que hagáis un nuevo nivel), empecemos con hacer el menú principal.

NOTA: Yo lo voy a hacer a mi manera, os recomiendo que vosotros lo hagáis a la vuestra teniendo en cuenta mi manera como base.

Recursos necesarios:

• Imágen del menú principal

• Fuente de letra que mas os de rabia

1. Creamos un material, en el selector de shaders seleccionamos Particle>>AlphaBlend, ponemos nuestra textura de menú principal y en las propiedades de color ponemos el color Alpha al máximo.

2. En el menú de herramientas, vamos a GameObject>>Create Other>>Plane, con esto crearemos un plano. En la propiedad transform del plano, pondremos como coordenadas XYZ=>(0,0,0) para ponerlo en nuestro “punto de vista”, luego en la propiedad rotation pondremos XYZ=>(90,270,90) (siempre y cuando se os vea la imagen al revés cuando insertéis el material que creaste para la textura, de lo contrario, insertad las coordenadas de rotación siguientes: XYZ=>(270,0,0)). En el componente Mesh Renderer, tenemos una propiedad llamada materials, en esta seleccione el material del menú principal.

3. Id a GameObject>>Create Other>>GUIText para crear una zona de texto en pantalla, copiad, pegad y modificad sus valores y al final el resultado será algo así:

Page 7: shooter en unity 3d

4. Por último: Haremos un Script que nos lleve al siguiente nivel cuando pulsemos espacio o el botón B del mando de XBOX 360, haciendo que el GUIText que pone “pulsa Espacio o botón B para empezar” parpadee.

4.1. Primero, crearemos un script con variables y funciones globales en Jscript: A este le llamaremos “Globals”, para ello, vamos a Assets>>Create>>Javascript para crear un documento de javascript, lo nombraremos Globals y hacemos doble click en él para editarlo.

4.2. En el documento escribiremos ESTO:

Globals.jsstatic var littleBallsexploded : int = 0; //bolas pequeñas que has explotadostatic var Ballstowin :int = 0; //bolas pequeñas necesarias para ganarstatic var Lives :int = 3; //vidas restantesstatic var Levels : int =0; //Nivel en el que te encuentrasstatic var Hook : boolean = false; //PowerUp Garfiostatic var doubleArpoon : boolean = false; //Power Up doble arpónstatic var Bulletlimit :int = 0; //Límite de disparosstatic var Score = 0; //Puntuación total

NOTA: Las variables globales serán nuestro gran aliado para operaciones y scripts que necesiten un valor que no cambie tras volver a cargar una escena.

4.3. Ahora crearemos un Script de la misma manera que en el paso 4.1, pero esta vez le llamaremos StartGame, y escribiremos en él ESTO:

StartGame.jsvar texto: GUIText; //el objeto texto que parpadearáprivate var Fadetexttime : float = 0; //contador de tiempo//Esta función nos permitirá setear varias variables al valor por defecto que deseemos cuando empiece la escenafunction Start() {

Globals.Lives = 3;Globals.Score = 0;Globals.Bulletlimit = 0;

}function Update () { //Esta función se repetirá cada frameif(Input.GetButtonDown("Jump")){

Application.LoadLevel(Globals.Levels + 1); //Si pulsamos el botón especificado como Jump(en mi caso será espacio o Boton B del mando de XBOX360) el juego cargará el próximo nivel y seremos transportados a éste.}if(Input.GetKeyDown(KeyCode.C)){

Application.OpenURL("http://elcazadordeleyendas.blogspot.com/"); //Si pulsamos el botón especificado (aquí, la tecla “C” del teclado), se abrirá el explorador por defecto y nos llevará a la página web especificada)}if(Input.GetButtonDown("Exit") || Input.GetKeyDown(KeyCode.Escape)){

Application.Quit(); //Si pulsamos la tecla indicada saldremos del juego

Page 8: shooter en unity 3d

}

if(Fadetexttime < 1){

Fadetexttime = Fadetexttime + 1 * Time.deltaTime; //mientras que nuestro contador tenga un valor inferior a 1, su valor sera sumado por el tiempo que ha pasado después del último frame

}else{

texto.text = "";Fadetexttime = Fadetexttime + 1 * Time.deltaTime; //de lo contrario, no mostrará texto

algunoif(Fadetexttime >= 2){

texto.text = "Pulsa espacio o el boton B para jugar";Fadetexttime = 0; //y si el tiempo es superior a 2, mostrará el texto otra vez y

reiniciará el contador}

}}

4.4. Ahora seleccionaremos el plano que hicimos antes y le añadiremos nuestro script StartGame yendo a Componet>>Scripts>>StartGame y en la variable texto de StartGame, seleccionaremos el GUIText que parpadeará.

5. Ahora lo único que nos queda será añadir el nivel al ejecutable, para ello iremos a File>>Build Seetings, nos aparecerá una ventana con una lista de niveles (vacía en este caso), simplemente pincharemos en el Add Current debajo de la lista para añadir la escena que contendrá nuestro menú principal.

CONSEJOS: jugad e investigad un poco sobre las GUIs, descubriréis muchos trucos para darle una curiosa presentación a vuestros juegos gracias a ello.

Page 9: shooter en unity 3d

Preparando el Gameplay:

PASOS GENERALES:Estos pasos se han de hacer independientemente de los objetos que hagamos, son pasos que haremos en la mayoría de los casos y estarán indicados cuando sea necesario:

A) Crear un material para el modelo 3D e implementarlo en él: 1. En la barra de herramientas, vamos a Assets>>Create>>Material para crear un material

en la carpeta del proyecto.

NOTA: Intentad ser ordenados y organizad los archivos que creéis o importéis en diferentes carpetas, cuanto más organizado y clasificado tengáis la carpeta de proyecto, mejor.

2. Pinchad en el material creado, metéis el nombre que queráis asignarle y, en el inspector, seleccionáis el shader, propiedades y textura/s que veáis convenientes.

B) Importar Texturas u otros elementos al proyecto(manera 1): 1. Id a Assets>>Import New Asset y elegid los archivos que queráis.

C) Importar Texturas u otros elementos al proyecto(manera 2): 1. Arrastrad los archivos que quieras importar desde el explorador de windows hasta la

carpeta de proyecto.

D) Importar Texturas u otros elementos al proyecto(manera 3): 1. Ejecuta el paquete .Unity que queréis descomprimir teniendo el programa activo

mientras estás en un proyecto.

2. Enseguida en unity te mostrará los archivos que se van a importar del paquete (puedes seleccionar y deseleccionar los que quieras), tras eso, dale a aceptar para empezar la importación.

E) Crear un objeto Prefab: 1. pinchad Assets>>Create>>Prefab, en la carpeta de proyecto se creará un prefab

“vacio”, ponedle el nombre que sea conveniente a la situacion.

2. Arrastrad el el objeto de la ventana de Hierarchy que queráis hacia el prefab vacío.

3. (opcional)Es aconsejable que borréis de la escena el objeto que habéis creado como prefab (siempre y cuando sea un objeto instanciable o que aparezca en cierto momento).

F) Añadir Script: 1. pinchad en Components>>Scripts y busca el script que quieras añadir al

prefab/gameobject

Page 10: shooter en unity 3d

1. El escenario: 1.1. Base de escenario: Esta clase de juegos tienen una base predefinida, tenemos la

base, las paredes y el techo, que limitan tanto el movimiento del personaje como el de las bolas.

1.2. Background: El pang original usaba un background dependiendo del país(escenario) en el que estabas.

1.3. Bloques: Son plataformas por donde rebotarán las bolas, las hay de dos tipos, bloques irrompibles y rompibles. Los rompibles añaden puntos a nuestro marcador y tienen la posibilidad de soltar items.

2. Los Items: Tenemos varios items que pueden soltar las bolas al dividirse o desaparecer o los bloques rompibles:

2.1. Doble Arpón: El doble arpón permitirá hacer dos disparos seguidos al jugador, a parte de que nos dará 1000 puntos.

NOTA: la mayoría de los bugs de disparo que os dará el juego mientras lo probáis(y seguís este tutorial al pie de letra) derivarán sobre el doble arpón.

2.2. Garfio: Este arma se pegará a las paredes durante 3 segundos, no podremos disparar otro hasta que desaparezca el disparo.

2.3. Vida Extra: Añade una oportunidad más o, si tienes 3 vidas, añade 10.000 puntos al marcador.

3. Los Enemigos: 3.1. Bola: Nuestro enemigo, se rige por la física y puede colisionar con las demás

bolas, haciéndolo medianamente imprevisible

3.2. Bola metálica: Esta bola, a diferencia que la bola normal, no rebota, pero va ligeramente más rápida que la normal.

ACTIVIDAD DE REFUERZO/INVESTIGACIÓN: Intenta crear más tipos de enemigos, eso te ayudará a diversificar la jugabilidad.

4. Debries, proyectiles y Efectos de partículas: Estos son los denominados Instanced Objects, objetos que aparecen (y se cargan en memoria) cuando lo indicamos. Los debries son los denominados “restos” de un objeto al “morir” o ser “destruido”. Los proyectiles, no hace falta explicarlos, la verdad... los efectos de partículas son simplemente efectos especiales.

4.1. Fracción de Bola: Cuando una bola es impactada por un arpón, ésta se divide en dos más pequeñas, es conveniente hacer 3 tipos de divisiones (La bola más grande del Pang original se dividía 3 veces antes de soltar las bolas más pequeñas), cuando el tamaño de la bola es muy pequeña, está desaparecerá.

4.2. Arpón: El personaje dispara arpones y, dependiendo del item cogido, la textura del arpón cambiará. También dependiendo del Item obtenido podemos disparar de una a dos arpones a la vez. Si un arpón colisiona con una bola o el escenario, al desaparecer nos brindará la oportunidad de disparar otra vez.

Page 11: shooter en unity 3d

4.3. Partícula de explosión: Cuando el arpón colisiona con la bola se produce una explosión.

5. Personaje: No hay que olvidarse de nuestro personaje principal...

6. GUI: La interfaz gráfica del usuario, yo no hice prefab de ella, pero quizás sería una buena idea hacerlo.

6.1. Contador de Puntos: poco hay que decir de él, reflejará el valor de la variable global Score del script Globals.js

6.2. Mensaje principal: Game Over, Stage Clear o Pause son mensajes principales que aparecerán en determinado momento.

6.3. Mensaje consejo: Se muestra junto con el mensaje principal, siempre nos indicará la tecla qué hay que tocar para continuar.

6.4. Contador de vidas: Poco hay que decir sobre él...

CONSEJO: puede que la GUI sea importante para que el jugador vea su estado y estadísticas. pero la GUI, cuanto más minimalista y clara sea,mejor. Nunca hay que saturar al jugador con elementos GUI.

Page 12: shooter en unity 3d

Creando los Prefabs(I): Los objetos físicosAntes de nada, haz los pasos comentados en la sección “¡Manos A la Obra(Primeros pasos)!”,

pero esta vez creando una escena nueva (y guardando la anterior).Para mayor comodidad, pondremos la pantalla de la escena y la de vista de juego en paralelo

para poder visualizar los límites del escenario y ajustar medidas.

NOTA: Crearemos el escenario concorde a la resolución por default de nuestro juego, que será 1024x768.

EL ESCENARIO:1. Creamos 4 cubos en GameObject>>Create Other>>Cube y en Hierarchy, les ponemos los

nombres: Top, Left, Right y Base y movemos su transform a XYZ(0,0,0).2. A Left y Right modificamos su Scale a XYZ(10,1,1) y los posicionamos de tal manera de

que en la vista de juego se vea como en la imagen del resultado.

3. A Top y Base modificamos su Scale a XYZ(11.45,0.5,1) y lo posicionamos de tal manera de que en la vista de juego se vea como en la imágen del resultado

4. Creamos un Plano en GameObject>>Create Other>>Plane, movemos su transform a XYZ(0,0,1.5) y lo rotamos a XYZ(90,270,90). Éste será nuestro Background.

5. Ahora modificaremos su Scale de tal manera que se vea como la Imagen del resultado.

6. Hacer el Paso General (B,C o D)7. Hacer el Paso General (A)8. Ahora crearemos un nuevo GameObject en GameObject>>Create Empty, lo

posicionaremos en transform XYZ(0,0,0) y lo llamaremos “Scenario”.

9. En Hierarchy, emparentamos todos los objetos que hemos creado hasta ahora seleccionando éstos y arrastrándolos hasta el GameObject Scenario.

10. Hacer el Paso General(E) con el GameObjet Scenario.

Page 13: shooter en unity 3d

RESULTADO:

Page 14: shooter en unity 3d

LOS BLOQUES:

Bloque Normal:

1. Creamos 1 cubo en GameObject>>Create Other>>Cube y en Hierarchy, le ponemos como nombre Brick, movemos su transform a XYZ(0,0,0) y modificamos su Scale a XYZ(1,0.2,1).

2. Hacer el Paso General (A)3. Hacer el Paso General (B,C o D)4. Hacer el Paso General(E)

Bloque Rompible:

1. Hacer los mismos pasos que con el bloque Normal

NOTA: Como ves en la imagen, el bloque rompible tiene 2 capas de textura, debes usar el shader Decal para el material. Más adelante crearemos el script para que la segunda capa se mueva.

Page 15: shooter en unity 3d

ITEMS:

A todos los he creado “físicamente” de la misma manera, así que con explicar la creación de uno es suficiente.

1. Creamos 1 cubo en GameObject>>Create Other>>Cube y en Hierarchy, le ponemos como nombre el item que represente, movemos su transform a XYZ(0,0,0), su Scale a XYZ(0.25,0.25,0.25) y su rotation dependiendo si da problemas...

2. Seleccionamos el objeto y Añadimos un RigidBody en Components>>Physics>>RigidBody y activamos la propiedad Freeze Rotation.

3. Seleccionamos el objeto y Añadimos un Configurable Joint en Components>>Physics>>Configurable Joint y seleccionamos “Locked“en las propiedades Zmotion, AngularXMotion e AngularYMotion.

4. Hacer el Paso General (A)5. Hacer el Paso General (B,C o D)6. Hacer el Paso General(E, obligatorio el paso 3)

Page 16: shooter en unity 3d

LOS ENEMIGOS:

Bola:

1. Creamos una esfera en GameObject>>Create Other>>Sphere y en Hierarchy, ponemos como nombre Ball, movemos su transform a XYZ(0,0,0) y su Scale a XYZ(1.5,1.5,1.5).

2. Seleccionamos el objeto y Añadimos un RigidBody en Components>>Physics>>RigidBody.

3. Seleccionamos el objeto y Añadimos un Configurable Joint en Components>>Physics>>Configurable Joint y seleccionamos “Locked” en las propiedades Zmotion, AngularXMotion e AngularYMotion.

4. Hacer el Paso General (A)5. Hacer el Paso General (B,C o D)6. Hacer el Paso General(E)

Bola metálica:

1. Creamos una esfera en GameObject>>Create Other>>Sphere y en Hierarchy, ponemos como nombre Heavy Ball, movemos su transform a XYZ(0,0,0) y su Scale a XYZ(0.25,0.25,0.25).

2. Repetir los pasos del 2 al 6 del anterior objeto

Page 17: shooter en unity 3d

DEBRIES, PROYECTILES Y EFECTOS DE PARTÍCULAS:

Fracción de Bola:

1. Crear objeto vacio en GameObject>>Create Empty, le llamaremos “Ball Fraction 1” y lo posicionamos en la position XYZ(0,0,0).

2. añadimos dos prefabs de bola a BallFraction1 y le bajamos el Scale a la mitad e intentamos juntarlas desde la position XYZ(0,0,0), separadlos dos décimas X(0,2) entre si para que no colisionen entre si cuando aparezcan.

3. Hacer Paso General (E, obligatorio paso 3).4. repetir los pasos de 1 a 3 con la mitad de Scale que el anterior.

Arpón:

1. Creamos un Plano en GameObject>>Create Other>>Plane, movemos su transform a XYZ(0,0,0) y lo rotamos a XYZ(90,270,90) y quitamos el componente mesh collider de él. Ésta será la punta nuestro arpón.

2. Añadimos un line renderer en Components>>Miscellaneous>>Line Renderer, en la propiedad positions, en size, añadimos 2 y los configuramos de esta manera: Element 0: XYZ(0,-100,0) ; Element 1: XYZ(0,-0.5,0). Y en parameters configuramos Start Width y End Width a 0.1.

3. Hacer Paso General (A).4. Crear objeto vacío en GameObject>>Create Empty y le llamaremos “Arpoon”.

5. añadimos Rigidbody y un Raycast Collider en Components>>Physics desactivamos la gravedad en el RigidBody y el Lenght del Raycast Collider a 10

Page 18: shooter en unity 3d

6. añadimos el objeto plane a Arpoon.

7. Hacer Paso General (B,C o D)8. Hacer Paso General (E, obligatorio paso 3)

Partículas:

1. Creamos un emisor de partículas en GameObject>>Create Other>>Particle System.2. En el componente Ellipsoid Particle emmiter, cambiamos min y max Emmision a 10,

min/max Energy a 1, Min/Max Size a 0.5, y activamos One Shot.

3. En el componente Particle Animator, cambiamos el Color animation [0-4] a los colores que querais, el damping lo cambiais a 0.1 y activais el Autodestruct.

4. Hacer Paso General(E, obligatorio el paso 3).

Page 19: shooter en unity 3d

EL PERSONAJE:

1. Creamos un Plano en GameObject>>Create Other>>Plane, movemos su position a XYZ(0,0,0) y lo rotamos a XYZ(90,270,90) quitamos el componente mesh collider de él. Ésta será la representación visual de nuestro personaje.

2. Creamos un objeto vacío en GameObject>>Create Empty, lo llamamos “Character” y lo posicionamos en XYZ(0,0,0).

3. Añadimos a este nuevo objeto un Capsule Collider y un RigidBody, éstos componentes están en Components>>Physics.

4. Activamos freeze rotation en RigidBody y Capsule Collider lo modificamos de esta manera: Radius = 0.3, Height = 2, Center=XYZ(-0.15,-0.35,0)

5. Añadimos el objeto plane a Character.

6. Hacer Paso General(A)7. Hacer Paso General(B,C o D)8. Hacer Paso General(E)

Page 20: shooter en unity 3d

GUI:Con lo aprendido en el apartado “Creando un menú principal simple”, la manera de hacer la

apariencia física de la GUI no cambia, así que, con lo que habeis aprendido en aquel apartado, intentad que os quede un resultado similar al de la imágen (La GUI in Game tiene

GUI Textures, pero su manejo es similar al GUI Text).

Resultado:

Después de terminarlo, hay dos maneras de reutilizarlo: la primera es fácil, pero tediosa y la otra compleja, pero rápida. La facil y tediosa es hacer lo mismo en cada nivel, y la compleja pero rápida es poner toda la GUI en un Prefab. Esta segunda podria ser compleja mas bien

por el tema del funcionamiento de los scripts, pero tampoco es que sea tan complicado.

Page 21: shooter en unity 3d

Creando los Prefabs (II): Hora de programar.

Este apartado tiene como índice el mismo apartado que en “Creando los Prefabs(I)”, por lo que, si algún objeto necesita un script, éste se expondrá de la misma forma y orden que en el apartado anterior. Recordad que para añadir nuestro script al prefab, debemos seleccionar el

prefab desde el directorio de archivos, no desde Hierarchy, porque podríais perder la conexión con el prefab. Recordad también que, si modificamos desde prefab, modificaremos

todos los objetos que tengan enlace a ese prefab. La manera de incluir Script en nuestro prefab está especificada en el Paso General (F).

Escenario:En este prefab meteremos todos los scripts que tengan que ver con las reglas del juego;

condiciones para ganar, condiciones para perder, etc.

Pause Game:

PauseGame.jsvar texto: GUIText; //El GuiText que mostrará la palabra “pausa” cuando es pulsado el botón de pausavar paused: boolean = false; //Indica si el juego está pausado o no(podría ser una variable privada)function Update () {if(Input.GetButtonDown("Pause")&& paused == false){

texto.text = "Pausa";Time.timeScale = 0;paused = true; //Si se pulsa el botón de pausa y la variable paused es falsa, la

velocidad del juego se pausará y pause sera equivalente a verdadero}

else if(Input.GetButtonDown("Pause")&& paused == true){texto.text = "";Time.timeScale = 1;paused = false; //Si se pulsa el botón de pausa y la variable paused es verdadera, la

velocidad del juego se reanudará y pause sera equivalente a falso}if(Input.GetButtonDown("Exit") || Input.GetKeyDown(KeyCode.Backspace)){

Globals.Levels = 0;Application.LoadLevel(Globals.Levels); //En caso de que pulsemos el botón

indicado, volveremos al menú principal.}

}

Page 22: shooter en unity 3d

Score:

Score.jsvar texto:GUIText; //El texto que mostrará la puntuaciónfunction Update () {texto.text = Globals.Score.ToString(); //Actualiza e imprime el valor que tiene la variable global Score}

Show Lives:

ShowLives.jsvar livetexture : Texture; //La textura que corresponde a las vidas restantesvar lives : GUITexture[] = [null,null,null]; //el número de vidasvar texto : GUIText; //El texto que indica fin de juegovar texto2 : GUIText; //El texto que indica las instruccionesfunction Update () {//Dependiendo de cuantas vidas nos quede, se mostrarán u ocultaran las texturas(color.a = transparencia)if(Globals.Lives == 3){

lives[2].color.a = 128;lives[1].color.a = 128;lives[0].color.a = 128;

}if(Globals.Lives == 2){

lives[2].color.a = 0;lives[1].color.a = 128;lives[0].color.a = 128;

}if(Globals.Lives == 1){

lives[2].color.a = 0;lives[1].color.a = 0;lives[0].color.a = 128;

}if(Globals.Lives == 0){ //Cuando el numero de vidas llega a 0, se mostrará la pantalla de Game Over y si pulsamos el botón asignado, nos trasladaremos al menú principal.

lives[2].color.a = 0;lives[1].color.a = 0;lives[0].color.a = 0;texto.text = "Game Over";texto2.text = "Pulsa espacio para volver al menu principal";if(Input.GetButtonDown("Jump")){

Globals.Levels = 0;Application.LoadLevel(Globals.Levels);

}}}

Page 23: shooter en unity 3d

Win:

Win.jsvar littleballstowin : int; //Las bolas pequeñas necesarias para ganarvar texto1 : GUIText; //El texto que aparece cuando terminas el nivelvar texto2 : GUIText; //las instrucciones para avanzar al siguiente nivelvar level : int; //El nivel en el que estásfunction Start(){ //Reiniciar las variables globales de manera de que no se generen bugsGlobals.littleBallsexploded = 0;Globals.Ballstowin = littleballstowin;Globals.Levels = level;Globals.Hook = false;Globals.doubleArpoon = false;Globals.Bulletlimit = 0;}function Update () {

if(Globals.littleBallsexploded >= Globals.Ballstowin){ //Si el numero de bolas que hemos explotado coincide con el numero de bolas explotadas necesarias para ganar, se mostraran los texto y avanzaremos de nivel cuando pulsemos el botón indicado.

texto1.text = "Stage Clear";texto2.text = "Pulsa espacio o el boton B para continuar";if(Input.GetButtonDown("Jump")){Application.LoadLevel(Globals.Levels + 1);

if(!Application.isLoadingLevel){//En caso de no haber más niveles, se volverá al menú principal.Globals.Levels = 0;Application.LoadLevel(Globals.Levels);}

}}

}

Page 24: shooter en unity 3d

Bloque Rompible:Animate Fake Reflection:

AnimateFakeReflection.jsvar scrollSpeed = 0.5; //Velocidad de movimiento del reflejofunction Update () {//la segunda textura se mueve hacia arribavar offset = Time.time * scrollSpeed;renderer.material.SetTextureOffset ("_DecalTex", Vector2(0,offset));}

Destroy Object 2:

DestroyObject2.jsvar item : GameObject[]; //los objetos que “dropea” al ser destruidofunction OnCollisionEnter (colision : Collision) { //si el objeto arpón colisiona con el objeto, destruye el objeto y aumenta en 500 la puntuación total. Se genera un número aleatorio, y si es igual al asignado en las condiciones, dropeará un objeto u otro. Podéis modificarlo a medida que añadáis mas items.for (var contact : ContactPoint in colision.contacts)

if(contact.otherCollider.name == "Arpoon(Clone)"){var rot2 = Quaternion.FromToRotation(Vector3.up, Vector3.up);var pos2 = contact.point;

Globals.Score += 500;Destroy(gameObject);var dropitem : int= Random.Range(0, 20);

if(dropitem == 5 || dropitem == 10){

var Itemdropped : GameObject = Instantiate(item[0],pos2,rot2);}if(dropitem == 1 || dropitem == 2){

var Itemdropped1 : GameObject = Instantiate(item[1],pos2,rot2);}if(dropitem == 9 || dropitem == 19){

var Itemdropped2 : GameObject = Instantiate(item[2],pos2,rot2);}

}}

Page 25: shooter en unity 3d

Doble Arpón(Item):ItemDArpoon:

ItemDArpoon.js

function OnCollisionEnter(collision : Collision){ //Si el objeto colisiona con el personaje, éste obtendrá 500 puntos y activara la variable global doubleArpoon.

for (var contact : ContactPoint in collision.contacts)

if(contact.otherCollider.name == "Character"){

Globals.Score += 500;Globals.doubleArpoon = true;Globals.Hook = false;Destroy(gameObject);

}}function Update(){ //Si el objeto no es recogido en un cierto tiempo, éste desaparecerá

Destroy(gameObject,3);}

NOTA: Es posible que haya que hacer unos arreglillos al script, ya que si colisiona con otro objeto y el personaje colisiona con el item, puntua doble. Lo mismo pasa con los demás Items.

Garfio(Item):ItemHook:

ItemHook.js//Ídem a ItemDArpoon.js, pero activando el item de garfiofunction OnCollisionEnter(collision : Collision){

for (var contact : ContactPoint in collision.contacts)if(contact.otherCollider.name == "Character"){

Globals.Hook = true;Globals.doubleArpoon = false;Globals.Score += 500;Destroy(gameObject);

}}function Update(){//Si el objeto no es recogido en un cierto tiempo, éste desaparecerá

Destroy(gameObject,3);}

Page 26: shooter en unity 3d

Vida Extra(Item):ItemExtraLife:

ItemExtraLife.js//Si el objeto colisiona con personaje, si su numero de vidas es 3, solamente recibe 5000 puntos, de lo contrario, obtiene una vida.function OnCollisionEnter(collision : Collision){

for (var contact : ContactPoint in collision.contacts)

if(contact.otherCollider.name == "Character"){

if(Globals.Lives > 2)Globals.Score += 5000;

elseGlobals.Lives += 1;print(Globals.Lives + "quedan");

Destroy(gameObject);}

}function Update(){//Si el objeto no es recogido en un cierto tiempo, éste desaparecerá

Destroy(gameObject,3);}

Page 27: shooter en unity 3d

Bola(Enemigo):

BallMoveStart:

BallMoveStart.jsvar vel:float = 2; //La velocidad de desplazamiento lateral de la bolavar bump:float = 10; //La altura de bote de la bolavar particle : GameObject; //El sistema de partículas que se emitirá cuando el arpón toque la bolavar item : GameObject[]; //los items que dropeará la bola.var Divisionsection: GameObject; //La división que aparecerá cuando la bola es destruidavar contactname : String = "Ball"; //El nombre de la bola en caso de contactar con algo, llamad siempre al prefab de bola por este nombre.var Arpoonname :String = "Arpoon(Clone)"; //El nombre del proyectil.var leftorright : boolean = true; //¿Va hacia la izquierda o hacia la derecha?private var dropitem : int;function Start(){ //dependiendo del valor de leftorright, la bola empezara a desplazarse hacia la izquierda o hacia la derechaif(leftorright == true){ rigidbody.velocity.x = vel;}else{ rigidbody.velocity.x = -vel;}}function OnCollisionEnter(collision : Collision) {

for (var contact : ContactPoint in collision.contacts) {//si contacta por los laterales, el objeto irá por el lado contrarioif(contact.normal.x < -0.1){ rigidbody.velocity.x = vel; leftorright = false;}

if(contact.normal.x > 0.1){ rigidbody.velocity.x = -vel; leftorright = true;}//si contacta por debajo, la bola rebotaráif(contact.normal.y > 0.5){ rigidbody.velocity.y = bump;}

if(contact.otherCollider.name == Arpoonname){//En caso de que el arpón colisione con la bola, podremos disparar otra vez mas,a parte de generar una variable aleatoria que, si su valor coincide con lo estipulado en las instrucciones if, la bola dropeará un objeto.

Page 28: shooter en unity 3d

Globals.Bulletlimit -= 1;if(Globals.Bulletlimit < 0){

Globals.Bulletlimit = 0;}var rot2 = Quaternion.FromToRotation(Vector3.up, Vector3.up);var pos2 = contact.point;var Sparks : GameObject= Instantiate(particle, pos2, rot2);dropitem = Random.Range(0, 20);if(dropitem == 5){

var Itemdropped : GameObject = Instantiate(item[0],pos2,rot2);}if(dropitem == 1){

var Itemdropped1 : GameObject = Instantiate(item[1],pos2,rot2);}//En caso de que la variable de division esté vacía, se sumará al numero de bolas pequeñas destruidas y se obsequiará con una puntuación de 1600 al jugadorif(Divisionsection == null){Globals.littleBallsexploded += 1;Globals.Score += 1600;Destroy(gameObject);}else{//de lo contrario, la bola será reemplazada por la división correspondiente. var rot = Quaternion.FromToRotation(Vector3.up, Vector3.up);var pos = transform.position; var Broken : GameObject = Instantiate(Divisionsection, pos,rot);//dependiendo del nombre de la division, el jugador sumará una puntuación u otra if(Divisionsection.name == "BallFraction1") { Globals.Score += 200; } if(Divisionsection.name == "BallFraction2") { Globals.Score += 400; } if(Divisionsection.name == "BallFraction3") { Globals.Score += 800; } Destroy(gameObject);} }if(contact.otherCollider.name == "Character"){//si la bola contacta con el personaje, el jugador perderá una vida y el nivel se reinicaráGlobals.Lives -= 1;Globals.Bulletlimit = 0; Application.LoadLevel(Globals.Levels);}}

Page 29: shooter en unity 3d

}function OnCollisionStay(collision: Collision){//Esta función soluciona ciertos bugs, ya que a veces la bola no botaba, lo que hace esta función es ver en cada frame si el objeto colisiona con otro, y de ser así, hara lo que esté especificado en la función. for (var contact : ContactPoint in collision.contacts) {

if(contact.normal.x < -0.1){

rigidbody.velocity.x = vel;leftorright = false;

}

if(contact.normal.x > 0.1){

rigidbody.velocity.x = -vel;leftorright = true;

}if(contact.normal.y > 0.5){

rigidbody.velocity.y = bump;}}}function Update(){

if(leftorright == true){

rigidbody.velocity.x = vel;}else{

rigidbody.velocity.x = -vel;}

}

Page 30: shooter en unity 3d

Bola Metálica(Enemigo):

HeavyBallMoveStart:

HeavyBallMoveStart.js//Idem a BallMoveStart salvo que no hay Fracciones ni tampoco la bola saltavar vel:float = 2;var particle : GameObject;var item : GameObject[];var contactname : String = "Sphere";var Arpoonname :String = "Arpoon(Clone)";var leftorright : boolean = true;private var dropitem : int;

function Start(){if(leftorright == true){

rigidbody.velocity.x = vel;}else{

rigidbody.velocity.x = -vel;}}

function OnCollisionEnter(collision : Collision) {

for (var contact : ContactPoint in collision.contacts) {// Visualize the contact pointif(contact.normal.x < -0.1){

rigidbody.velocity.x = vel;leftorright = false;

}

if(contact.normal.x > 0.1){

rigidbody.velocity.x = -vel;leftorright = true;

}if(contact.otherCollider.name == Arpoonname){Globals.Bulletlimit -= 1;if(Globals.Bulletlimit < 0){

Globals.Bulletlimit = 0;}var rot2 = Quaternion.FromToRotation(Vector3.up, Vector3.up);var pos2 = contact.point;var Sparks : GameObject= Instantiate(particle, pos2, rot2);dropitem = Random.Range(0, 20);

Page 31: shooter en unity 3d

if(dropitem == 5){

var Itemdropped : GameObject = Instantiate(item[0],pos2,rot2);}if(dropitem == 1){

var Itemdropped1 : GameObject = Instantiate(item[1],pos2,rot2);}if(dropitem == 19){

var Itemdropped2 : GameObject = Instantiate(item[2],pos2,rot2);}

Globals.littleBallsexploded += 1;Globals.Score += 1600;Destroy(gameObject);}if(contact.otherCollider.name == "Character"){Globals.Lives -= 1;Globals.Bulletlimit = 0;

print("vida perdida: " + Globals.Lives +" restantes");Application.LoadLevel(Globals.Levels);

}}}function OnCollisionStay(collision: Collision){for (var contact : ContactPoint in collision.contacts) {// Visualize the contact pointif(contact.normal.x < -0.1){

rigidbody.velocity.x = vel;leftorright = false;

}

if(contact.normal.x > 0.1){

rigidbody.velocity.x = -vel;leftorright = true;

}}}function Update(){

if(leftorright == true){

rigidbody.velocity.x = vel;}else{

rigidbody.velocity.x = -vel;}}

Page 32: shooter en unity 3d

Arpón(Proyectil):

Destroy Object:

NOTA: Este script se añade al objeto padre(Arpoon)

DestroyObject.jsfunction OnCollisionEnter (colision : Collision) {//Si está activado el power up de garfio y colisiona con cualquier cosa que no sea una bola, éste tardará 3 segundos en desaparecer o hasta colisionar con alguna bola.if(Globals.Hook == true){

for (var contact : ContactPoint in colision.contacts) {if(contact.otherCollider.name == "Ball"){Destroy(gameObject);}}rigidbody.isKinematic = true;yield WaitForSeconds(3);Globals.Bulletlimit -=1;Destroy(gameObject);

}else{//De lo contrario, el arpón desaparecerá cuando colisione con cualquier cosa que no sea una bolafor (var contact : ContactPoint in colision.contacts)

if(contact.otherCollider.name != "Ball")Globals.Bulletlimit -=1;if(Globals.Bulletlimit < 0){

Globals.Bulletlimit = 0;}

Destroy(gameObject);}}

Change Texture:

NOTA: Este script se añade al objeto hijo(Arpoon>>Plane)

ChangeTexture.jsvar Arpoontexture: Texture; //Textura que reemplazará el garfio function Update() {//Si el power up del garfio está activado, la textura cambiará a la que esté asignada

if(Globals.Hook == true)renderer.material.mainTexture = Arpoontexture;

}

Page 33: shooter en unity 3d

Personaje:

MoveCharacter:

NOTA: se ha de poner en el objeto padre Character

MoveCharacter.jsvar speed = 6; //Velocidad en la que se moverá el personajevar Ball : GameObject; //el objeto bolaprivate var moveDirection = Vector3.zero;function Update () {

// Move the controllerrigidbody.velocity.x = Input.GetAxis("Horizontal") * speed;//el personaje se moverá

dependiendo del control de eje horizontal (izquierda/derecha)if(Globals.Lives == 0){

Destroy(this.gameObject); //Si el contador de vidas llega a 0, el personaje desaparece.

}}

Arpoon:

NOTA: se ha de poner en el objeto padre Character

Arpoon.jsvar bulletPrefab : Rigidbody; //El proyectil en sivar basescenario: GameObject; //la base del escenariovar chara: GameObject; //el personajevar bulletspeed : int; //velocidad de proyectilprivate var Bullet : Rigidbody;//var shotclip :AudioClip;, usalo cuando quieras reproducir un sonido al disparar... aunque necesitas un audio source para ellofunction Update () {

if(Globals.Bulletlimit == 0 && Globals.doubleArpoon == false){

Shoot();}else if(Globals.Bulletlimit < 2 && Globals.doubleArpoon == true){

Shoot();}

}

function Shoot(){//cuando pulses el botón de disparo, se generará una instancia/copia del prefab de proyectil y se moverá hacia arriba a la velocidad establecida. A parte, ignorará las colisiones de personaje y la base del escenario

if(Input.GetButtonDown("Fire1")){

Page 34: shooter en unity 3d

Bullet = Instantiate(bulletPrefab,transform.position-Vector3(0,0.5,0),transform.rotation);

Bullet.velocity = transform.TransformDirection(Vector3(0,bulletspeed,0));Physics.IgnoreCollision(Bullet.collider,transform.root.collider,true);Physics.IgnoreCollision(Bullet.collider,basescenario.collider);Physics.IgnoreCollision(Bullet.collider,chara.collider);//audio.PlayOneShot(shotclip);Globals.Bulletlimit += 1;

}}

TileAnimation:

NOTA: se ha de poner en el objeto hijo Character>>Plane, a parte, ésta no es la manera “adecuada” de usar este script

TileAnimation.js//vars for the whole sheetvar colCount : int = 4;var rowCount : int = 4;

//vars for animationvar rowNumber : int = 0; //Zero Indexedvar colNumber : int = 0; //Zero Indexedvar totalCells : int = 4;var fps : int = 10;var offset : Vector2; //Maybe this should be a private var

//Updatefunction Update () {if(Input.GetAxis("Horizontal") > 0){

SetSpriteAnimation(colCount,rowCount,0,colNumber,totalCells,fps); }if(Input.GetAxis("Horizontal") < 0){SetSpriteAnimation(colCount,rowCount,2,colNumber,totalCells,fps); }if(Input.GetAxis("Horizontal") == 0){SetSpriteAnimation(colCount,rowCount,1,colNumber,1,fps); }}

//SetSpriteAnimationfunction SetSpriteAnimation(colCount : int,rowCount : int,rowNumber : int,colNumber : int,totalCells : int,fps : int){

// Calculate index var index : int = Time.time * fps;

Page 35: shooter en unity 3d

// Repeat when exhausting all cells index = index % totalCells; // Size of every cell var size = Vector2 (1.0 / colCount, 1.0 / rowCount); // split into horizontal and vertical index var uIndex = index % colCount; var vIndex = index / colCount; // build offset // v coordinate is the bottom of the image in opengl so we need to invert. offset = Vector2 ((uIndex+colNumber) * size.x, (1.0 - size.y) - (vIndex+rowNumber) * size.y); renderer.material.SetTextureOffset ("_MainTex", offset); renderer.material.SetTextureScale ("_MainTex", size);}

Sobre como usar este script, indicaré en donde he conseguido la versión original:http://www.unifycommunity.com/wiki/index.php?title=Animating_Tiled_texture_-_Extended

Page 36: shooter en unity 3d

Paso final: Debugging y creación de niveles

Una vez hecho los prefabs, es la hora de ver su funcionamiento. Este paso lo haréis vosotros solitos puesto que testear nuestra creación en busca de fallos y corregirlos es tarea de cada uno. Unity 3D tiene un pedazo de manual bien completito y una gigantesca comunidad de

cerca de 10.000 desarrolladores con los que compartir experiencias y ayudarse entre sí. Simplemente buscad en la web oficial o en los manuales que vienen en el programa y vuestras

dudas se resolverán mas pronto de lo que creíais.Cuando veáis que vuestro juego este mas o menos libre de errores(ningún programa es

perfecto, y siempre hay maneras de disimularlos). Podéis lanzaros ya a la creación del nivel.Si habéis seguido los pasos de esta guía, el escenario principal debería estar hecho ya. por lo tanto, solo queda posicionar en nuestro nivel las bolas y las plataformas (En el Pang original hay escaleras también, podéis intentar hacerlas). Intentad que la dificultad de cada nivel sea gradual y que cada X niveles haya alguno “de relax”, usease, nivel relativamente facilito para que el jugador se relaje para luego seguir adelante. A veces no es bueno exponer todo el rato al

jugador con una dificultad totalmente ascendente.

Y con estos consejos, me despido y nos vemos en el próximo tutorial de Gameplay: Arcade FPS (“on rails” First Person Shooter).