Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

quiero definir un Item para agregarlo a un pila de objetos y luego agruparlo.

Iniciado por Ness, Julio 20, 2018, 04:38:52 PM

Tema anterior - Siguiente tema
tengo un clase que la otorgo la variable cantidad y de tipo("La defino por lista de Enum"), pero me he dado cuanta de que es complicado buscar un objeto atrevas de este método lo que se me ha ocurrido es definir primero el tipo de objeto y que luego en base  a esa elección me sea visible la lista de objetos de esa pila en especifico, pero no tengo idea de como hacer eso.
 
 
 

[System.Serializable]
public class Item
{
    public enum ItenType
    {
        //consumibles
        posion,
        hierva,
        pierda,
        manzana,
        antidoto,
        megaposion,
       
        // , Attacks
        Barrida,
        Recuperacion,
        //ObjClave
        llave,
        pistola,
        palodepesca,
        //Frutas
        fruta1,
        fruta2,
        fruta3,
        fruta4,
        //Jaulas
        normal,
        especial,
        acuatia,
        sol,
        luna,
        rapida,
        recuperacion,
        solida,
        sinestado,
        Confusion,
       
       
        //Stands
        pasiva,
        agresiva,
        defensiva,
        desgaste,
        aguante,
        PosturaRapida,
 

        //ObjEfects
        ataqueEfec,
        defensaEfec,
        velocidadEfec,
        AntiEstado,
        MoreExperience,
        antiFinalHit
 
    }
    public ItenType iten = new ItenType();
    public int cantidad;
    }

 
Esta  clase tiene la cantidad y todos los objetos visibles, pero quiero hacerlo por de forma que primero  defino que clase objeto ejemplo; si es consumible,  aparece todos los objetos consumibles, si una hierba la defino como tal y luego me aparece una lista con todas objetos hierbas.

tendria que tener otro enum donde enumeres las clases de objeto...
 
y en la funcion "new" (cuando creas un item) añadir un switch que mire que item es... y dependiendo de que item sea se ponga automatica la clase...
 
si es pocion la clase es consumible...
 
 
 
...yo lo habria hecho solo con un enum de "clase"... y el nombre del item seria un string... no un enum... aunque no se que "funcionalidades" quieres que tenga...
 
 

Cita de: Igor date=1532116127tendria que tener otro enum donde enumeres las clases de objeto...
   
   
      y en la funcion "new" (cuando creas un item) añadir un switch que mire que item es... y dependiendo de que item sea se ponga automatica la clase...
   
   
      si es pocion la clase es consumible...
   
   
       
   
   
      ...yo lo habria hecho solo con un enum de "clase"... y el nombre del item seria un string... no un enum... aunque no se que "funcionalidades" quieres que tenga...
   
   
       
   


Así es como lo tengo hecho en principio ,  pero a la larga ese método :/ requiere tenga una lista inmensa para cada cosa ademas de memorizar X( objetos en ves de definiros desde un principio me encontré que costumizando la editor se puede conseguir ese resultado pero estoy tratando de que usando esta función pueda usarla sin necesidad andar poniéndola en otro scritp pero por lo que  voy  viendo me va tocar hacer eso.
 
https://answers.unity.com/questions/1085035/how-can-i-create-a-enum-like-as-component-light.html
 
Aquí esta el scripts en el que me estoy basando pero una ves se usa, todas  la demás variables son invisibles, agradecería saber si hay alguna forma de usarlo para que no tenga que usar scritps  externos a la clase principal del método.

Para mi te falta expandir sino utilizar la programación orientada a objetos. El enum suele ser "lindo" para reemplazar una secuencia de números y ponerle a cada uno una etiqueta como por ej "bajo", "medio", "ultra", que se yo, pero no para utilizarlo para tipos, osea se puede (pero los estás usando de tags, sin funcionalidad) y sobretodo para meter a todo en la misma bolsa, quizás el concepto de herencia junto con polimorfismo vayan bien para hacer lo que querés hacer, teniendo a item la clase base como clase abstracta (para no crear directamente un "item", sí sus derivados). entonces item solo es una clase y sus clases derivadas reciben el System.Serializable.
 
Cita de: Ness date=1532136699Aquí esta el scripts en el que me estoy basando pero una ves se usa, todas  la demás variables son invisibles, agradecería saber si hay alguna forma de usarlo para que no tenga que usar scritps  externos a la clase principal del método.
   


Bueno, teniendo tus instancias como decía anteriormente no necesitás esto, cada instancia tendrá sus parámetros asociados que si son serializables (https://docs.unity3d.com/ScriptReference/SerializeField.html) podrás exponerlos en el inspector dependiendo del tipo de objeto que sea sin necesidad de elegirlos de una gran lista, es decir vos lo creas en tal momento.
 
Algo así no se si es más o menos lo que querés (un script que tenía por ahí):
 

 
Todas son abilidades (pertenecientes a la clase Abilities), en código tengo algo así:
 

public HorizontalMovementAbility m_horizontalMovement;
public GravityAbility m_gravity;
public JumpAbility m_jump;
... (y sigue)

 
Cada habilidad es de un tipo, cada una expone distintos parámetros, via polimorfismo puede decirle a cada una " HaceEsto() " y cada una responde distinto, o si quiero expandirla simplemente derivo de alguna de ellas ... vs unos simples enums.

Los tags son excelentes pero es que si voy tener 7 tipos diferentes de objetos pues a larga es una desventaja, los enum brillan con fuerza es cuando se utilizan dentro del script, ya que si se utiliza un script se corre el riesgo de cometer errores ortográficos, esto con los  enum no pasa  y le puede salvar la vida a uno mas de una ves.
 
Joda lightbug gracias por el aporte pero me termine decantando por el primer método hacia unas horas, voy probar el tuyo a ver si puedo implementarlo, gracias.

ah, claro, puedes hacerlo con classes como dice @lightbug
 
siempre se me olvida que es un lenguaje orientado a objetos.... jeje... puedes hacer la class item... y hacer que los otros items sean derivados... hay si que podrias derivarlos por "tipo" (consumible, ingrediente, arma, .. o lo que sea)
 
y dentro de esos podrias tener un enum para cada "item" (consumiblesEnum: pocion, pan, manzana...) 
 
o mejor igual solo un string de nombre... y luego unos campos de valores... 
 
 
 
lo siento @lightbug, pero lo de la serializacion tengo un problema serio, ni se para que vale, ni se como se usa
 
y no te creas que tengo muy claro como hacer clases derivadas de otras clases... recuerda que vengo de BASIC... y ahi no habia objetos ni clases ni nada....  lo justo toque un poco de Java y C++ antes de decidirme por Unity...
 
si puedes explicarme lo de "serializar" (a grandes rasgos, pa que me haga un idea...) mas que nada para que sirve, que no tengo ni idea

Como ha dicho el tito light, se usa herencia que para eso esta y te dejas de enums, que los enums solo se deberian usar para cosas pequeñas (elegir entre 3-4 valores).
 
 
 
Es decir algo tipo:
 

class Item{
//mis campos
}
class Sword : Item{
//los campos heredados mas lo que queramos que tenga la espada
}

 
 
 
Y luego todo eso lo rematamos con varias interfaces tipo 
 

interface IOnUse{
void OnUse();
}
 
interface IOnConsume{
void OnConsume();
}

 
 
 
De esta forma tendriamos algo como 
 

class Sword : Item, IOnUse{
public void OnUse(){
//lo que sea que hagamos para usar la espada
}
 
class HealingPotion : Item, IOnConsume{
public void OnConsume(){
//lo que sea para tomarse la pocion
}
}

 
 
 
Asi en vez de tanto if y tanto enum, en algun sitio tendras un:
 

void UsarObjetoDeInventario(){
for(int i = 0; i < miListaDeInventario.Count; i++){
if (miListaDeInventario is IOnConsume){
miListaDeInventario.OnConsume();
break;
}
}
}

 
 
 
Me he dejado la conversion del objeto a la interface, pero solo para que se entienda el ejemplo. Asi se podria loopear la lista para buscar el interface que quieras (por ejemplo IPotions) y asi sabrias que objetos son de tipo pocion, etc, etc, etc

Cita de: Igor date=1532274892lo siento @lightbug, pero lo de la serializacion tengo un problema serio, ni se para que vale, ni se como se usa
   
      y no te creas que tengo muy claro como hacer clases derivadas de otras clases... recuerda que vengo de BASIC... y ahi no habia objetos ni clases ni nada....  lo justo toque un poco de Java y C++ antes de decidirme por Unity...
   
      si puedes explicarme lo de "serializar" (a grandes rasgos, pa que me haga un idea...) mas que nada para que sirve, que no tengo ni idea


Cuando vos le mandás el atributo Serialize principalmente le estás diciendo al Editor que debe tomar en cuenta a la clase o a los campos a la hora de los HotReloads (cuando el circulito gira en la esquina inferior derecha del Editor :) ) o a la hora de guardar un asset (prefab, escenas, etc) , es decir le estás diciendo que "guarde" esos valores, osea que terminás exponiéndolos en el inspector (así se comporta por default).
 
https://docs.unity3d.com/Manual/script-Serialization.html
 
Cualquier "public X" de un monobehaviour se serializa, pero public implica más cosas que solo eso, estás dando acceso para todos y todas. Es un pecado muy visto usar "public" para exponer en inspector y uno aveces lo hace para cosas rápidas, cuando en realidad debería tener solo un "SerializeField", pero bueno, básicamente en monobehaviours alcanza con un public para mostrar cosas en inspector. Cuando tenés clases genéricas de C# Unity no hace nada con tus publics, lo que podés hacer es Serializar los campos con [SerializeField], pero para guardar estos campos también se debe guardar las instancias de la clase que los contienen, así que debés indicarle a la clase el atributo [System.Serializable]. Entonces las terminás viendo como en a imagen que subí, el tipico "foldout" del inspector de la instancia serializable con los campos serializados dentro:
 

 
más o menos, en el link tenés muy completo que hace y pa' que sirve.

Julio 23, 2018, 05:51:39 AM #8 Ultima modificación: Julio 23, 2018, 05:56:57 AM por juanma_teso
Otro más que te anima a utilizar herencia, incluso puede servir como ejemplo para explicar a alguien para qué sirve, creo que para tu caso @Eskema lo ha clavado.
 
Esto no quita que puedas usar un Enum para catalogar, pero yo haría algo más genérico tipo:
 

public Enum
{
fruta,
jaula,
objetoClave,
...
}

 
De esta forma puedes agregar en una lista todos los objetos que hereden de la clase base "Item" y ordenarlos como tú quieras al implementar la interfaz IComparable.

Cita de: juanma_teso date=1532317899Otro más que te anima a utilizar herencia, incluso puede servir como ejemplo para explicar a alguien para qué sirve, creo que para tu caso @Eskema lo ha clavado.
   
   
      Esto no quita que puedas usar un Enum para catalogar, pero yo haría algo más genérico tipo:
   
   

public Enum
{
fruta,
jaula,
objetoClave,
...
}

   
      De esta forma puedes agregar en una lista todos los objetos que hereden de la clase base "Item" y ordenarlos como tú quieras al implementar la interfaz IComparable.
   


El problema de usar un enum ahi es que se te va de las manos con la cantidad de objetos que puede haber. En tal caso yo como mucho tiraria de interfaces con los tipos, IPotion, IFood, etc, etc y asi lo mismo me da si es una manzana o una pera, es de tipo IFood y a tirar millas. 
 
Y lo mismo para el resto de "categorias" porque realmente no vas a poner nunca en la vida codigo tipo if (objeto.enum == manzana) RecuperaVida();, y si pones codigo asi lo estas haciendo realmente mal (esto va para cualquier persona que vaya comparando objetos para saber que logica les aplica)
 
Llamaras a la interfaz con el void OnUse(); y ya se apañara el objeto manzana para saber lo que quiere hacer o como lo hace.

En el título del topic pone que quiere hacer una pila de objeto y agruparlos, me parece que esa sería la forma más fácil de hacerlo... no estoy hablando de lo que haga cada "Item".

Cita de: juanma_teso date=1532350731En el título del topic pone que quiere hacer una pila de objeto y agruparlos, me parece que esa sería la forma más fácil de hacerlo... no estoy hablando de lo que haga cada "Item".
   


Dejando de lado la funcionalidad, "agruparlos" con interfaces es mas comodo que tirar de enums

@Eskema He tratado de implementar ese método que pusiste pero no he logrado resultados o no entiendo algunos pasos ("disculpa para que sirve el método interfaces "), me serviría un ejemplo mas explicito si no es mucho pedir, pero creo que el culpable de todo este enredo soy yo voy poner capturas para explicarme quiero  hacer un sistema de inventario para un rpg por turnos para un juego parecido a pokemon, 
 

 
En el inspector tengo  una list<>   para definir cuales son los items  que quiero guardarlos en la mochila, luego con este método los agrupo atreves  IF de un método que los clasifica a cada objeto en  en otra list<> , atrevas de  void DefineList(Item iten );
 

public enum TablesName
    {
        Consumible,
        Attacks,
        ObjClave,
        Frutas,
        Jaulas,
        Stands,
        ObjEfects
    }
public List<Item> item;
   [System.Serializable]
    public class ListStruck
    {
        public string Name = "Name Stand";
        [HideInInspector]
        public bool bUsed;
        public List<Item> Item;
     
       
    }
    /// <summary>
    /// 0: Consumibles, 1: Attacks, 2: ObjClaves, 3: Frutas, 4: Jaulas, 5: Stands, 6: ObjEfect
    /// </summary>
    public ListStruck[] listTables = new ListStruck[7];
 
 
  //----
void Start()
{
//recorro la lista de items que quiero meter en la lista.
 for (int i = 0; i < item.Count; i++)
        {
            DefineList(item);
        }
}
                               
   
                                //aqui ordeno las tablas
    /// <summary>
    /// define la lista de objetos dentro de todas las tablas.
    /// </summary>
    /// <param name="iten"></param>
    void DefineList(Item iten )
    {
//estos if me definen en cual lista deben ir  cada objeto
        int aux = 10;
         //consumible
        if (
               iten.iten == Item.ItenType.posion
            || iten.iten == Item.ItenType.antidoto
            || iten.iten == Item.ItenType.manzana
            || iten.iten == Item.ItenType.hierva
            || iten.iten == Item.ItenType.megaposion
            )
        {
            aux = 0;
        }
        //Atacks
        else if (
          iten.iten == Item.ItenType.Barrida
       || iten.iten == Item.ItenType.Recuperacion
       )
        {
            aux = 1;
        }
        //objetos claves
        else if
              (
                iten.iten == Item.ItenType.llave
             || iten.iten == Item.ItenType.pistola
             || iten.iten == Item.ItenType.CañadePescar
              )
        {
            aux = 2;
        }
 
        //Frutas
        else if
             (
                iten.iten == Item.ItenType.fruta1
              || iten.iten == Item.ItenType.fruta2
              || iten.iten == Item.ItenType.fruta3
              || iten.iten == Item.ItenType.fruta4
             )
        {
            aux = 3;
        }
 
        //Jaulas
        else if
             (
                 iten.iten == Item.ItenType.normal
              || iten.iten == Item.ItenType.especial
              || iten.iten == Item.ItenType.acuatia
              || iten.iten == Item.ItenType.sol
              || iten.iten == Item.ItenType.luna
              || iten.iten == Item.ItenType.rapida
              || iten.iten == Item.ItenType.recuperacion
              || iten.iten == Item.ItenType.solida
              || iten.iten == Item.ItenType.sinestado
              || iten.iten == Item.ItenType.Confusion
             )
        {
            aux = 4;
        }
        //stand
        else if
            (
                iten.iten == Item.ItenType.pasiva
             || iten.iten == Item.ItenType.agresiva
             || iten.iten == Item.ItenType.defensiva
             || iten.iten == Item.ItenType.desgaste
             || iten.iten == Item.ItenType.aguante
             || iten.iten == Item.ItenType.PosturaRapida
            )
        {
            aux = 5;
        }
        //Obj Especiales
        else if
            (
                iten.iten == Item.ItenType.ataqueEfec
             || iten.iten == Item.ItenType.defensaEfec
             || iten.iten == Item.ItenType.velocidadEfec
             || iten.iten == Item.ItenType.AntiEstado
             || iten.iten == Item.ItenType.MoreExperience
             || iten.iten == Item.ItenType.antiFinalHit
            )
        {
            aux = 6;
        }
 
        if (aux >=0 && aux <=6)
        {
            bool NoExisteItem = false;
            if (listTables[aux].Item.Count != 0)
            {
                for (int i = 0; i < listTables[aux].Item.Count; i++)
                {
// icrementador si el objeto  esta en lista
                    if (listTables[aux].Item.iten == iten.iten)
                    {
                        print("aqui llegue");
                        listTables[aux].Item.cantidad += iten.cantidad;
                        listTables[aux].Item.textobj.text = iten.iten.ToString()+ "  " + listTables[aux].Item.cantidad;
                        break;
                    }
                    if (i == listTables[aux].Item.Count - 1)
                    {
                        NoExisteItem = true;
                    }
                }
            }
            else if (
               listTables[aux].Item.Count == 0
                )
            {
                NoExisteItem = true;
            }
//creo un objeto en nuevo si item no esta en la lista
            if (NoExisteItem == true)
            {
                cloneText(iten, aux);
                print("test");
                listTables[aux].Item.Add(iten);
            }
        }
       
    }
                               

 
luego cuando lo ejecuta este me ordena la tabla en su respectiva tabla de grupo 
 
4
 

 
 
 
Me encantaría saber como tener un método que me permita definir el objeto y en base esa definición me salta la lista especifica para ese tipo de objeto antes de mandarlo a el tipo de tabla que quiero usar. para que a la hora de ordenar  sea simplemente decir que tabla voy a usar como ustedes mismos me recomiendan pero sin tanto if,  @Eskema el método que me pesaste no lo he logrado implementar bien todavía  pero según veo es para un juego en el que quiero quiero tener objetos que se ejecuten al momento de uno tenerlos pero yo lo que quiero es agruparlos en mi caso solo los quiero tenerlos una list<> para cada tipo para luego en el menú usarlos.

Lo que has hecho no está nada mal, si lo has escrito tú enhorabuena porque así se empieza!!
 
Una manera de conseguir lo que quieres (y la manera que yo lo haría) es:
 

//Creas tu clase base, de momento con dos campos que tendrán todos los item.
public class Item
{
public string nombre; //Es mejor usar protected pero para no complicarnos...
public TipoObjeto tipo; //Aquí defines si es consumible, etc... (pero te lo puedes ahorrar)
public int cantidad;
}
//Creas cada objeto y heredas de Item.
[Serializable]
public class Manzana : Item
{
... de momento no hay interface (funciones) por aquí...
}
//La clase mochila (inventario) aparte de la interfaz (el menú que tienes ahí)
public class Mochila : MonoBehaviour
{
List<Item> objetos;
 
     void Start ()
{
   objetos = new List<Item>();
}
 
public void AgregarObjeto (Item _nuevo)   //cuando consigues un objeto nuevo llamas esta función.
{
   Item obj = objetos.Find(x.GetType == typeOf(_nuevo));
   if(obj!=null)
      obj.cantidad += _nuevo.cantidad;
   else
      objetos.Add(_nuevo);
}
public List<Item> ObtenerObjetos (TipoObjeto _tipo) //cuando la interfaz necesite una lista de objetos llama esta función.
{
   return objetos.FindAll(x.tipo == _tipo);
}
}

 
Tienes que tener muy claro si los Item van a servir para algo o si solo son "datos", porque en ese caso puedes usar ScriptableObject y facilizarte la vida.

Cita de: juanma_teso date=1532395630Lo que has hecho no está nada mal, si lo has escrito tú enhorabuena porque así se empieza!!
   
   
      Una manera de conseguir lo que quieres (y la manera que yo lo haría) es:
   
   

//Creas tu clase base, de momento con dos campos que tendrán todos los item.
public class Item
{
public string nombre; //Es mejor usar protected pero para no complicarnos...
public TipoObjeto tipo; //Aquí defines si es consumible, etc... (pero te lo puedes ahorrar)
public int cantidad;
}
//Creas cada objeto y heredas de Item.
[Serializable]
public class Manzana : Item
{
... de momento no hay interface (funciones) por aquí...
}
//La clase mochila (inventario) aparte de la interfaz (el menú que tienes ahí)
public class Mochila : MonoBehaviour
{
List<Item> objetos;
 
     void Start ()
{
   objetos = new List<Item>();
}
 
public void AgregarObjeto (Item _nuevo)   //cuando consigues un objeto nuevo llamas esta función.
{
   Item obj = objetos.Find(x.GetType == typeOf(_nuevo));
   if(obj!=null)
      obj.cantidad += _nuevo.cantidad;
   else
      objetos.Add(_nuevo);
}
public List<Item> ObtenerObjetos (TipoObjeto _tipo) //cuando la interfaz necesite una lista de objetos llama esta función.
{
   return objetos.FindAll(x.tipo == _tipo);
}
}

   
      Tienes que tener muy claro si los Item van a servir para algo o si solo son "datos", porque en ese caso puedes usar ScriptableObject y facilizarte la vida.
   


Esta genial  este método gracias me resulta muy útil.
 
bueno si los itens van tener una función en especifico para mi desgracia pero ya revise lo de los ScriptableObject y me llevo una  super buena impresion voy utilizar ese metodo para almacenar  data me parece mejor que playerprefac.
 
 
 
 

Etiquetas: