lunes, 14 de abril de 2014

Tutorial Galería 3D en Unity

Hoy vamos a aprender a hacer una sencilla galería de personajes para nuestro videojuego. Lo haremos mediante Unity3D.



Para ello colocaremos tres modelos 3D en diversas posiciones de un plano mediante el Editor.
Una vez en sus posiciones hay que crear un script para el movimiento de la cámara. Dentro del script podemos distinguir 3 elementos:

  • Función Start
  • Función Update
  • Función OnGUI
 Antes de revisar el script vamos a echar un vistazo a las variables:

// Object to show in gallery
var objects : GameObject[];
// Current object showed by camera
var current : int = 0;
// is camera position chaging to next object?
var onChange : boolean = true;
// Smooth in camera movement
var cameraSmoothing : int = 5;
// Textures for GUI
var arrowNextTexture : Texture;
// Textures for GUI
var arrowPrevTexture : Texture;
// Delta in camera rotation
var deltaMine : float = 1;
// Is camera rotating?
var rotating : boolean = false;



objects tendrá un array que se rellenerá desde el Editor.
current tendrá el índice del personaje mostrado por la cámara.
onChange servirá para detectar si la cámara puede empezar a rotar sobre el personaje.
cameraSmoothing será la suavidad con la que se mueva la cámara.
arrowNextTexture y arrowPrevTexture serán las texturas del GUI.
deltaMine será el factor delta con el que rote la cámara.
rotating un flag para saber si la cámara está rotando al rededor del personaje.

La función Start inicializará las variables antes descritas y mostrará en cámara el primer personaje del array objects.

En la función Update se hace lo siguiente:

Primero se obtiene la diferencia de movimiento de la cámara en el eje X. Con esto sabremos que la cámara se esta moviendo hacia otro personaje. Se setean los flags para decidir si la cámara tiene que empezar a rotar o no.

function Update () {
 
 var diff = Mathf.Abs(target.position.x - transform.position.x); 

 // Offset movement to decide if camera starts rotating
 
 if (!rotating && diff > 0.001) {
 
  onChange = true;
  rotating = false;
  
 } else {
 
  onChange = false;
  rotating = true;
 
 }


Después si no está cambiando de objetivo la cámara se empieza a rotar sobre el personaje actual.
Si está cambiando de objetivo entonces se fija en el tag del personaje. Si el tag es "Small" entonces se acerca más, si el tag es "Big" se aleja un poco del personaje y si no tiene tag queda la cámara en una posición intermedia. Se calcula la posición de la cámara y la rotación inicial mirando hacia el personaje. Por último se guarda la posición X actual de la cámara.
 

 // Smooth translate to target

 if (!onChange) {
  
  transform.RotateAround(target.position, Vector3.up, deltaMine);
  
  
 } else {

  // If the object is tagged with Small, camera will go close to the object
  // If object has Big tag, the camera will show object from distance
  // Else normal camera distance

  if (target.tag == "Small")
   transform.position = Vector3.Lerp(transform.position, target.position + currentCameraOffsetPlayers, Time.deltaTime * cameraSmoothing);
  else if (target.tag == "Big")
   transform.position = Vector3.Lerp(transform.position, target.position + currentCameraOffsetHuge, Time.deltaTime * cameraSmoothing);
  else
   transform.position = Vector3.Lerp(transform.position, target.position + currentCameraOffset, Time.deltaTime * cameraSmoothing);
 
 
  // Smooth transition to new rotation

      var relativePos = (target.position + currentFocusOffset) - transform.position;

     targetRotation = Quaternion.LookRotation(relativePos);

     transform.rotation = Quaternion.Lerp(transform.rotation, targetRotation, Time.deltaTime * cameraSmoothing); 

  // Track old x position to decide if camera starts rotating

  oldXPosition = transform.position.x;
  
 }
 
}

En la función OnGUI se muetran las dos flechas que permitirán pasar de un personaje a otro:
 
function OnGUI () {
 
  var width : int = 50;
  var height : int = 50;
  var rectNext : Rect = Rect((Screen.width * 0.85) - 50, Screen.height/2, width, height);
  
  // Next!
   if (GUI.Button(rectNext,arrowNextTexture)) {
    
    // Mod, from last to first and viceversa
    if (current == objects.length-1)
     current = -1;
   
   target = objects[++current].transform;
   rotating = false;
   onChange = true;
   
   }  
  
  
  var rectPrev : Rect = Rect((Screen.width * 0.15), Screen.height/2, width, height);
  
   // Previous!
   if (GUI.Button(rectPrev,arrowPrevTexture)) {
   
    // Mod, from last to first and viceversa
    if (current == 0)
     current = objects.length;
     
   target = objects[--current].transform;
   rotating = false;
   onChange = true;
   
   }       
 
} 


Aquí podeís encontrar el proyecto Unity completo: