Jump to content
UnitySpain
Yilmar Lopez Ospina

Problema al ubicar prefab dentro de Canvas

Recommended Posts

Hola a todos, agradezco de antemano la ayuda que me puedan brindar

Estoy creando un videojuego 2D muy sencillo, donde el personaje inicia con tres vidas y puede ir recolectando algunas otras a medida que avanza en los niveles, cada vida esta representada por un corazón que aparece cuando se colisiona con un objeto particular, esto funciona muy bien, el problema es que cuando el personaje se mueve y obtiene una nueva vida el cortazon aparece en una posicion distinta de la esperada, puede ser antes o despues de los otros inclusive sobre ellos.

Creo que el problema es por el manejo del Canvas y su componente RectTransform pero no doy en como solucionarlo, gracias

vidas_bien.PNG

vidas_mal.PNG

vidas_mal_2.PNG

Share this post


Link to post
Share on other sites

una idea, los corazones insancialos dentro de un digamos contenedorDeCorazones y a este contenedor agregale un componente que se llama "Horizontal Layout Group" y a los prefabs de los corazones agregales el componente Layout Element y ya me cuentas que tal te va ;)

Share this post


Link to post
Share on other sites

Hola Tiagosan,

Creo un objeto vacío que sera el contenedor y le agrego el componente "Horizontal Layout Group" , al prefabs del corazon le agrego el componente "Layout Element", pero cuando ejecuto el juego me da el siguiente error.

error_layuot.PNG

Share this post


Link to post
Share on other sites

HOla, como te dicen arriba con el Group (me suena aunque nunca lo he usado) o si querés podés simplemente tener una "pool" de corazones ya ubicados, activar o desactivar dependiendo de los corazones que tengas.

Osea tenés un padre que contiene dentro a los corazones (visuales) y el script activa o desactiva cada uno dependiendo de una variable (un int), puse un actualizar corazones (a modo de generalizar), pero si agregas o quitás de a uno te podés manejar mejor y no haría falta el for, pero bueno no es tan relevante para 5 corazones. Esta medio en pseudocodigo.

int corazones; 

List<Image> corazonesUI = new List<Image>(); //de "UnityEngine.UI"

public Transform parentCorazonesUI;
//...

void Start(){
	for(int i=0 ; i< parentCorazonesUI.childCount ; i++){
    	corazonesUI.Add( parentCorazonesUI.GetComponent<Image>() );
    }
}

//se dió que cambió el num de corazones llamás a esto
void ActualizarCorazones(){
	for(int i=0 ; i< corazonesUI.Count ; i++){    
    	corazonesUI[i].enabled = i < corazones;	//true si i es menor a corazones, false si no es así        
    }
}

Si querés ubicarlos por código hacerlo en runtime siempre no tendría sentido, lo mejor es hacerlo una vez (en start por ej) y despues tocar el enabled o activando/desactivando el gameObject si quisieras. En start para ubicarlos solo tenés que hacer:

void Start(){
  for(int i=0 ; i< parentCorazonesUI.childCount ; i++){
          corazonesUI.Add( parentCorazonesUI.GetComponent<Image>() );
          //posDeRef la que vos quieras , offset lo definis como quieras, en tu imagen sería Vector2.right * offsetX (en pixels)
          corazonesUI.rectTransform.anchoredPosition = posDeRef + i * Offset;
      }

}

Saludos

Edited by lightbug

Share this post


Link to post
Share on other sites

no necesitas setearle la posicion, simplemente los vas instanciando dentro del group layout y ya se ordenan solitos, ahora tambien es verdad que tenerlos siempre instanciados y irlos desactivando es una buena idea, incluso te diría que mejor! ya que evitas estar instanciando y destruyendo que implica carga extra para el procesador

podrias por tanto montar el contenedor con el horizontal layout group y ahí dentro poner un corazon y e irlos duplicando (ctrl+d) veras como se van ordenando solitos.

y ya luego creas un script que te gestione el activar desactivar los corazones y yastaria, simple y menos carga para el micro ;)

Share this post


Link to post
Share on other sites

Hola lightbug y TiagoSan

Anoche logre solucionarlo con una idea que se me ocurrió cuando estaba implementando la primera respuesta de TiagoSan y fue mas o menos asi, cree un Stack para almacenar los corazones a medida que se van creando y cada que se va a crear uno nuevo se obtiene la posicion del ultimo creado que esta al inicio de la pila y se le suma algunos pixeles a la posicion en x del vector de posicion para usarla como la posicion del nuevo objeto, asi funciono correctamente.

Pero ahora pensando en el uso de recursos no se si sera mejor optar por la recomendacion de lightbug, ¿que me recomienda?

Dejo el codigo que hice

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CrtPlayerLifes : MonoBehaviour
{
	public GameObject Player;
	public GameObject LifeObject;
	public GameObject PnlLifes;
	public float AddPosition;

	private Vector3 LifeObjectPosition;
	private Stack<GameObject> StackLifes;
	private int InitLifes;
	private int MaxLifes;

	// Use this for initialization
	void Start () {
		LifeObjectPosition 	= LifeObject.GetComponent<Transform>().position;
		InitLifes 			= (int)Player.GetComponent<CrtPlayerController> ().InitAmountLifes;
		MaxLifes 			= (int)Player.GetComponent<CrtPlayerController> ().MaxAmountLifes;
		StackLifes 			= new Stack<GameObject>();
		InitializeLifes ();
	}

	private void InitializeLifes()
	{
		for(int i = 1; i <= InitLifes; i++)
			CreateLife ();
	}

	public void CreateLife()
	{
		if (StackLifes.Count < MaxLifes)
		{
			Vector3 PosicionActualLife	= (StackLifes.Count > 0) ? StackLifes.Peek ().GetComponent<Transform>().position : LifeObjectPosition;
			PosicionActualLife.x 		+= AddPosition;
			GameObject ActualLife 		= Instantiate (LifeObject, PosicionActualLife, Quaternion.identity);
			int Position 				= StackLifes.Count + 1;
			ActualLife.transform.parent = PnlLifes.transform;
			ActualLife.name				= "Life" + Position;
			StackLifes.Push (ActualLife);
		}
	}

	public void DestroyLife()
	{
		if (StackLifes.Count > 0)
		{
			GameObject ActualLife = StackLifes.Pop ();
			Destroy (ActualLife.gameObject);
			LifeObjectPosition.x -= AddPosition;
		}
	}
}

 

 

Share this post


Link to post
Share on other sites

Yo te recomendaría usar las dos soluciones, el prender/apagar (sin instanciar) mezclado con el Layout Group :12_slight_smile: ., si querés en vez de la lista usar un stack o cualquier otro contenedor (queue, array, etc) está perfecto también, es más con un array estás mas que bien para esto, si querés orderarlos usando un "helper" como el Layout group, o por código o a mano (en el mismo editor) también está bien, no importa realmente, claro depende, Ej si tuvieras unos corazones UI estilo la UI de "Persona5" (un despiole bárbaro) te diría que vayas al "a mano".

Acordate que no es necesario usar getcomponent<Transform>

StackLifes.Peek ().GetComponent<Transform>().position

abajo lo usaste bien con el ".transform".

Saludos

 

Share this post


Link to post
Share on other sites

eso, y no te compliques poniendo los objetos a mano (o sea marcando la posición, con el layout group se ponen solitos, una nota en esto lo corazones tenes que marcarles en el rect transform que se alinien a la parte superior derecha así van a ir amontonandose en orden a la izquierda [♥♥♥♥-]
más que programar es cuestión de que pruebes configuraciones en el layout group y en el element layout, 
y si como más optimo es que estén siempre instanciados y los actives/desactives según corresponda 

 

Share this post


Link to post
Share on other sites

×
×
  • Create New...