Está en la página 1de 36

Tutorial de Gameplay: Shooter 2D

Por jonay Rosales Gonzalez Don Barks Gheist


Este documento est bajo licencia Creative Commons:

INTRODUCCN:
Bienvenidos al que va a ser el primero de muchos tutoriales sobre diseo y desarrollo de gameplay
de video juegos. En este he empezado con algo sencillo y que a muchos les gustaran hacer: Un
shooter 2D.
Tras mirar referencias, creo que la mas famosa es la del juego pang. As que primero empezaremos
por el diseo del gameplay y despus empezaremos a crearlo.

Diseando 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 pequeo
trasfondo histrico. 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 gnero.

Personajes:
Nuestro personaje es un cazador de bolas. Dependiendo de muchos factores, nuestro hroe
tambin puede determinar varios parmetros de nuestro juego: la ambientacin, 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, sern nuestro enemigo en este juego, saltarn y rebotarn entre si para
hacerlas ms impredecibles (un aadido 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, puntuacin y un largo etctera de
elementos de juego.

Control:
Cmo 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 hroe se mover de izquierda a derecha y disparar,
posiblemente tenga que subir escaleras (Cosa que no voy a hacer yo, pero s vosotros si queris).

Escenarios/Niveles/Fases y dems nombres:


Cuantos niveles tendr que pasar nuestro personaje para terminar con su objetivo?, esto es cosa
vostra. Pero deberan ser suficientes para satisfacer al jugador; ni muy pocos, ni muchos. Cada
nivel, por regla de ORO, debe ser mas desafiante que el anterior.

Diseo Artstico:
Ser un remake, y en el juego de referencia me pas casi por el forro el diseo artstico (mas bien
porque es un proyecto de entrenamiento). Pero vosotros NI DE COA lo hagis. La gente come
por los ojos, y si ve un juego cuya presentacin visual no le llame la atencin, pasar de l. En esta
generacin de la industria se valor muchsimo el aspecto visual (y la historia) que en anteriores.
As que tened mucho cuidado con este aspecto.

Manos a la obra (Primeros pasos)!


Tras terminar vuestro documento de diseo, es hora de abrir Unity 3D y crear un nuevo proyecto,
llamadlo como os de la real gana. Ahora cogemos la cmara y, en su propiedad transform, la
ponemos a X=0,Y=0, Z=-10. En sus propiedades de cmara, marcamos la de Ortographic.
NOTA: La cmara ortogrfica no detecta distancia pese a que estemos haciendo una escena 3D,
por consecuencia, todos los objetos tendrn el mismo tamao sin importar la lejana. Aprovechad
esto para poner capas de imgenes o planos en vuestros escenarios o para hacer mens.
NOTA: para hacer efectos de Zoom en una cmara Ortogrfica, 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 usis le afecta la iluminacin) y dejis las propiedades tal cual estn.
NOTA: hay 3 tipos de luces en Unity 3D, la directional Light emula la direccin de los rayos del
sol. El SpotLight emulara un foco de luz y el Point Light emulara iluminacin ambiental, como
la provocada por el fuego o una explosin.

Creando un men principal simple:


Una vez hecho el paso de la pgina anterior (lo deberis de hacer cada vez que hagis un nuevo
nivel), empecemos con hacer el men principal.
NOTA: Yo lo voy a hacer a mi manera, os recomiendo que vosotros lo hagis a la vuestra teniendo
en cuenta mi manera como base.
Recursos necesarios:

Imgen 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 mximo.
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 revs cuando
insertis el material que creaste para la textura, de lo contrario, insertad las coordenadas de
rotacin 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:

4. Por ltimo: Haremos un Script que nos lleve al siguiente nivel cuando pulsemos espacio o el
botn B del mando de XBOX 360, haciendo que el GUIText que pone pulsa Espacio o
botn 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.js
static var littleBallsexploded : int = 0; //bolas pequeas que has explotado
static var Ballstowin :int = 0; //bolas pequeas necesarias para ganar
static var Lives :int = 3; //vidas restantes
static var Levels : int =0; //Nivel en el que te encuentras
static var Hook : boolean = false; //PowerUp Garfio
static var doubleArpoon : boolean = false; //Power Up doble arpn
static var Bulletlimit :int = 0; //Lmite de disparos
static var Score = 0; //Puntuacin total
NOTA: Las variables globales sern 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.js
var texto: GUIText; //el objeto texto que parpadear
private var Fadetexttime : float = 0; //contador de tiempo
//Esta funcin nos permitir setear varias variables al valor por defecto que deseemos cuando
empiece la escena
function Start()
{
Globals.Lives = 3;
Globals.Score = 0;
Globals.Bulletlimit = 0;
}
function Update () { //Esta funcin se repetir cada frame
if(Input.GetButtonDown("Jump"))
{
Application.LoadLevel(Globals.Levels + 1); //Si pulsamos el botn especificado como
Jump(en mi caso ser espacio o Boton B del mando de XBOX360) el juego cargar el prximo
nivel y seremos transportados a ste.
}
if(Input.GetKeyDown(KeyCode.C))
{
Application.OpenURL("http://elcazadordeleyendas.blogspot.com/"); //Si pulsamos el botn
especificado (aqu, la tecla C del teclado), se abrir el explorador por defecto y nos llevar a la
pgina web especificada)
}
if(Input.GetButtonDown("Exit") || Input.GetKeyDown(KeyCode.Escape))
{
Application.Quit(); //Si pulsamos la tecla indicada saldremos del juego

}
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 despus del ltimo frame
}
else
{
texto.text = "";
Fadetexttime = Fadetexttime + 1 * Time.deltaTime; //de lo contrario, no mostrar texto
alguno
if(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 aadiremos 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 aadir el nivel al ejecutable, para ello iremos a
File>>Build Seetings, nos aparecer una ventana con una lista de niveles (vaca en este
caso), simplemente pincharemos en el Add Current debajo de la lista para aadir la escena
que contendr nuestro men principal.
CONSEJOS: jugad e investigad un poco sobre las GUIs, descubriris muchos trucos para darle una
curiosa presentacin a vuestros juegos gracias a ello.

Preparando el Gameplay:
PASOS GENERALES:
Estos pasos se han de hacer independientemente de los objetos que hagamos, son pasos que
haremos en la mayora de los casos y estarn 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 creis o importis en diferentes
carpetas, cuanto ms organizado y clasificado tengis la carpeta de proyecto, mejor.
2. Pinchad en el material creado, metis el nombre que queris asignarle y, en el inspector,
seleccionis el shader, propiedades y textura/s que veis convenientes.
B) Importar Texturas u otros elementos al proyecto(manera 1):
1. Id a Assets>>Import New Asset y elegid los archivos que queris.
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 queris descomprimir teniendo el programa activo
mientras ests 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
importacin.
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 queris hacia el prefab vaco.
3. (opcional)Es aconsejable que borris de la escena el objeto que habis creado como
prefab (siempre y cuando sea un objeto instanciable o que aparezca en cierto momento).
F) Aadir Script:
1. pinchad en Components>>Scripts y busca el script que quieras aadir al
prefab/gameobject

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
pas(escenario) en el que estabas.
1.3.
Bloques: Son plataformas por donde rebotarn las bolas, las hay de dos tipos,
bloques irrompibles y rompibles. Los rompibles aaden 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 Arpn: El doble arpn permitir hacer dos disparos seguidos al jugador, a
parte de que nos dar 1000 puntos.
NOTA: la mayora de los bugs de disparo que os dar el juego mientras lo probis(y segus este
tutorial al pie de letra) derivarn sobre el doble arpn.
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: Aade una oportunidad ms o, si tienes 3 vidas, aade 10.000
puntos al marcador.

3. Los Enemigos:
3.1.
Bola: Nuestro enemigo, se rige por la fsica y puede colisionar con las dems
bolas, hacindolo medianamente imprevisible
3.2.
Bola metlica: Esta bola, a diferencia que la bola normal, no rebota, pero va
ligeramente ms rpida que la normal.
ACTIVIDAD DE REFUERZO/INVESTIGACIN: Intenta crear ms tipos de enemigos, eso te
ayudar a diversificar la jugabilidad.

4. Debries, proyectiles y Efectos de partculas: 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 partculas son simplemente efectos
especiales.

4.1.

Fraccin de Bola: Cuando una bola es impactada por un arpn, sta se divide en
dos ms pequeas, es conveniente hacer 3 tipos de divisiones (La bola ms grande del
Pang original se divida 3 veces antes de soltar las bolas ms pequeas), cuando el
tamao de la bola es muy pequea, est desaparecer.

4.2.

Arpn: El personaje dispara arpones y, dependiendo del item cogido, la textura


del arpn cambiar. Tambin dependiendo del Item obtenido podemos disparar de una a
dos arpones a la vez. Si un arpn colisiona con una bola o el escenario, al desaparecer
nos brindar la oportunidad de disparar otra vez.

4.3.

Partcula de explosin: Cuando el arpn colisiona con la bola se produce una


explosin.

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


6. GUI: La interfaz grfica del usuario, yo no hice prefab de ella, pero quizs sera 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 aparecern 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 estadsticas. pero
la GUI, cuanto ms minimalista y clara sea,mejor. Nunca hay que saturar al jugador con elementos
GUI.

Creando los Prefabs(I): Los objetos fsicos


Antes de nada, haz los pasos comentados en la seccin 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 lmites del escenario y ajustar medidas.
NOTA: Crearemos el escenario concorde a la resolucin 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 imgen 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 arrastrndolos hasta el GameObject Scenario.
10. Hacer el Paso General(E) con el GameObjet Scenario.

RESULTADO:

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. Ms adelante crearemos el script para que la segunda capa se mueva.

ITEMS:
A todos los he creado fsicamente de la misma manera, as que con explicar la creacin 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 Aadimos un RigidBody en
Components>>Physics>>RigidBody y activamos la propiedad Freeze Rotation.
3. Seleccionamos el objeto y Aadimos un Configurable Joint en
Components>>Physics>>Configurable Joint y seleccionamos Lockeden 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)

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 Aadimos un RigidBody en
Components>>Physics>>RigidBody.
3. Seleccionamos el objeto y Aadimos 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 metlica:

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

DEBRIES, PROYECTILES Y EFECTOS DE PARTCULAS:


Fraccin 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. aadimos 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 dcimas 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.
Arpn:

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 arpn.
2. Aadimos un line renderer en Components>>Miscellaneous>>Line Renderer, en la
propiedad positions, en size, aadimos 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 vaco en GameObject>>Create Empty y le llamaremos Arpoon.
5. aadimos Rigidbody y un Raycast Collider en Components>>Physics desactivamos la
gravedad en el RigidBody y el Lenght del Raycast Collider a 10

6. aadimos el objeto plane a Arpoon.


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

1. Creamos un emisor de partculas 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).

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 representacin visual de nuestro personaje.
2. Creamos un objeto vaco en GameObject>>Create Empty, lo llamamos Character y lo
posicionamos en XYZ(0,0,0).
3. Aadimos a este nuevo objeto un Capsule Collider y un RigidBody, stos componentes
estn 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. Aadimos el objeto plane a Character.
6. Hacer Paso General(A)
7. Hacer Paso General(B,C o D)
8. Hacer Paso General(E)

GUI:
Con lo aprendido en el apartado Creando un men principal simple, la manera de hacer la
apariencia fsica 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 imgen (La GUI in Game tiene
GUI Textures, pero su manejo es similar al GUI Text).
Resultado:

Despus de terminarlo, hay dos maneras de reutilizarlo: la primera es fcil, pero tediosa y la
otra compleja, pero rpida. La facil y tediosa es hacer lo mismo en cada nivel, y la compleja
pero rpida 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.

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 algn objeto necesita un script, ste se expondr de la misma forma y orden que en el
apartado anterior. Recordad que para aadir nuestro script al prefab, debemos seleccionar el
prefab desde el directorio de archivos, no desde Hierarchy, porque podrais perder la
conexin con el prefab. Recordad tambin 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.js
var texto: GUIText; //El GuiText que mostrar la palabra pausa cuando es pulsado el botn de
pausa
var paused: boolean = false; //Indica si el juego est pausado o no(podra ser una variable
privada)
function Update () {
if(Input.GetButtonDown("Pause")&& paused == false){
texto.text = "Pausa";
Time.timeScale = 0;
paused = true; //Si se pulsa el botn 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 botn 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 botn
indicado, volveremos al men principal.
}
}

Score:
Score.js
var texto:GUIText; //El texto que mostrar la puntuacin
function Update () {
texto.text = Globals.Score.ToString(); //Actualiza e imprime el valor que tiene la variable global
Score
}
Show Lives:
ShowLives.js
var livetexture : Texture; //La textura que corresponde a las vidas restantes
var lives : GUITexture[] = [null,null,null]; //el nmero de vidas
var texto : GUIText; //El texto que indica fin de juego
var texto2 : GUIText; //El texto que indica las instrucciones
function Update () {//Dependiendo de cuantas vidas nos quede, se mostrarn 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
botn 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);
}
}
}

Win:
Win.js
var littleballstowin : int; //Las bolas pequeas necesarias para ganar
var texto1 : GUIText; //El texto que aparece cuando terminas el nivel
var texto2 : GUIText; //las instrucciones para avanzar al siguiente nivel
var level : int; //El nivel en el que ests
function Start()
{ //Reiniciar las variables globales de manera de que no se generen bugs
Globals.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 botn
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 ms niveles, se volver al men principal.
Globals.Levels = 0;
Application.LoadLevel(Globals.Levels);}

}
}
}

Bloque Rompible:
Animate Fake Reflection:
AnimateFakeReflection.js
var scrollSpeed = 0.5; //Velocidad de movimiento del reflejo
function Update () {//la segunda textura se mueve hacia arriba
var offset = Time.time * scrollSpeed;
renderer.material.SetTextureOffset ("_DecalTex", Vector2(0,offset));
}
Destroy Object 2:
DestroyObject2.js
var item : GameObject[]; //los objetos que dropea al ser destruido
function OnCollisionEnter (colision : Collision) { //si el objeto arpn colisiona con el objeto,
destruye el objeto y aumenta en 500 la puntuacin total. Se genera un nmero aleatorio, y si es
igual al asignado en las condiciones, dropear un objeto u otro. Podis modificarlo a medida que
aadis 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);
}
}
}

Doble Arpn(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 dems Items.

Garfio(Item):
ItemHook:
ItemHook.js
//dem a ItemDArpoon.js, pero activando el item de garfio
function 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);

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;
else
Globals.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);
}

Bola(Enemigo):
BallMoveStart:
BallMoveStart.js
var vel:float = 2; //La velocidad de desplazamiento lateral de la bola
var bump:float = 10; //La altura de bote de la bola
var particle : GameObject; //El sistema de partculas que se emitir cuando el arpn toque la bola
var item : GameObject[]; //los items que dropear la bola.
var Divisionsection: GameObject; //La divisin que aparecer cuando la bola es destruida
var 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 derecha
if(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 contrario
if(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 arpn 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.

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 vaca, se sumar al numero de bolas pequeas
destruidas y se obsequiar con una puntuacin de 1600 al jugador
if(Divisionsection == null)
{Globals.littleBallsexploded += 1;
Globals.Score += 1600;
Destroy(gameObject);}
else
{//de lo contrario, la bola ser reemplazada por la divisin 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 puntuacin 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);
}
}

}
function OnCollisionStay(collision: Collision)
{//Esta funcin soluciona ciertos bugs, ya que a veces la bola no botaba, lo que hace esta funcin
es ver en cada frame si el objeto colisiona con otro, y de ser as, hara lo que est especificado en la
funcin.
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;
}
}

Bola Metlica(Enemigo):
HeavyBallMoveStart:
HeavyBallMoveStart.js
//Idem a BallMoveStart salvo que no hay Fracciones ni tampoco la bola salta
var 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 point
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.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);

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 point
if(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;
}
}

Arpn(Proyectil):
Destroy Object:
NOTA: Este script se aade al objeto padre(Arpoon)
DestroyObject.js
function 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 arpn desaparecer cuando colisione con cualquier cosa que no sea una bola
for (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 aade al objeto hijo(Arpoon>>Plane)
ChangeTexture.js
var 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;
}

Personaje:
MoveCharacter:
NOTA: se ha de poner en el objeto padre Character
MoveCharacter.js
var speed = 6; //Velocidad en la que se mover el personaje
var Ball : GameObject; //el objeto bola
private var moveDirection = Vector3.zero;
function Update () {
// Move the controller
rigidbody.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.js
var bulletPrefab : Rigidbody; //El proyectil en si
var basescenario: GameObject; //la base del escenario
var chara: GameObject; //el personaje
var bulletspeed : int; //velocidad de proyectil
private var Bullet : Rigidbody;
//var shotclip :AudioClip;, usalo cuando quieras reproducir un sonido al disparar... aunque
necesitas un audio source para ello
function Update () {
if(Globals.Bulletlimit == 0 && Globals.doubleArpoon == false)
{
Shoot();
}
else if(Globals.Bulletlimit < 2 && Globals.doubleArpoon == true)
{
Shoot();
}
}
function Shoot()
{//cuando pulses el botn 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")){

Bullet = Instantiate(bulletPrefab,transform.positionVector3(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 sheet
var colCount : int = 4;
var rowCount : int = 4;
//vars for animation
var rowNumber : int = 0; //Zero Indexed
var colNumber : int = 0; //Zero Indexed
var totalCells : int = 4;
var fps : int = 10;
var offset : Vector2; //Maybe this should be a private var
//Update
function 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);
}
}
//SetSpriteAnimation
function SetSpriteAnimation(colCount : int,rowCount : int,rowNumber : int,colNumber :
int,totalCells : int,fps : int){
// Calculate index
var index : int = Time.time * fps;

// 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 versin original:
http://www.unifycommunity.com/wiki/index.php?title=Animating_Tiled_texture_-_Extended

Paso final: Debugging y creacin de niveles


Una vez hecho los prefabs, es la hora de ver su funcionamiento. Este paso lo haris vosotros
solitos puesto que testear nuestra creacin 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 resolvern mas pronto de lo que creais.
Cuando veis que vuestro juego este mas o menos libre de errores(ningn programa es
perfecto, y siempre hay maneras de disimularlos). Podis lanzaros ya a la creacin del nivel.
Si habis seguido los pasos de esta gua, el escenario principal debera estar hecho ya. por lo
tanto, solo queda posicionar en nuestro nivel las bolas y las plataformas (En el Pang original
hay escaleras tambin, podis 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 prximo tutorial de Gameplay: Arcade
FPS (on rails First Person Shooter).

También podría gustarte