Jump to content
GSG3D

Lista generica de tipo Type [Pregunta]

Recommended Posts

Estoy queriendo realizar una clase generica la cual la utilizare para llamar a un metodo especifico llamado "Execute" lo cual tendra diferentes funcionalidades dependiendo la
clase a la que se este refiriendo.
La pregunta es si es el mejor metodo, lo cual cada objeto tendra la clase "Action" y sus derivadas estaran dentro de una clase llamada "GlobalActions" como para dar un nombre.
La funcionalidad de este es que tengo una clase controladora encargada de la interfaz, lo cual muestra informacion segun el objecto seleccionado; mas especificamente en un juego RTS.
Luego está analiza la clase "Action" y muestra los botones correspondientes segun el tipo (sprite, etc), lo cual agrega un Listener a un boton especifico con sus respectiva funcion (Execute).

 

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

namespace ControllerRTS
{
    public class Action : MonoBehaviour 
    {
        void Start() //test
        {
            AddAction(typeof(ActionTest1));
            AddAction(typeof(ActionTest2));

            Execute(); //test button1
            Execute(1); //test button2
        }

        private List<Type> actions = new List<Type>();
        public void AddAction(Type action)
        {
            actions.Add(action);
        }
        public void Execute(int index)
        {
            Type type = actions[index];
            MethodInfo method = type.GetMethod("Execute");
            object instace = Activator.CreateInstance(type, null);
            method.Invoke(instace, null);
        }
    }
    //funciones externas class "GlobalActions"
    public class ActionTest1
    {
        public void Execute()
        {
            Debug.Log("ActionTest1");
        }
    }
    public class ActionTest2
    {
        public void Execute()
        {
            Debug.Log("ActionTest2");
        }
    }
    //etc..
}

 

Share this post


Link to post
Share on other sites

creo, si no me equivoco que lo que tu buscas es herencia y encapsulacion. (no se si entendi tu "pregunta")

te dejo documentacion:

lo que yo haria seria esto:

//Crear una clase padre
public abstract class globalActions
{
	public void ExecuteAction(){}
}
//Luego las clases secundarias
public class Action1 : globalActions
{
}
public class Action2 : globalActions
{
}

//luego tu Lista no deberia ser de tipo Type
  Public List<globalActions> listActions = new List<globalActions>();
//Despues para llamarla solo seria
listActions[x].ExecuteAction();

  

Creo que la teoria seria esta. Un saludo.

Share this post


Link to post
Share on other sites

@kingtrase, al principio trate de utilizar herencia, pero me detuvo lo mismo que estas queriendo decir tu; porque no se puede hacer una llamada de la clases hijos desde el padre, porque aunque usando funciones virtuales/override es lo mismo ( a no ser que exista algo como base.Method() pero para hijos, que desconozca), ya que el metodo ExecuteAction es de los hijos y son diferentes.
Ademas de no poder agregar un "accion" especifica a la lista. En lo que hice yo funciona, pero no se si se vera la perspectiva y funcionalidad de mi parte.
 

Edited by GSG3D

Share this post


Link to post
Share on other sites

@GSG3D puedo preguntarte justo para que quieres lo que dices, ya veo que algo para las acciones, pero tu tipo de juego es un RTS. y a mi entender en estos juegos cada 'Personaje' es el que lleva su propia lista de acciones. ¿Sabes a lo que me refiero?

Share this post


Link to post
Share on other sites

@kingtrase es por sobre todo, tema de organización, utilizando una clase "dinamica de acciones" (para cada objeto), ya que quiero desligar esa carga a las clases controladoras principales, en este caso "InterfaceController", y asi administrar todo dependiendo de cada unidad dependientemente; en si para no crear una clase para cada objeto, y a su vez crear metodos para que sean reutilizados.
En si es cosa mia tratando de crear materia xD

Edited by GSG3D

Share this post


Link to post
Share on other sites

@GSG3D No sé si te he entendido, ¿te serviría algo así?:

// Interface que obliga a implementar el método Execute
public interface IAction
{	
	void Execute();
}

// Clases que utilizan la interface 
public class ActionTipo1: IAction
{
	void Execute()
	{
		// Hacer cosas tipo 1
	}
}

public class ActionTipo2: IAction
{
	void Execute()
	{
		// Hacer cosas tipo 2
	}
}

// La classe actions manager o como se diga
public class ActionManager
{
	List<IAction> Acciones = new List<IAction>();
      
    public void AddAction(IAction accion)
    {      	
    	Acciones.add(accion);  
    }
    
    public void ExecuteAction(indetificador de la acción)
    {
    	Acciones.First(buscar con el identificador).Execute();
   	}
}

Mehhh revisando el post veo que lo que he puesto es prácticamente lo mismo que te ha puesto @kingtrase, de hecho su solución me parece mejor porque en la clase base puedes declarar un identificador de acción y un constructor que obligue a pasar ese id he inicialice esa variable identificador. Luego con esto al insertar acciones puedes mirar si previamente ya existían en la lista y al ejecutar también puedes comprobar si la acción que te piden ejecutar está en la lista o no.

Bueno no sé si van por aquí los tiros o qué

 

 

 

Share this post


Link to post
Share on other sites

@musaranya Ya estubimos debatiendo sobre la "solucion" jajajaja es mas bien que nuestro amigo @GSG3D esta probando como hacer cosas, y yo le estube dando vueltas a la cabeza y aun asi vi la luz. :) pero seguro que GSG3D lo soluciona, y espero que postee la solucion!

Share this post


Link to post
Share on other sites

La primer solución de @GSG3D no me parece la mejor, en principio cada vez que se llame Ejecutar tiene que estar accediendo a métodos de Reflexión algo que consume mucho tiempo, y en un RTS no puedes permitirlo.

Por lo general para este tipo de juegos se utilizar varias técnicas, pero la más eficaz es la lista de comandos, un ejemplo práctico AOE 3, si te detienes a analizar los XML de configuración de unidades de AOE te vas a encontrar con un sin fin de ID de acciones, cada ID hace referencia a uno o varios comandos que al final los llaman acciones. Es muy parecido a una base de datos, donde tienes tu tabla Action y Commands, digamos que en action puedes agregar múltiples comandos para un solo ID, relacion de Uno a Muchos. 

Una vez que tienes estos Comandos, es hora de programar de qué manera se van a ejecutar en cada Actor. Para esto, te recomiendo utilices simplemente una referencia a una clase llamada Action, es decir.

public class Actor 
{
	public class Action action;

	public void EjectueAction(int CommandID)
	{
		action.Ejecute(CommandID);
	}
}

y luego tus clases de acción.

public class Action
{
	public virtual void Ejecute(int CommandID)
  	{
	}
}

public class Action_test : Action
{
	public override void Ejecute(int CommandID)
	{
	}
}

public class Action_test2 : Action
{
	public override void Ejecute(int CommandID)
	{
	}
}

De esta manera es la más eficiente, siempre y cuando cada ID de acción ejecute eventos diferentes para cada Actor.

Hay que tener bien separado los Eventos de las Acciones, esto lleva tiempo y muchas veces hasta una reconstrucción por completo de la base del juego, si tienes pensado luego añadir un multi jugador entonces de la manera que te estoy recomendando luego vas a evitarte muchos dolores de cabeza.

Hace ya varios meses vengo programando un juego de cartas, que si bien no es un RTS tiene planteamientos similares, y este creo, fue uno de los que más tiempo me llevó, en cuanto a investigación, práctica y correcto funcionamiento. 

 

Un abrazo suerte.

Share this post


Link to post
Share on other sites

Lo de utilizar id es algo bueno para añadir, la cuestion por sobre todo es la implementacion del Update() por eso me opte por el sistema que utilice (que funciona con el agregado de un par de lineas mas), pero como dicen ustedes y a mi tmb me parecio que es muy tedioso.
Al fin y al cabo, lo mejor seria utilizar cada Accion como si fuera un componente e ir añadiendo/quitando segun conveniencia y añadir botones segun la lista de id's que tenga el objeto.
Pero la cuestion era esa, de tener algo mas organizado que eso, o mas bien implentar  Delegates y Events en la clase Action.
Mas sugerencias?

 

 

Share this post


Link to post
Share on other sites

Al final opte por utilizar el siguiente metodo.
Una simple clase "Action" donde se setean los id's de las acciones y su funcion Execute.
public class Action : MonoBehaviour 
{
    public List<int> actionsID;
    public void Execute(int ID) { CmdAction.Execute(ID, transform); }
}

Y donde CmdAction (por el momento es una clase estatica) se encarga de realizar las repectivos metodos segun el id, aplicados al objeto "transform".
Asi libero la carga a la clase "Action"; ademas con esta lista de id's la utilizo para rellenar los botones de la interfaz y su su respectivo Listener (Execute(int))

Share this post


Link to post
Share on other sites

@GSG3D lo que si podrias usar (que no se si lo haces ya, te lo pongo como apunte :P ) para dar las acciones, en CmdAction (ID, worldObject); donde worldObject es el personaje, o tambien la construccion. me refiero a herencia:

public class worldObject {etc etc}

public class character : worldObject {etc etc}

public class build : worldObject {etc etc}

y asi tratas directamente con los objetos de tu juego y no con el transform de cualquier cosa.

Espero haberme explicado jajajaja un saludo!

Share this post


Link to post
Share on other sites

@kingtrase si, lo implemente al principio pero con el tiempo va cambiando mucho el sentido de como lo pensas en tu cabeza, y mas de ser mi primera vez que programo un RTS.
En la clase Action solo uso el parametro "transform" para agregar determinado componente, nada mas.

Share this post


Link to post
Share on other sites

Hola, no podes usar un Scriptable object para las caracteristicas o tipo de acciones de cada objeto. No se si lo entendi bien pero vos estas haciendo un rts, osea que seleccionas un objeto cualquiera, ponele un aldeano (a lo AOE), y el controlador sabe las acciones que puede realizar, etc. no? Y no queres que cada aldeano tenga una clase con sus propias acciones y caracteristicas, etc. Es asi?

 

 

Share this post


Link to post
Share on other sites
hace 2 horas, lightbug said:

Hola, no podes usar un Scriptable object para las caracteristicas o tipo de acciones de cada objeto. No se si lo entendi bien pero vos estas haciendo un rts, osea que seleccionas un objeto cualquiera, ponele un aldeano (a lo AOE), y el controlador sabe las acciones que puede realizar, etc. no? Y no queres que cada aldeano tenga una clase con sus propias acciones y caracteristicas, etc. Es asi?

 

 

El controlador lee los id de acciones que tiene el player (solo para setear la interfaz y los botones), el tema de las acciones en si estoy viendo de implementar añadiendo los componentes necesarios o ya tener cada objecto seteado como tu lo dices, el tema es que yo busco algo generico, para no tener que tener que realizarlo para cada unidad, lo voy a ir viendo y te comento. Aunque no descarto nada ya que es a prueba y error.

Share this post


Link to post
Share on other sites

Comentario personal: Intentar crearte un framework de desarrollo propio dentro de Unity es bueno y es una manera de aprender y experimentar. Sin embargo cuidado al final:

- El añadir demasiada complejidad al utilizar este framework personal (o API) y acabar no usándolo

- Cada proyecto tiende a ser diferente y las soluciones genéricas no se adaptan bien u óptimamente

- Tendencia a desarrollar proyectos genéricos con resultados muy parecido entre sí (UI similar, mismos efectos, etc.)

- Al ir adquiriendo experiencia surge que cierto código hecho anteriormente lo hubieras de otra manera, además se añaden innovaciones de Unity + plugins que nos lo harán cambiar

Saludos!

Share this post


Link to post
Share on other sites

UnitySpain © Todos los derechos reservados 2020
×
×
  • Create New...