Unity 3D – Cómo hacer un cuadro de selección como el de un RTS

El cuadro de selección

Ahora vamos a hacer el cuadro de selección. Para ello vamos a utilizar unaGUITexture, a la que le he metido una textura que he hecho fácilmente con cualquier programa que maneje transparencias. Consiste en una imagen PNG de un único pixel verde a la que he añadido una transparencia del 15% llamada «selection.png» que he puesto en una carpeta nueva llamada «Textures».

Los elementos GUI se dibujan directamente en pantalla, es decir, no tienen ninguna profundidad y, por tanto,  no ocupan un espacio tridimensional. Esto es imprescindible para hacer los menús, el HUD, o este cuadro de selección.

Igual que hicimos con los cazas, vamos a crear un Prefab llamado «SelectionBox» dentro de la carpeta «Resources» (¡¡recordad que si no no nos funcionará!!), y vamos a arrastrar el GUITexture que hemos creado en él. Y ya podemos borrarlo del Hierarchy.

Ahora vamos a hacer que nuestro cuadro se dibuje. Para ello volvemos al «GameLogicScript» y esta vez vamos a trabajar sobre el Update. ¿Qué vamos a hacer?

Cuando el usuario inicie un cuadro de selección, vamos a tirar un rayo (clase Ray) desde la posición de nuestro puntero, y vamos a guardar el primer punto 3D en el que colisione (propiedad RaycastHit.point). ¿Por qué? Porque si guardásemos simplemente el punto de la pantalla, al mover la cámara éste cambiaría con respecto a la malla tridimensional, que es donde realmente está apuntando el jugador. Una vez sepamos dónde comienza nuestro cuadro de selección, a la hora de dibujarlo tan sólo necesitaremos pasar sus coordenadas de mundo a las coordenadas de pantalla respecto a la posición actual de la cámara. De este modo, el cuadro no hará cosas raras cuando se mueva la cámara.

El nuevo código del «GameLogicScript» va a quedar así:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. public class GameLogicScript : MonoBehaviour
  5. {
  6.     InputHandlerScript _input;
  7.     //Lista de cazas
  8.     List<gameobject> _fighters;
  9.     //Cuadro de selección
  10.     GameObject _selectionBox;
  11.     //Origen de la selección actual
  12.     Vector3 _selectionOrigin;
  13.     //Con esta variable sabemos si hemos comenzado una selección
  14.     bool _selecting;
  15.     // Use this for initialization
  16.     void Start ()
  17.     {
  18.         //Guardamos la referencia al input en nuestra clase
  19.         _input = this.GetComponent<InputHandlerScript>();
  20.         //Inicializamos la lista
  21.         _fighters = new List<GameObject>();
  22.         //Vamos a crear 3 cazas
  23.         GameObject fighter = Resources.Load(«FighterObject») as GameObject;
  24.         GameObject fighter1 = GameObject.Instantiate(fighter, new Vector3(831, 1, 961), Quaternion.identity) as GameObject;
  25.         GameObject fighter2 = GameObject.Instantiate(fighter, new Vector3(841, 1, 961), Quaternion.identity) as GameObject;
  26.         GameObject fighter3 = GameObject.Instantiate(fighter, new Vector3(851, 1, 961), Quaternion.identity) as GameObject;
  27.         //Añadimos los cazas a la lista
  28.         _fighters.Add(fighter1);
  29.         _fighters.Add(fighter2);
  30.         _fighters.Add(fighter3);
  31.     }
  32.     // Update is called once per frame
  33.     void Update ()
  34.     {
  35.         DrawSelectionBox();
  36.     }
  37.     void DrawSelectionBox()
  38.     {
  39.         if (!_selecting)
  40.         {
  41.             //Si no estamos seleccionando, comprobamos que si se ha pulsado la tecla de selección
  42.             if (_input._selectingBegins)
  43.             {
  44.                 RaycastHit hit;
  45.                 Ray ray;
  46.                 //Lanzamos un rayo desde la pantalla de nuestra cámara, tomando como punto la posición de nuestro puntero
  47.                 ray = Camera.main.ScreenPointToRay(_input._mousePosition);
  48.                 if (Physics.Raycast(ray, out hit))
  49.                 {
  50.                     //Guardamos el punto tridimensional en el que colisiona nuestro rayo.
  51.                     _selectionOrigin = hit.point;
  52.                     //Creamos el cuadro de selección
  53.                     _selectionBox = GameObject.Instantiate(Resources.Load(«SelectionBox»)) as GameObject;
  54.                     _selectionBox.guiTexture.pixelInset = new Rect(_input._mousePosition.x, _input._mousePosition.y, 1, 1);
  55.                     //Indicamos que hemos empezado una selección
  56.                     _selecting = true;
  57.                 }
  58.             }
  59.         }
  60.         else
  61.         {
  62.             //Si ya hemos comenzado una selección, comprobamos que ésta no ha acabado
  63.             if (_input._selectingEnds)
  64.             {
  65.                 //Destruimos el cuadro de selección
  66.                 Destroy(_selectionBox);
  67.                 //Indicamos que hemos finalizado nuestra selección
  68.                 _selecting = false;
  69.             }
  70.             else
  71.             {
  72.                 //Estos son los límites de nuestro cuadro de selección
  73.                 Rect bound = _selectionBox.guiTexture.pixelInset;
  74.                 //Con esta sencilla función pasamos el origen de la selección a coordenadas de pantalla
  75.                 Vector3 selectionOriginBox = Camera.main.WorldToScreenPoint(_selectionOrigin);
  76.                 //Recogemos los límites de nuestro cuadro en función del punto de origen y la posición actual del puntero
  77.                 bound.xMin = Mathf.Min(selectionOriginBox.x, _input._mousePosition.x);
  78.                 bound.yMin = Mathf.Min(selectionOriginBox.y, _input._mousePosition.y);
  79.                 bound.xMax = Mathf.Max(selectionOriginBox.x, _input._mousePosition.x);
  80.                 bound.yMax = Mathf.Max(selectionOriginBox.y, _input._mousePosition.y);
  81.                 //Cambiamos el pixelInset de nuestro cuadro de selección
  82.                 _selectionBox.guiTexture.pixelInset = bound;
  83.             }
  84.         }
  85.     }
  86. }
  87. </gameobject>

Nos fijamos que hemos introducido unas cuantas propiedades más en nuestro proyecto. Si lo lanzamos ya deberíamos ver cómo se dibuja perfectamente nuestro cuadro de selección, manteniendo la coherencia respecto al espacio tridimensional aún cuando movemos la cámara.

Unity 3D – Cómo hacer un cuadro de selección como el de un RTS comentarios en «4»

  1. Me encants está sección *O* ,antes daba un poco de programación,nada del otro mundo pero ya se me ha olvidado casi todo T^T

      1. Sí, la verdad es que este tutorial me ha quedado un poquito bastante denso.

        Espero que con el código fuente, por lo menos la gente pueda trastear y ver cómo está todo si se pierden en algún punto del tutorial y no les sale ;).

  2. Buenas, estaba trasteando y me he quedado un poco colgado en la primera parte con el script, me da un error en la linea 14
    «GameObject fighter = Resources.Load(“FighterObject”)»
    Podrias poner de nuevo la fuente de ejemplo para ver como está la jerarquia y despejar mis dudas? Porque da error.
    Gracias

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *