Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Docslide - Es Tutorial Shooter 2d en Unity
Docslide - Es Tutorial Shooter 2d en Unity
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).
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.
¡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.
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
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.js
var 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 escena
function Start()
{
Globals.Lives = 3;
Globals.Score = 0;
Globals.Bulletlimit = 0;
}
function Update () { //Esta función se repetirá cada frame
if(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
}
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
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 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.
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
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.
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.
RESULTADO:
LOS BLOQUES:
Bloque Normal:
Bloque Rompible:
A todos los he creado “físicamente” de la misma manera, así que con explicar la creación de
uno es suficiente.
Bola:
Bola metálica:
Fracción de Bola:
Arpón:
Partículas:
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.
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.js
var texto: GUIText; //El GuiText que mostrará la palabra “pausa” cuando es pulsado el botón de
pausa
var 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.
}
}
Score:
Score.js
var texto:GUIText; //El texto que mostrará la puntuación
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 número 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 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);
}
}
}
Win:
Win.js
var littleballstowin : int; //Las bolas pequeñas 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 estás
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 () {
}
}
}
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 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);
}
}
}
Doble Arpón(Item):
ItemDArpoon:
ItemDArpoon.js
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 garfio
function OnCollisionEnter(collision : Collision)
{
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)
{
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 partículas que se emitirá cuando el arpón toque la bola
var item : GameObject[]; //los items que dropeará la bola.
var Divisionsection: GameObject; //La división 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) {
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.
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 jugador
if(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);
}
}
}
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) {
}
Bola Metálica(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;
}
}
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;
}
Destroy Object:
NOTA: Este script se añade 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)
{
}
else
{//De lo contrario, el arpón 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 añade 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 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")){
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 sheet
var colCount : int = 4;
var rowCount : int = 4;
//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;
// 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);
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
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).