Si las naves estuvieran demasiado alejadas del terreno, el cuadro de selección, que tiene su origen anclado al suelo, podría hacer alguna cosa rara con las naves. En ese caso, podríamos establecer el origen cogiendo la posición del eje Y de las coordenadas de los cazas. Pero todas esas cosas ya os las dejo a vosotros si queréis complementar el código.
Nuestro cuadro aún no selecciona nada, que era para eso para lo que lo queríamos, así que vamos a tener que completar el código del «GameLogic» un poco más con una nueva función que he llamado «UpdateSelection()».
Vamos a utilizar una variable «_selectedFighters» para guardar los cazas seleccionados, de modo que en un futuro podamos darles órdenes. Y crearemos otra variable «_keptSelectedFighters» donde guardaremos la última selección de cazas, y que se mantendrá si el usuario utiliza las teclas de «keepSelection» o «invertSelection». Ambas variables deberemos inicializarlas en la función Start();Otra cosa que he hecho es meter la lógica del «_selecting» en el «UpdateSelection()», para que el «DrawSelectionBox()» no impida que se ejecute la inicialización y la finalización de la lógica de selección.
El código definitivo nos quedará así:
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- public class GameLogicScript : MonoBehaviour
- {
- InputHandlerScript _input;
- //Listas de cazas
- public List<GameObject> _fighters;
- public List<GameObject> _selectedFighters;
- public List<GameObject> _keptSelectedFighters;
- //Cuadro de selección
- public GameObject _selectionBox;
- //Origen de la selección actual
- public Vector3 _selectionOrigin;
- //Con esta variable sabemos si hemos comenzado una selección
- public bool _selecting;
- // Use this for initialization
- void Start ()
- {
- //Guardamos la referencia al input en nuestra clase
- _input = this.GetComponent<InputHandlerScript>();
- //Inicializamos las listas
- _fighters = new List<GameObject>();
- _selectedFighters = new List<GameObject>();
- _keptSelectedFighters = new List<GameObject>();
- //Vamos a crear 3 cazas
- GameObject fighter = Resources.Load(«FighterObject») as GameObject;
- GameObject fighter1 = GameObject.Instantiate(fighter, new Vector3(831, 1, 961), Quaternion.identity) as GameObject;
- GameObject fighter2 = GameObject.Instantiate(fighter, new Vector3(841, 1, 961), Quaternion.identity) as GameObject;
- GameObject fighter3 = GameObject.Instantiate(fighter, new Vector3(851, 1, 961), Quaternion.identity) as GameObject;
- //Añadimos los cazas a la lista
- _fighters.Add(fighter1);
- _fighters.Add(fighter2);
- _fighters.Add(fighter3);
- }
- // Update is called once per frame
- void Update ()
- {
- DrawSelectionBox();
- UpdateSelection();
- }
- void DrawSelectionBox()
- {
- if (!_selecting)
- {
- //Si no estamos seleccionando, comprobamos que si se ha pulsado la tecla de selección
- if (_input._selectingBegins)
- {
- RaycastHit hit;
- Ray ray;
- //Lanzamos un rayo desde la pantalla de nuestra cámara, tomando como punto la posición de nuestro puntero
- ray = Camera.main.ScreenPointToRay(_input._mousePosition);
- if (Physics.Raycast(ray, out hit))
- {
- //Guardamos el punto tridimensional en el que colisiona nuestro rayo.
- _selectionOrigin = hit.point;
- //Creamos el cuadro de selección
- _selectionBox = GameObject.Instantiate(Resources.Load(«SelectionBox»)) as GameObject;
- _selectionBox.guiTexture.pixelInset = new Rect(_input._mousePosition.x, _input._mousePosition.y, 1, 1);
- }
- }
- }
- else
- {
- //Si ya hemos comenzado una selección, comprobamos que ésta no ha acabado
- if (_input._selectingEnds)
- {
- //Destruimos el cuadro de selección
- Destroy(_selectionBox);
- }
- else
- {
- //Estos son los límites de nuestro cuadro de selección
- Rect bound = _selectionBox.guiTexture.pixelInset;
- //Con esta sencilla función pasamos el origen de la selección a coordenadas de pantalla
- Vector3 selectionOriginBox = Camera.main.WorldToScreenPoint(_selectionOrigin);
- //Recogemos los límites de nuestro cuadro en función del punto de origen y la posición actual del puntero
- bound.xMin = Mathf.Min(selectionOriginBox.x, _input._mousePosition.x);
- bound.yMin = Mathf.Min(selectionOriginBox.y, _input._mousePosition.y);
- bound.xMax = Mathf.Max(selectionOriginBox.x, _input._mousePosition.x);
- bound.yMax = Mathf.Max(selectionOriginBox.y, _input._mousePosition.y);
- //Cambiamos el pixelInset de nuestro cuadro de selección
- _selectionBox.guiTexture.pixelInset = bound;
- }
- }
- }
- void UpdateSelection()
- {
- if (!_selecting)
- {
- if (_input._selectingBegins)
- {
- //Si no mantenemos la selección
- if (!_input._keepSelection && !_input._invertSelection)
- {
- //Desmarcamos los cazas
- foreach (GameObject fighter in _selectedFighters)
- {
- Component[] renders = fighter.GetComponentsInChildren(typeof(Renderer));
- foreach (Renderer render in renders)
- render.material.color -= Color.yellow;
- }
- //Limpiamos las listas de cazas seleccionados
- _selectedFighters.Clear(); //Esta no es necesario limpiarla ya
- _keptSelectedFighters.Clear();
- }
- //Indicamos que hemos empezado una selección
- _selecting = true;
- }
- }
- else
- {
- if (_input._selectingEnds)
- {
- //Guardamos la lista actual de cazas seleccionados
- foreach (GameObject fighter in _selectedFighters)
- _keptSelectedFighters.Add(fighter);
- //Indicamos que hemos finalizado nuestra selección
- _selecting = false;
- }
- else
- {
- RaycastHit hit;
- Ray ray;
- //Buscamos las unidades y edificios que se encuentren dentro de la caja de selección
- List<GameObject> fightersInSelectionBox = new List<GameObject>();
- //Dado que no se puede modificar una lista mientras la estás recorriendo,
- //es mejor utilizar listas alternaticas para agregar y remover
- //Lista de cazas que añadiremos a la selección
- List<GameObject> fightersToAdd = new List<GameObject>();
- //Lista de cazas que removeremos de la selección
- List<GameObject> fightersToRemove = new List<GameObject>();
- //Primero lanzamos un rayo para guardar el punto de finalización de la selección
- ray = Camera.main.ScreenPointToRay(_input._mousePosition);
- if (Physics.Raycast(ray, out hit))
- {
- //Este es el plano tridimensional de selección
- Rect selectionPlane = new Rect();
- selectionPlane.xMin = Mathf.Min(_selectionOrigin.x, hit.point.x);
- selectionPlane.yMin = Mathf.Min(_selectionOrigin.z, hit.point.z);
- selectionPlane.xMax = Mathf.Max(_selectionOrigin.x, hit.point.x);
- selectionPlane.yMax = Mathf.Max(_selectionOrigin.z, hit.point.z);
- //Comprobamos que el rayo no golpea directamente en una unidad
- //if (this._fighters.Contains(hit.collider.gameObject)) //Si el collider estuviera en el propio objeto
- //En nuestro caso los colider están en los componentes hijos del FighterObject, por lo que debemos acceder al padre
- if (hit.collider.gameObject.transform.parent != null && this._fighters.Contains(hit.collider.gameObject.transform.parent.gameObject))
- {
- //Esta comprobación es necesaria, ya que al coger un único punto de referencia de los cazas, si éste punto no está dentro del cuadro, no lo seleccionaría
- fightersInSelectionBox.Add(hit.collider.gameObject.transform.parent.gameObject);
- }
- //Agregamos a la lista los cazas que se encuentran dentro del cuadro de selección
- foreach (GameObject fighter in this._fighters)
- {
- if (!fightersInSelectionBox.Contains(fighter) && (fighter.transform.position.x >= selectionPlane.xMin && fighter.transform.position.x <= selectionPlane.xMax && fighter.transform.position.z >= selectionPlane.yMin && fighter.transform.position.z <= selectionPlane.yMax))
- {
- fightersInSelectionBox.Add(fighter);
- }
- }
- }
- foreach (GameObject fighter in fightersInSelectionBox)
- {
- if (!_input._invertSelection)
- {
- //Si no está pulsada la tecla de invertSelection seleccionamos los cazas del cuadro
- if (!_selectedFighters.Contains(fighter))
- {
- fightersToAdd.Add(fighter);
- }
- }
- else
- {
- //Si está pulsada la tecla de invertSelection removemos los cazas del cuadro
- if (_selectedFighters.Contains(fighter))
- {
- fightersToRemove.Add(fighter);
- }
- }
- }
- if (!_input._keepSelection)
- {
- foreach (GameObject fighter in _keptSelectedFighters)
- {
- if (!_input._invertSelection)
- {
- if (!fightersInSelectionBox.Contains(fighter) && _selectedFighters.Contains(fighter))
- {
- fightersToRemove.Add(fighter);
- }
- }
- else
- {
- if (!fightersInSelectionBox.Contains(fighter) && !_selectedFighters.Contains(fighter))
- {
- fightersToAdd.Add(fighter);
- }
- }
- }
- }
- foreach (GameObject fighter in fightersToAdd)
- {
- SelectFighter(fighter);
- }
- foreach (GameObject fighter in fightersToRemove)
- {
- DeselectFighter(fighter);
- }
- }
- }
- }
- void SelectFighter(GameObject fighter)
- {
- //Comprobamos que el caza no esté ya seleccionado
- if (!_selectedFighters.Contains(fighter))
- {
- //Agregamos el caza a la lista
- _selectedFighters.Add(fighter);
- //Marcamos el caza de color amarillo
- Component[] renders = fighter.GetComponentsInChildren(typeof(Renderer));
- foreach (Renderer render in renders)
- render.material.color += Color.yellow;
- }
- }
- void DeselectFighter(GameObject fighter)
- {
- if (_selectedFighters.Contains(fighter))
- {
- //Removemos el caza de la lista
- _selectedFighters.Remove(fighter);
- //Desmarcamos el caza
- Component[] renders = fighter.GetComponentsInChildren(typeof(Renderer));
- foreach (Renderer render in renders)
- render.material.color -= Color.yellow;
- }
- }
- }
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
hace un mes o dos colgamos un tutorial más simple para mover un objeto por la pantalla =P
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 ;).
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